ZAPI-685 and
ZAPI-782 were two changes made to the
same DeleteVm VMAPI endpoint, and they both broke VMAPI clients in some way.
ZAPI-685 was originally made to avoid starting workflow jobs, and thus
potentially flooding the jobs queue, when handling DeleteVm requests, unless
necessary.
It broke SAPI, which was fixed with ZAPI-782 by changing the behavior of VMAPI
to respond with an error in cases when previously VMAPI would send a response
that wasn't consistent with the format of other successful responses. It also
caused ZAPI-755, preventing VMs that were actually stuck in 'provisioning'
state from being deleted.
Unfortunately, ZAPI-782 broke one of sdc-vm-agent's tests, which was relying on that behavior from ZAPI-685.
At that point it seems clear that:
-
Although obvious in hindsight, changing the behavior of the
DeleteVmendpoint, even for what seems like edge cases, can have a significant impact on the rest of the Triton ecosystem -
The behavior of the
DeleteVmendpoint is perfectible, and even if some of the consequences of ZAPI-685 and ZAPI-782 were unfortunate, it seems that it can be improved
This section recommends making two changes to the current behavior of VMAPI's
DeleteVm endpoint.
-
DeleteVmon a VM with noserver_uuidcan happen on a VM actually being provisioned (itsserver_uuidwill be set at the end of the provisioning workflow if that VM is actually provisioned on a CN). To avoid races where a VM would end up being marked as destroyed when it's actually provisioned, these requests need to be serialized by acquiring a ticket. For that, they need to go through a workflow job and their response needs to have a 202 HTTP status code and its data needs to be a "VM job object". -
DeleteVmon a VM with aserver_uuidthat references a CN that cannot be found via CNAPI'sGetServerendpoint could avoid going through a workflow job. That VM would not be being provisioned, so the race previously described would not be a concern. However, in order to prevent other races, such as overwriting a value previously set by e.g a CN being back up again and its vm-agent PUTing the VM with state !== 'destroyed', it would be helpful if it used an etag. In case the deletion would be successful, the response could be a 200 HTTP status code with the response's data being the VM object with the status set todestroyed. I'm not sure it makes sense in this case to set thezone_statestatus, since there is likely no underlying zone if the VM has noserver_uuidassociated.
These recommendations are not in line with the guidelines in RFC 2616 about
DELETE
requests.
However, I don't think it necessarily makes sense to follow these to the letter
since that section of the RFC assumes that DELETEd objects are made inaccessible
or removed from the system, which is not the case for VMAPI. In other words, it
seems VMAPI's API deviates enough from a pure REST API that it might not be
worthwhile to strictly require sticking to what that RFC mandates for the
DeleteVm endpoint.
As we've seen with changes made with ZAPI-685 and ZAPI-782, changes to the
DeleteVM endpoint' response can be disruptive for the Triton ecosystem.
Ideally, VMAPI would introduce a versioning mechanism before integrating these
changes.
One of the challenges here is that, since VMAPI currently doesn't have any support for API versioning, all current VMAPI clients always use the latest version. Thus, if we were to introduce API versioning to VMAPI, the default API version would need to be a version that represents the current state of VMAPI at the time versioning mechanisms are introduced. That version could be version 1.0.
sdc-imgapi implemented something similar by considering all clients that do not
specify an Accept-Version header implicitly use version
1.0 and
then conditionally changing some endpoints' response's format when an accepted
version different from the default version is provided.
After these versioning mechanisms are introduced in VMAPI, the changes mentioned in the previous section "Recommended changes" could be made, and released as version "2.0".
The way to deal with it seems to be: passing the etag from the loaded VM to the putObject request, and error if putObject results in an error. That seems straightforward enough, but I won't push for it.
OK, it seems currently that there's no mechanism for guarding against deleting a
'failed'VM, but I could have missed something. Not that it would be a justification to continue doing that. I'd be interesting in @joshwilsdon's feedback.The problem with using that status code is that the VM object is still available, e.g via
GetVm.Sounds good.