-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update virtual provisioning counters on instance stop/start #4277
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,11 @@ declare_saga_actions! { | |
+ sis_alloc_propolis_ip | ||
} | ||
|
||
ADD_VIRTUAL_RESOURCES -> "virtual_resources" { | ||
+ sis_account_virtual_resources | ||
- sis_account_virtual_resources_undo | ||
} | ||
|
||
CREATE_VMM_RECORD -> "vmm_record" { | ||
+ sis_create_vmm_record | ||
- sis_destroy_vmm_record | ||
|
@@ -96,6 +101,7 @@ impl NexusSaga for SagaInstanceStart { | |
|
||
builder.append(alloc_server_action()); | ||
builder.append(alloc_propolis_ip_action()); | ||
builder.append(add_virtual_resources_action()); | ||
builder.append(create_vmm_record_action()); | ||
builder.append(mark_as_starting_action()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ordering is wrong. The saga should only add virtual resources once it's successfully marked the instance as starting, i.e., it should get through the "only one start can proceed at a time" interlock before charging for anything. Will fix in the next push. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 16b7fe6. |
||
builder.append(dpd_ensure_action()); | ||
|
@@ -149,6 +155,56 @@ async fn sis_alloc_propolis_ip( | |
allocate_sled_ipv6(&opctx, sagactx.user_data().datastore(), sled_uuid).await | ||
} | ||
|
||
async fn sis_account_virtual_resources( | ||
sagactx: NexusActionContext, | ||
) -> Result<(), ActionError> { | ||
let osagactx = sagactx.user_data(); | ||
let params = sagactx.saga_params::<Params>()?; | ||
let instance_id = params.db_instance.id(); | ||
|
||
let opctx = crate::context::op_context_for_saga_action( | ||
&sagactx, | ||
¶ms.serialized_authn, | ||
); | ||
osagactx | ||
.datastore() | ||
.virtual_provisioning_collection_insert_instance( | ||
&opctx, | ||
instance_id, | ||
params.db_instance.project_id, | ||
i64::from(params.db_instance.ncpus.0 .0), | ||
nexus_db_model::ByteCount(*params.db_instance.memory), | ||
) | ||
.await | ||
.map_err(ActionError::action_failed)?; | ||
Ok(()) | ||
} | ||
|
||
async fn sis_account_virtual_resources_undo( | ||
sagactx: NexusActionContext, | ||
) -> Result<(), anyhow::Error> { | ||
let osagactx = sagactx.user_data(); | ||
let params = sagactx.saga_params::<Params>()?; | ||
let instance_id = params.db_instance.id(); | ||
|
||
let opctx = crate::context::op_context_for_saga_action( | ||
&sagactx, | ||
¶ms.serialized_authn, | ||
); | ||
osagactx | ||
.datastore() | ||
.virtual_provisioning_collection_delete_instance( | ||
&opctx, | ||
instance_id, | ||
params.db_instance.project_id, | ||
i64::from(params.db_instance.ncpus.0 .0), | ||
nexus_db_model::ByteCount(*params.db_instance.memory), | ||
) | ||
.await | ||
.map_err(ActionError::action_failed)?; | ||
Ok(()) | ||
} | ||
|
||
async fn sis_create_vmm_record( | ||
sagactx: NexusActionContext, | ||
) -> Result<db::model::Vmm, ActionError> { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is made based off of
new_runtime_state
(from the sled agent) as well asdb_instance.runtime()
(from the DB), but both are cached -- couldn't both be out-of-date?For example:
ensure_updated_instance_network_config
yields for a really long time.virtual_provisioning_collection_delete_instance
function. Now the accounting is wrong! This is a running instance, but we would have deleted the resources it's currently using.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is related to what I was touching on here: #4194 (comment)
If we're associating these resources with VMMs (AKA, "what is actually running") rather than Instances (the opaque thing that exists even without a propolis), should we alter the calls to
virtual_provisioning_collection_{create, delete}_instance
to act on VMM UUIDs instead, rather than instance UUIDs?That way, it wouldn't be possible to do a "double delete" -- once a VMM is gone, the UUID for it should never be re-used/re-added, so repeated/delayed requests to delete should have no further effect after the first successful call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Let me think about this one a little more--the race you've identified is definitely a problem. I'll mull it over to see if there's a good way to resolve it without dipping into transaction-land (such that we could say "only proceed with the deletion if the instance generation number is less than the one I think I'm trying to apply" or suchlike).
It's true that VMMs don't share that problem because they can't come back from a terminal state, but I want to be careful about charging counters on a per-VMM basis if those counters are going to be used for quota management purposes (which AIUI is part of the discussion in RFD 427). For example, suppose I have a quota of 32 vCPUs on my project; I start an instance with 16 vCPUs; the rack operator starts an upgrade that migrates my instance; then I try to start a second instance with 16 vCPUs; if we track per-VMM, this will fail because my quota's exhausted--but what do you mean it's exhausted? I only have the one running instance! (cc @askfongjojo to help weigh in on this part; if we're OK with charging on a per-VMM basis even though this can cause transient double-counting, then switching to VMM IDs is a much simpler option here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 16b7fe6 (or so I think...) by putting a sub-select into the instance provisioning counter deletion query that makes it apply only if the caller has furnished a sufficiently new generation number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Transient double-counting is probably fine if it's indeed transient (i.e. seconds, not minutes). But if we foresee failure modes that can cause in-progress migration to double count for an extended period of time, it'll be better for the system rather than the user to "absorb" the migration-in-transit usage.