In our most recent article we covered Using Request ID Headers with Nutanix v4 APIs. This article is the second part in a mini series covering how the Nutanix v4 APIs implement better, standards-based approaches, particularly with regards to how users consume those APIs. Request IDs are generally accepted as standard practice when sending API requests; ETag and If-Match headers fall under the same category of standard practices.
How did this work in API v3?
When updating a resource using the Nutanix Prism Central v3 APIs, responses could fail with an error indicating a version mismatch. This situation could arise from a resource being read by the API consumer and, before the resource could be updated, that resource would change. The result is a mismatched specification that would prevent an API consumer from successfully completing a resource update request.
The Nutanix Prism Central v3 APIs did not implement ETag-based version matching and could not use them as a way of guaranteeing spec mismatches would never occur. That all changes in Nutanix Prism Central API v4.
Nutanix Prism Central API v4: ETag Implementation
The Mozilla developer network docs describe ETag as follows:
The
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETagETag
(or entity tag) HTTP response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content was not changed. Additionally, etags help to prevent simultaneous updates of a resource from overwriting each other (“mid-air collisions”).
With a greater focus on standards-based implementations like ETag, previous issues with potential spec mismatches and mid-air collisions can be completely avoided.
Prepare Test Image
Note: This section can be skipped if you would like to update an existing image in your environment. In an upcoming step we will use the v4 APIs to obtain an image ext_id
.
In today’s example, we’ll look at creating then updating a Prism Central image. Prism Central images are often used as base disks for virtual machines and can contain pre-configured operating sytem configurations, software packages (etc).
To create an image that can be used for testing, use Postman or your preferred API prototyping/test software to submit a request with the following settings.
Note: In all examples throughout this article, {{pc_ip}}
refers to the IP address or FQDN of your Prism Central instance.
- URL:
https://{{pc_ip}}:9440/api/vmm/v4.0.a1/images
- Method:
POST
- Headers
Content-Type: application/json
Ntnx-Request-Id: <UUID generated at https://www.uuidgenerator.net>
- JSON payload: As shown below
{{centos7_url}}
can be replaced with disk images such as https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2003.qcow2{{cluster_uuid}}
must be the clusterext_id
or UUID of your specific Prism Element cluster. This will be different for each environment.
Note: During testing, this request can be sent without the initialClusterLocations
object.
{
"name": "centos7minimal",
"type": "DISK_IMAGE",
"description": "CentOS 7 x86_64 Minimal from v4 APIs",
"source": {
"url": "{{centos7_url}}",
"allowInsecure": false,
"$objectType": "vmm.v4.images.UrlSource"
},
"initialClusterLocations": [
{
"extId": "{{cluster_uuid}}"
}
]
}
Get Existing Image extId (with OData filters)
To update an image, we first need to obtain an existing image’s extId
. This is a unique identifier for the image and will be used to ensure we are updating the correct image. The following settings can be used to list images visible to an existing Nutanix Prism Central instance; note that this request uses v4 API OData filters to find a specific image with a name starting with "centos7"
. Adjust this filter parameter if you are searching for a different image.
- URL:
https://{{pc_ip}}:9440/api/vmm/v4.0.a1/images?$filter=startswith(name, 'centos7')
- Method:
GET
- Headers
Content-Type: application/json
In this demo’s test environment, this will return details of a single image named "centos7minimal"
, matching the name of the image created in the previous step. The screenshot below shows the image’s extId
as fa90243c-c2bc-45b3-879b-c75f85559e75
.
Get Existing Image Details
Now that we know the relevant image’s extId
, we can get that image’s details, again using the v4 APIs. This is a simple request, as follows:
- URL:
https://{{pc_ip}}:9440/api/vmm/v4.0.a1/images/fa90243c-c2bc-45b3-879b-c75f85559e75
- Method:
GET
The response from this request includes a number of critical pieces of information. For this demo, we are specifically interested in the following:
- The image’s current specification:
data
object. Within this object, we can see the image’s name is"centos7minimal"
. - The image resource’s “version”, identified in the response headers as
"Etag"
. Below, we can see the ETag isYXBwbGljYXRpb24vanNvbg==:01
.
Resource Update Without ETag
Before continuing with a real image update, we’ll take a quick look at what happens when an image update is requested, but without using the Etag header value to specify the resource version.
- URL:
https://{{pc_ip}}:9440/api/vmm/v4.0.a1/images/fa90243c-c2bc-45b3-879b-c75f85559e75
- Method:
PUT
- Headers
Content-Type: application/json
Ntnx-Request-Id: <UUID generated from https://www.uuidgenerator.net>
- JSON payload: As obtained from previous GET request’s
data
object.
When this request is submitted, the immediate response is HTTP 428 PRECONDITION REQUIRED
. This tells us we have not included the resource’s Etag as the value of the If-Match
header. This is required to verify the resource’s version.
Resource Update With ETag and If-Match Header
To fix the error in the previous request, it is mandatory to include the Etag value as the If-Match
header. In addition, there are two important notes to consider here:
- Remember to provide a new
Ntnx-Request-Id
header value each time requests like this are sent - The resource’s
Etag
value will change after every update. If you make a change to any resource, you must get the resource’s new ETag via a new API GET request.
With these changes in mind, our request can be constructed as follows:
- URL:
https://{{pc_ip}}:9440/api/vmm/v4.0.a1/images/fa90243c-c2bc-45b3-879b-c75f85559e75
- Method:
PUT
- Headers
Content-Type: application/json
Ntnx-Request-Id: <UUID generated from https://www.uuidgenerator.net>
If-Match: <Etag value>
Now, when this request is sent, the response is HTTP 202 ACCEPTED, indicating all prerequisites have been met and the request has been accepted successfully.
Resource Update With Incorrect ETag
It is possible that a resource update request could be submitted without first obtaining the resource’s current ETag. This would be the case if a previous update request was submitted and accepted, without requesting the resource’s updated ETag. As mentioned previously, resource ETags will change after every update.
Despite the request being properly constructed and containing all the required data, an incorrect ETag will return a response similar to the example below.
Wrapping Up
The changes detailed here are conceptually quite simple and bring this part of the Nutanix v4 APIs in-line with accepted API best practices. Combining Ntnx-Request-Id
and ETag
will help ensure your requests are sent and accepted successfully.
For the first part in this series, remember to check out Using Request ID Headers with Nutanix v4 APIs.
Thanks for reading and have a great day! 🙂
Appendix A: Complete Image Update Payload
For the purposes of this demo, the image’s name has been updated from “centos7minimal” to “centos7minimal_updated”
{
"sizeBytes": 8589934592,
"$sourceItemDiscriminator": "vmm.v4.images.UrlSource",
"source": {
"url": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2003.qcow2",
"allowInsecure": false,
"$reserved": {
"$fqObjectType": "vmm.v4.r0.a1.images.UrlSource"
},
"$objectType": "vmm.v4.images.UrlSource"
},
"$reserved": {
"$fqObjectType": "vmm.v4.r0.a1.images.Image"
},
"$objectType": "vmm.v4.images.Image",
"extId": "fa90243c-c2bc-45b3-879b-c75f85559e75",
"name": "centos7minimal_updated",
"description": "CentOS 7 x86_64 Minimal from v4 APIs",
"type": "DISK_IMAGE"
}