Introduction to VMs API
January 26, 2021 ยท View on GitHub
What is VMAPI?
VMAPI is an HTTP API server for managing VMs on an SDC installation.
Features
- Search for VMs by specific criteria such as ram, owner, tags, etc.
- Get information about a single VM
- Create VMs
- Perform actions on an existing VM such as start, stop, reboot, update, modify NICs, destroy, etc.
VM Object
The following is the list of attributes that can be associated with a VM. By default the API returns a fixed list of fields, so there are additional fields that will also be returned if they are set, otherwise they are considered to have null values. Some of these fields can be set by both a CreateVm or UpdateVm call, while some of them can only be set at VM creation time. In the next table, the column "VM Response Default" refers to attributes that are always going to be part of the VM response object. Those with a column value of 'No' are only going to be returned when set via CreateVm or UpdateVm. Finally, the last two columns specify whether or not some VM attributes can be set at creation or update time.
| Param | Type | Description | Vm Response Default | Create | Update |
|---|---|---|---|---|---|
| alias | String | VM alias (max length 189 chars, and must match /^[a-zA-Z0-9][a-zA-Z0-9\_\.\-]*$/) | Yes | Yes | Yes |
| autoboot | Boolean | Controls whether or not a VM is booted when the system is rebooted. | Yes | Yes | Yes |
| billing_id | UUID | UUID of the PAPI package associated with this VM | Yes | Yes | Yes |
| brand | String | Brand of the VM (joyent, joyent-minimal, lx, bhyve or kvm) | Yes | Yes | No |
| cpu_cap | Number | CPU Cap | No | Yes | Yes |
| cpu_shares | Number | CPU Shares | Yes | Yes | Yes |
| create_timestamp | Date | The time at which the VM was created in ISO 8601 format | Yes | No | No |
| customer_metadata | Object | VM metadata | Yes | Yes | Yes |
| destroyed | Date | The time at which the VM was destroyed in ISO 8601 format | Yes | No | No |
| datasets | Array | VM datasets | Yes | No | No |
| delegate_dataset | Boolean | Delegate a data dataset to the VM | No | Yes | No |
| disks | Array | Array of virtual disks (zvols) that are used by a bhyve VM. | No | No | No |
| disks.*.path | String | File path in GZ. | No | No | No |
| disks.*.size | Number (MiB) | Size of disk. | No | No | No |
| disks.*.pci_slot | String | Specifies the virtual PCI slot a disk occupies. | No | No | No |
| disks.*.boot | Boolean | If this is a VM's boot disk. | No | No | No |
| flexible_disk_size | Number (MiB) | Maximum amount of space that can be used by the sum of all disks. | No | Yes | No |
| dns_domain | String | Search domain value for /etc/resolv.conf (max length 255 chars) | No | Yes | No |
| do_not_inventory | Boolean | The primary use-case of this attribute is for test VMs that are created but you don't want their existence propagated up to VMAPI since they'll be short-lived and its lifecycle will be physically managed in the server | No | Yes | Yes |
| firewall_enabled | Boolean | Enable firewall for the VM | Yes | Yes | Yes |
| flexible_disk_size | Number (MiB) | The amount of space a bhyve instance may use for its disks and snapshots of those disks | No | Yes | Yes |
| free_space | Number (MiB) | Space that is not allocated to bhyve instance disks nor in use by snapshots of those disks) | No | Yes | Yes |
| fs_allowed | String (comma-separated list) | Filesystems allowed for the VM | No | Yes | Yes |
| hostname | String | Hostname (excluding DNS suffix) for the VM (max length 63 chars, must be DNS-safe) | No | Yes | No |
| image_uuid | UUID | Image of the VM | Yes | Yes | No |
| indestructible_delegated | Boolean | When set this property adds an @indestructible snapshot to the delegated data dataset and sets a zfs hold on that snapshot. This hold must be removed before the VM can be deleted enabling a two-step deletion | No | Yes | Yes |
| indestructible_zoneroot | Boolean | When set this property adds an @indestructible snapshot to the zoneroot dataset and sets a zfs hold on that snapshot. This hold must be removed before the VM can be deleted or reprovisioned | No | Yes | Yes |
| internal_metadata | Object | Internal VM metadata | Yes | Yes | Yes |
| limit_priv | String (comma-separated list) | Privileges available to the VM | Yes | Yes | Yes |
| last_modified | Date | The time at which the VM was last modified in ISO 8601 format | Yes | No | No |
| maintain_resolvers | Boolean | This boolean indicates that /etc/resolv.conf must be updated when the VM resolvers are updated | No | Yes | Yes |
| max_locked_memory | Number (MiB) | Amounf of memory that can be locked for the VM | Yes | Yes | Yes |
| max_lwps | Number | Max. Lightweight Processes | Yes | Yes | Yes |
| max_physical_memory | Number (MiB) | Amount of memory of the VM. For KVM VMs this value should be ram + 1024 | Yes | Yes | Yes |
| max_swap | Number (MiB) | Maximum amount of virtual memory. Defaults to 2 x max_phsical_memory and cannot be lower than 256 | Yes | Yes | Yes |
| mdata_exec_timeout | Number | Timeout in seconds on the start method of the svc:/smartdc/mdata:execute service running in the VM | No | Yes | No |
| networks | Array | At provision time, specify the networks on which the VM NICs should be provisioned | No | Yes | No |
| networks.*.uuid | String | Network UUID. Optional, required if networks.*.name is not present | -- | -- | -- |
| networks.*.name | String | Network name. Optional, required if networks.*.uuid is not present | -- | -- | -- |
| networks.*.primary | String | Specifies that this will be the primary NIC of the VM. Optional | -- | -- | -- |
| networks.*.ip | IP Address | Specifies the IP address desired on this network. Optional | -- | -- | -- |
| nics | Array | VM NICs. They can only be updated. NICs get provisioned for a VM from the values of networks in CreateVm. See UpdateNIcs for more details. | Yes | No | No |
| owner_uuid | UUID | VM Owner | Yes | Yes | Yes |
| package_name | String | DEPRECATED: use billing_id | No | Yes | Yes |
| package_version | String | DEPRECATED: use billing_id | No | Yes | Yes |
| platform_buildstamp | String | Timestamp of the SDC platform the VM is running on. This value only changes when the platform of the Compute Node where the VM is running is upgraded | Yes | No | No |
| quota | Number (GiB) | VM quota | Yes | Yes | Yes |
| ram | Number (MiB) | Amount of memory of the VM | Yes | Yes | Yes |
| resolvers | Array | DNS resolvers for the VM | Yes | Yes | Yes |
| server_uuid | UUID | Server UUID of the VM | Yes | Yes | No |
| snapshots | Array | VM snapshots | Yes | No | No |
| state | String | State of the VM | Yes | No | No |
| tags | Object | VM tags | Yes | Yes | Yes |
| tmpfs | Number | Amount of memory for the /tmp filesystem | No | Yes | Yes |
| zfs_data_compression | String | Specifies a compression algorithm used for the VM's data dataset | No | Yes | Yes |
| zfs_io_priority | Number | ZFS IO Priority | Yes | Yes | Yes |
| zfs_snapshot_limit | Number | Sets the number of ZFS snapshots a VM can take. Undefined or null indicates no limits, and setting null disables previously-set limits. NOTE: On compute nodes running versions of SmartOS prior to June, 2020, setting zfs_snapshot_limit to null will cause the VM to not allow snapshots at all. Setting a high number will mitigate this on older versions of SmartOS. | No | Yes | Yes |
| zlog_max_size | Number | Sets the maximum size of the stdio.log file for a docker zone before rotation. NOTE: To be used by sdc-docker only. | No | Yes | Yes |
Furthermore, when dealing with KVM VMs there are additional attributes to know about and are specific to KVM being a different type of virtualization: cpu_type, disks, disk_driver, nic_driver and vcpus. KVM VMs require at least two disks and only the properties documented below should be specified. For additional advanced attributes that can be set on disks please refer to the vmadm(1) man page.
| Param | Type | Description | Vm Response Default | Create | Update |
|---|---|---|---|---|---|
| cpu_type | String | Type of virtual CPU exposed to the guest | Yes | Yes | No |
| disk_driver | String | Drivel model for the VM disks | Yes | Yes | No |
| disks | Array | Disks for the KVM VM. | Yes | Yes | No |
| disks[0].image_uuid | UUID | Image UUID for the KVM VM | Yes | Yes | No |
| disks[1].size | Number (MiB) | Size of the disk | Yes | Yes | No |
| nic_driver | String | Drivel model for the VM NICs | Yes | Yes | No |
| vcpus | Number | Number of virtual CPUs | Yes | Yes | No |
The following is a sample VM response object. The only two endpoints that return VM objects are GetVm and ListVms. ListVms returns a collection of VM objects.
{
"uuid": "ef375f03-57ca-44a9-bc8d-63aec09fbc37",
"brand": "joyent",
"dataset_uuid": "01b2c898-945f-11e1-a523-af1afbe22822",
"image_uuid": "01b2c898-945f-11e1-a523-af1afbe22822",
"server_uuid": "564d6836-ed2e-18f8-bdf2-e900490a57a1",
"alias": "assets1",
"ram": 64,
"max_physical_memory": 64,
"max_swap": 256,
"quota": 10240,
"cpu_cap": 100,
"cpu_shares": 1,
"max_lwps": 1000,
"create_timestamp": "2012-05-16T23:33:09.809Z",
"destroyed": "",
"last_modified": "2012-05-16T23:33:12.000Z",
"zone_state": "running",
"state": "running",
"zpool": "zones",
"zfs_io_priority": 10,
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"nics": [
{
"interface": "net0",
"mac": "90:b8:d0:d6:26:6e",
"vlan_id": 0,
"nic_tag": "admin",
"ip": "10.99.99.192",
"netmask": "255.255.255.0",
"gateway": "10.99.99.7",
"primary": true
}
],
"resolvers": [
"10.99.99.11"
],
"customer_metadata": {
"host-ip": "10.99.99.9"
},
"internal_metadata": {
"throttle": true
},
"tags": {
"smartdc_role": "assets",
"smartdc_type": "core"
},
"snapshots": [
{
"name": "zones/ef375f03-57ca-44a9-bc8d-63aec09fbc37@backup"
}
],
}
The following is a sample KVM VM response object (brand == kvm). Note the additional attributes present in the payload:
{
"uuid": "03750e6a-fcf6-4755-85b5-22b8ddf0f1fb",
"brand": "kvm",
"image_uuid": "56108678-1183-11e1-83c3-ff3185a5b47f",
"server_uuid": "564d47c4-b845-113b-664f-2a1d85d0020c",
"billing_id": "00000000-0000-0000-0000-000000000000",
"alias": null,
"ram": 256,
"max_physical_memory": 512,
"max_swap": 512,
"quota": null,
"cpu_cap": null,
"cpu_shares": 2,
"max_lwps": 2000,
"create_timestamp": "2012-12-21T06:55:27.654Z",
"destroyed": null,
"last_modified": "2012-12-21T06:55:32.000Z",
"zone_state": "running",
"state": "running",
"zpool": null,
"zfs_io_priority": 100,
"owner_uuid": "00000000-0000-0000-0000-000000000000",
"nics": [
{
"interface": "net0",
"mac": "90:b8:d0:88:45:a8",
"vlan_id": 0,
"nic_tag": "admin",
"gateway": "10.99.99.7",
"primary": true,
"ip": "10.99.99.32",
"netmask": "255.255.255.0",
"model": "virtio"
}
],
"resolvers": [
"10.99.99.11"
],
"snapshots": [],
"customer_metadata": {},
"internal_metadata": {},
"tags": {},
"vcpus": 1,
"cpu_type": "host",
"disks": [
{
"path": "/dev/zvol/rdsk/zones/03750e6a-fcf6-4755-85b5-22b8ddf0f1fb-disk0",
"boot": false,
"model": "virtio",
"media": "disk",
"image_size": 10240,
"image_uuid": "56108678-1183-11e1-83c3-ff3185a5b47f",
"image_name": "ubuntu10.04",
"zfs_filesystem": "zones/03750e6a-fcf6-4755-85b5-22b8ddf0f1fb-disk0",
"zpool": "zones",
"size": 5120,
"compression": "off",
"block_size": 8192
},
{
"path": "/dev/zvol/rdsk/zones/03750e6a-fcf6-4755-85b5-22b8ddf0f1fb-disk1",
"boot": false,
"model": "virtio",
"media": "disk",
"size": 10240,
"zfs_filesystem": "zones/03750e6a-fcf6-4755-85b5-22b8ddf0f1fb-disk1",
"zpool": "zones",
"compression": "off",
"block_size": 8192
}
]
}
VM States
The VM response object contains a state attribute that should be used as the high level representation of the machine state. There are three 'running state' values for a VM, two 'provisioning state' values and an additional 'active' state that is only available as a search filter when used in the ListVms API endpoint:
| VM State | Description |
|---|---|
| running | Self-explanatory |
| stopped | Self-explanatory |
| destroyed | Self-explanatory |
| provisioning | VM is currently being provisioned in the system |
| incomplete | |
| failed | VM provisioning has failed |
| active | When used in ListVms, denotes machines that are not 'destroyed' or 'failed' |
| unknown | The VM was last seen as 'running', but the server the VM is running on is no longer contactable (e.g. the server is down and we can no longer be sure of what state the VM is in). |
In addition, there is a 'zone_state' property that represents the Solaris Zones state, since every VM is really a zone internally. The state property should be used in favor of zone_state at all times, but zone_state is provided in case it's needed for debugging purposes. The following is a table that shows all the possible zone_state values:
| Zone State |
|---|
| configured |
| incomplete |
| installed |
| ready |
| running |
| shutting down |
VM Features
Some VM attributes can be updated (or set at VM creation time) in order to make use of features that are supported on SDC. Currently, the following three features can be activated for VMs: delegate dataset, firewall and indestructible zoneroot/dataset.
VM Resize
When properties that represent physical attributes (RAM, swap, quota, I/O priority, etc) of a VM are changed, the VM is considered to have been resized. Since resizing a VM might cause unwanted effects depending on the current resources being utilized on the machine, this feature is only partially supported at the moment. For more information about how to resize a VM please refer to the UpdateVm section of this document. The following table describes the current resize support. Upsizing means when some VM attributes are increased and downsizing refers to the opposite.
| VM Type | Upsize | Downsize |
|---|---|---|
| OS | Supported | Supported |
| docker | Supported | Supported |
| lx | Supported | Supported |
| bhyve | Supported | Supported |
| KVM | Not supported | Not supported |
Delegate Dataset
If the delegate_dataset property is set when creating a non-KVM VM, the
machine will get a ZFS dataset mounted at (zoneroot dataset)/data (or just /data
when inside the VM). This property will only have an effect when passed as a
boolean with a value of true. The following is an example CreateVm call for
a VM with a delegate dataset:
POST /vms -d '{
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"networks": ["a4457fc9-c415-4ac9-8738-a03b1a8e7aee"],
"billing_id":"0ea54d9d-8d4d-4959-a87e-bf47c0f61a47",
"delegate_dataset": true
}'
Disk PCI Slot
Disk can only be added and removed from bhyve instances, and only if
flexible_disk_size is set on those instances.
Bhyve places each disk into a PCI slot that is identified by the PCI bus,
device, and function. The slot is specified as
Per the PCI specification legal values for bus, device and function are:
bus: 0 - 255, inclusive
device: 0 - 31, inclusive
function: 0 - 7, inclusive
All functions on devices 0, 6, 30, and 31 on bus 0 are reserved. If any function other than zero (e.g. 0:4:1) is used, function zero on the same device (e.g. 0:4:0) must also be used for the guest OS to recognize the disk in the non-zero slot.
See the SmartOS vmadm(1M) man page for more details about pci_slot.
Firewall
If the firewall_enabled property is set when creating or updating a VM,
firewall rules will be applied according to FWAPI and fwadm. For more
information about how to specify firewall rules for VMs, please refer to the
FWAPI documentation. The following is an example UpdateVm call for activating
firewall on a VM:
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=update -d '{
"firewall_enabled": true
}'
Indestructible Zoneroot and Delegated
Both properties have the effect of adding an @indestructible snapshot to either the zoneroot (the VM itself) or the delegate dataset in order to prevent them from being deleted. Having an indestructible delegate dataset is useful when reprovisioning a VM, since it's data dataset will be preserved but the VM itself is going to be recreated. The following is an example UpdateVm call for setting indestructible on the zoneroot:
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=update -d '{
"indestructible_zoneroot": true
}'
VM Job Response Object
Any action called on the VMs or Metadata endpoints will result on a new Job being created on the backend. Performing an action on VM doens't imply that changes are going to be reflected immediately, so a Job response object will provide the user with the necessary info to get more details about progress of the task that has been queued. The user can poll the GET /jobs/
{
"vm_uuid": "ef375f03-57ca-44a9-bc8d-63aec09fbc37",
"job_uuid": "6ad3a288-31cf-44e0-8d18-9b3f2a031067"
}
Error Response Object
Error responses will be returned when the response status code is one of 40X errors including 404. These responses will have an error code and a message:
{
"code": "ResourceNotFound",
"message": "Route does not exist"
}
Ping VMAPI
Use ping when you want a general status report from VMAPI. VMAPI makes HTTP connections to REST APIs and TCP connections to services like moray. The ping endpoint provides a compact response object that lets clients know what is VMAPI's point of view of the backend services it is connected to. The following is the format of the ping response object.
Ping (GET /ping)
GET /ping
{
"pingErrors": {},
"pid": 12456,
"status": "OK",
"healthy": true,
"services": {
"wfapi": "online",
"moray": "online"
}
"initialization": {
"moray": {
"status": "BUCKETS_REINDEX_DONE",
"error": "latest error encountered during moray buckets initialization"
}
}
},
"dataMigrations": {
"latestCompletedMigrations": {
"vms": 1
},
"latestErrors": {
"vms": "Error: error encountered during data migrations"
}
}
}
The pingErrors attribute is an object where each of its keys is the name of an API (wfapi, moray, cnapi or napi) and the value of each key is the error response that was obtained after pinging the correspondent service.
Of special note is the status attribute that lets us know if VMAPI is fully functional in terms of data and services initialized. A "healthy: true" value from the ping response means that VMAPI has not had HTTP or backend initialization errors.
The initialization.moray.status property can have the following values:
NOT_STARTED: the moray buckets initialization process hasn't started yet.STARTED: the moray buckets initialization process has started, but all buckets haven't been completely setup (created and updated to the current schemas) yet.BUCKETS_SETUP_DONE: the moray buckets have all been created and/or updated to their current schema.BUCKETS_REINDEX_DONE: the moray buckets have all been created and/or updated to their current schema, and all their rows have been reindexed.FAILED: the moray buckets initialization has failed with a non transient error.
The dataMigrations property is composed of two sub-properties:
-
latestCompletedMigrations: an object that has properties whose names identify data models (vms,server_vms,vm_role_tags) and whose values indicate the sequence number of the latest migrations that completed successfully for that model. -
latestErrors: an object structured similarly tolatestCompletedMigrations, but instead of values identifiying the latest migration that completed successfully, they represent the latest error that occured when migration the data for the corresponding data model.
Metrics
VMAPI exposes metrics via node-triton-metrics on http://<ADMIN_IP>:8881/metrics.
VMs
The Vms endpoint let us get information about VMs living on a SDC install; there is only one VMAPI instance per datacenter. VMAPI acts as an HTTP interface to VM data stored in Moray. VMAPI is used to obtain information about particular VMs, or when we need perform actions on them -- such as start, reboot, resize, etc.
ListVms (GET /vms)
Returns a list of VMs according the specified search filter.
Inputs
All inputs are optional. Inputs that are not listed below are invalid, and will result in a request error.
| Param | Type | Description |
|---|---|---|
| alias | String | VM Alias |
| billing_id | UUID | UUID of the package the VM was created with |
| brand | String | Brand of the VM (joyent, joyent-minimal, lx, bhyve or kvm) |
| create_timestamp | Unix Time in milliseconds or UTC ISO Date String | VM creation timestamp |
| docker | Boolean | true if the VM is a docker VM, false otherwise |
| fields | String (comma-separated values) | Specify which VM fields to return, see below |
| image_uuid | UUID | Image of the VM |
| internal_metadata | String | VM internal metadata, see below |
| owner_uuid | UUID | VM Owner |
| package_name | String | DEPRECATED: use billing_id |
| package_version | String | DEPRECATED: use billing_id |
| uuid | UUID | VM uuid |
| ram | Number | Amount of memory of the VM |
| server_uuid | UUID | Server where the VM lives |
| state | String | running, stopped, active or destroyed |
| uuids | String (comma-separated UUID values) | List of VM UUIDs to match |
| tag.key | String | VM tags, see below |
Specifying VM Fields to Return
Clients can also modify the response objects by specifying the only fields they
are interested in. This is not only useful for fetching smaller responses but
for accessing attributes that can only be explicitly requested, such as
role_tags. The fields query parameter is a comma-separated string of VM
fields, any field that is not part of the VM object will be ignored. This
parameter allows an additional wildcard '*' field, as a shortcut for asking the
API to return all default and non-default fields available. At the moment,
role_tags is the only non-default field supported. The following are some
example requests that use the fields query parameter:
GET /vms?fields=*
GET /vms?fields=role_tags
GET /vms?fields=uuid,role_tags,nics
GET /vms?fields=state,alias,server_uuid
Collection Size Control Inputs
ListVms also allows controlling the size of the resulting collection with the use of the sort, limit, and marker parameters. "sort" and "limit" can be used on either the regular or the LDAP query version of the ListVms endpoint.
| Param | Type | Description |
|---|---|---|
| sort | String | Sort by any of the ListVms inputs (except tags). |
| sort.order | String | Order direction. See below |
| limit | Number | Return only the given number of VMs |
| marker | String | Limit the collection starting from the given VM represented by "marker". |
Limit
Since version 8.0.0, the default and maximum limit on the size of the resulting collection is 1000. In order to paginate through the whole set of VMs, one should either use the "marker" parameter described above, or use the joyent/node-sdc-clients module.
Sorting
The sort direction can be:
- 'asc' or 'ASC' to sort by ascending order
- 'desc' or 'DESC' to sort by descending order
The sort direction is descending by default. The following are some examples of valid values for the sort parameter:
sort=uuid (results in 'uuid DESC')
sort=alias.desc (results in 'uuid DESC')
sort=alias.asc (results in 'uuid ASC')
By default, any response is sorted by uuid descending so that it can be
used as the first page of subsequent paginated requests using the marker
parameter.
Using the "marker" parameter to paginate through results
When listing VMs, the number of VMs returned in the response for one request is limited to 1000 entries. If there are more VMs to list for a given set of parameters/filters, more than one request will need to be sent with the same parameters to paginate through the results. Each request will fetch one page of results.
When paginating through results, set the "marker" parameter for each page but the first one. Set the value of "marker" to a string that represents the latest entry of the previous page.
How to represent the latest entry of the previous page depends on whether the "sort" parameter is used (more below in the sub-section entitled "Using markers when using the "sort" parameter").
But for now let's consider the simple use case of not using the "sort" parameter and describe how to paginate through a list of 4 VMs while using a limit of 2 entries per response:
-
Send the
GET /vms?limit=2request. The "marker" parameter is not used because this request gets the first page of results. -
The response for this request is for instance:
[{uuid: 1},{uuid: 2}] -
Send the same request, this time adding a "marker" parameter. Its value is a JSON string that represents an object with the uuid of the latest entry from the latest results:
GET /vms?limit=2&marker={"uuid": 2} -
The response to this request is for instance:
[{uuid: 3},{uuid: 4}] -
Now send the same request as the previous one, but set "marker" to include the uuid of the latest entry from the latest results:
GET /vms?limit=2&marker={"uuid": 4}. -
The response to this request is an empty array (
[]) because there's only 4 VMs in the data set. We're done paginating through results.
Please note that in reality, uuids are not simple numbers and they are not necessarily contiguous values.
Valid markers
A valid marker is a string that satisfies the following constraints:
-
It is a JSON string that represents a JavaScript object literal. JSON strings that represent strings, arrays or anything else that is not an object literal will result in a request error.
-
It represents an object that has at most two properties:
uuidand any property on which it is possible to sort the result set if a sort parameter is used.
Using markers when using the "sort" parameter
Always include one strict total order field in the marker
Let's consider that we're listing VMs and sorting them by time of creation descending:
GET /vms?sort=create_timestamp.DESC
In this case, it may be tempting to use only the create_timestamp value of
the latest VM object as the marker, and send the following request to get the
second page of results:
GET /vms?sort=create_timestamp.DESC&marker={"create_timestamp": "some_timestamp"}
The problem with this request is that two or more VMs can have the same value
for the create_timestamp property, and thus the server cannot determine
which one(s) to include in the results.
In fact, the server will respond to this request with the following error:
{
"code": "ValidationFailed",
"message": "Invalid Parameters",
"errors": [
{
"field": "marker",
"code": "Invalid",
"message": "Invalid marker: {\"create_timestamp\":\"some_timestamp\"}. A marker needs to have a uuid property from which a strict total order can be established"
}
]
}
The solution to this problem is to always include in the marker a property
that allows to establish a strict total order over the results set so that it
can represent a single object without any ambiguity. Currently, as the error
message mentioned above indicates, the only property that provides this
guarantee is uuid.
Thus, a correct request to get the second page of results is:
GET /vms?sort=create_timestamp.DESC&marker={"create_timestamp": "some_timestamp", "uuid": "uuid-of-latest-vm"}
Always include the sort field in the marker
When using both the sort and marker parameters, make sure the sort field is
included in the marker. For instance, the following request:
GET /vms?sort=create_timestamp.DESC&maker={"uuid":"some-uuid"}
will result in the following error message being sent:
{
"code": "ValidationFailed",
"message": "Invalid Parameters",
"errors": [
{
"field": "marker",
"code": "Invalid",
"message": "Invalid marker: {\"uuid\":\"some-uuid\"}. All sort fields must be present in marker. Sort fields: create_timestamp."
}
]
}
To solve this problem, just include the create_timestamp value for the
latest item in the current result set in the marker:
GET /vms?sort=create_timestamp.DESC&maker={"create_timestamp":"some-timestamp","uuid":"some-uuid"}
Always include marker fields in the sort parameter, except for the uuid field
When using a marker with a field other than uuid, make sure to include this
field in the sort parameter. It is not necessary to include the uuid field
as a sort parameter when using a marker because responses are already sorted
by uuid by default.
For instance, the following request:
GET /vms?marker:{"uuid": "someuuid"}
will not result in an error, but this request:
GET /vms?marker:{"uuid": "someuuid", "create_timestamp": "some_timestamp"}
will result in the following error message being sent:
{
"code": "ValidationFailed",
"message": "Invalid Parameters",
"errors": [
{
"field": "marker",
"code": "Invalid",
"message": "Invalid marker: {\"uuid\":\"someuuid\",\"create_timestamp\":\"some_timestamp\"}. All marker keys except uuid must be present in the sort parameter. Sort fields: undefined."
}
]
}
To fix this problem, just add a sort parameter to the request, like following:
GET /vms?sort=create_timestamp&marker:{"uuid": "someuuid", "create_timestamp": "some_timestamp"}
Deprecated parameters
ListVms also supports parameter that have been deprecated and should not be used anymore.
| Deprecated param | Type | Description |
|---|---|---|
| offset | Number | Limit the collection starting from the given |
| offset |
"offset" and "marker" cannot be used at the same time, and using them both will result in a request error.
Tags
VMs can also be searched by tags. Tags are key/value pairs that let us identify a vm by client-specific criteria. If a VM is tagged as 'role=master', then the search filter to be added to the request params should be 'tag.role=master'. When a tag value is '*', the search is performed for VMs that are tagged with any value of the specified key. Any number of tags can be specified. See the examples section for sample searches of VMs by tags.
Internal metadata
VMs can be searched by internal metadata. Internal metadata is an object with keys and values that are always strings. There are no nested objects/properties. Pattern matching is not available, so matching needs to be exact.
For example, to search for VMs with a docker:logdriver internal metadata key
with a value of "json-file", one can send the following query:
GET /vms?internal_metadata.docker:logdriver=json-file
There is one limitation to keep in mind: matching a string in a given internal metadata key that is larger than 100 characters is not supported.
ListVms Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK | Array of VM objects |
ListVms Examples
GET /vms
GET /vms?limit=10
GET /vms?sort=alias.asc&limit=100
GET /vms?alias=my-vm
GET /vms?state=running
GET /vms?tag.role=sdc
GET /vms?tag.role=sdc&tag.type=database
GET /vms?tag.role=*
ListVms With Search Predicate
Using a predicate is the preferred method for performing advanced searches at GET /vms. A predicate allows us to easily express a complex query when there are several fields that need to match specific values. VMAPI uses the same predicate syntax exposed by Cloud Analtyics (https://mo.joyent.com/docs/ca/master), but some operations such as "lt" (less than) are not supported since they do not form a valid LDAP query syntax.
A predicate can be composed of leaf predicates and compound predicates. Leaf predicates denote a direct comparison, like "field equals value", and compound predicates have one or more subpredicates that can be either compound or leaf predicates themselves.
Leaf Predicates
| Predicate | Description |
|---|---|
| { eq: [ fieldname, value ] } | Equality (field=value) |
| { ne: [ fieldname, value ] } | Inequality (!(field=value)) |
| { le: [ fieldname, value ] } | Less than or equal to (field<=value) |
| { ge: [ fieldname, value ] } | Greater than or equal to (field>=value) |
Compound Predicates
| Predicate | Description |
|---|---|
| { and: [ predicate, ... ] } | All subpredicates must be true. |
| { or: [ predicate, ... ] } | At least one of subpredicates must be true. |
Executing Predicate Queries
A predicate search can be performed by passing a predicate query parameter to
the GET /vms endpoint. Keep in mind that the predicate must be URL encoded, as it
contains characters like '[', '{' , '&', etc. that will not be parsed correctly
by the HTTP server, and will result in a request error.
In order to make testing of predicates easy, use the following code snippet that creates a urlencode helper function that can be called to convert a predicate object to a URL encoded string:
urlencode() {
# urlencode <string>
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c"
esac
done
}
Let's look at some usage examples of search predicates:
Search for VMs with less than or equal to 128MB RAM
sdc-vmapi "/vms?predicate=$(urlencode '{ "le" : [ "ram", 128 ] }')" \
| json -Ha uuid ram
215366ea-1646-4d2b-934d-ba10d7859189 128
54a70ea7-aa36-473f-a095-c1e1dee99966 128
1af5138e-8c23-4fdf-f13a-b0c4d275a026 64
73edd07f-93b9-4463-e132-fcb64b46f3be 64
Search for destroyed VMs tagged with role=database
sdc-vmapi "/vms?predicate=$(urlencode '{ "and" : [ { "eq": ["state", "destroyed" ] }, { "eq": ["tag.role", "database" ] } ] }')" \
| json -Ha uuid ram state tags.role
1af5138e-8c23-4fdf-f13a-b0c4d275a026 64 destroyed database
Search all VMs with a wildcard alias of vmapi* that have 1024MB RAM
sdc-vmapi "/vms?predicate=$(urlencode '{ "and" : [ { "eq" : [ "ram", 1024 ] }, { "eq" : [ "alias", "vmapi*" ] } ] }')" \
| json -Ha uuid ram
2a564d9f-ae52-4ac7-8d98-1ef00a95e086 1024
ListVms With Search Query
There is also an advanced feature in the VMs endpoint, where you can execute an LDAP-compatible search filter if you want a more precise object search. However, you need to consider that the same rules regarding searchable attributes apply to this endpoint, so any search on an non-indexed column will return an error. All the searchable attributes listed in the Inputs table above for the ListVms endpoint can be used, with the exception of create_timestamp, where only its Unix time form can be passed. Additionally, there is a very special format you need to respect if you want to search VMs by tags. More on this below.
Executing LDAP Search Queries
In order to execute a search query against the /vms endpoint, you need to pass a string parameter called query. The string must have the form of a valid LDAP search filter, or you will get an error. Here are some usage examples of this feature:
GET /vms?query=(alias=adminui*)
GET /vms?query=(ram>=1024)
GET /vms?query=(%26(ram<=256)(alias=adminui*)
GET /vms?query=(%26(ram=512)(alias=adminui0))
Note how the '&' character is escaped as '%26', since the query must be URL encoded. The only exception in the searchable attributes are tags. Since tags have a special format in the database, they have a different but straightforward format for the search filter. Below is an example of searching VMs with a specific tag by using a logical OR:
GET /vms?query=(|(tags=*-smartdc_type=core-*)(ram>=1024))
As we can see, all we need to do is to enclose the key=value format of tag by the '*-'' and '-*'' characters. These are some examples of how to convert tags into a search expression for VMAPI:
| Tag Key | Tag Value | Tag String | Search Expression |
|---|---|---|---|
| role | dns | role=dns | tags=*-role=dns-* |
| priority | high | priority=high | tags=*-priority=high-* |
| purpose | db | purpose=db | tags=*-purpose=db-* |
GetVm (GET /vms/:uuid)
Returns a VM with the specified UUID. When sync=true is passed, VMAPI will directly load VM details with a synchronous call to CNAPI. This will also refresh the VMs cache so that if a VM was already destroyed and it doesn't appear to be, it will be marked as such in the process. Using the sync version of this action can be seen as 'force VMAPI' to load the VM information directly from CNAPI.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner. If specified, the VM object will be checked for ownership against this owner_uuid. If vm.owner_uuid does not match the provided value the call will result in a 404 VM Not Found error | No |
| sync | Boolean | Load VM info from CNAPI | No |
Specifying VM Fields to Return
Same as ListVms, clients can modify the response object by specifying the only fields they are interested in. The fields query parameter is a comma-separated string of VM fields, any field that is not part of the VM object will be ignored. This parameter allows an additional wildcard '*' field, as a shortcut for asking the API to return all default and non-default fields available. At the moment, role_tags is the only non-default field supported.
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK | VM object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Examples
GET /vms/00956725-4689-4e2c-9d25-f2172f496f9c
GET /vms/00956725-4689-4e2c-9d25-f2172f496f9c?fields=uuid,role_tags
GET /vms/00956725-4689-4e2c-9d25-f2172f496f9c?fields=*
GET /vms/00956725-4689-4e2c-9d25-f2172f496f9c?sync=true
GetVmProc /proc data (GET /vms/:uuid/proc)
Returns a specific VM's /proc data. Specifically it returns a list of JSON
structs that each contain psinfo and prusage data extracted from /proc.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK | VM object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Examples
GET /vms/00956725-4689-4e2c-9d25-f2172f496f9c/proc
CreateVm (POST /vms)
Queues a VM provision. This will validate all parameters and create a new job on workflow API when the request is considered to be valid. The response is the same as a GET to /vms/:uuid, however some VM attributes might not be present since it has not been provisioned yet. The response also contains a Job-Location header which can be used to get more information about the provisioning job that is being executed by workflow API.
Minimum Required Inputs
| Param | Type | Description |
|---|---|---|
| owner_uuid | UUID | VM Owner |
| networks* | Array* | List of networks. See 'Specifying Networks for a VM' below. |
| brand | String | 'joyent', 'joyent-minimal', 'lx', 'bhvve' or 'kvm' |
| ram* | Number | VM RAM. Not required if billing_id is present |
| billing_id* | UUID | SDC Package UUID. Not required if at least ram is present. See 'Provisioning with an SDC Package' below. |
Required Inputs for OS VMs
| Param | Type | Description |
|---|---|---|
| image_uuid | UUID | Image UUID. This field is not allowed as a top level attribute for a KVM VM payload, see below |
Required Inputs for KVM VMs
| Param | Type | Description |
|---|---|---|
| disks | Array | Disks definition for the KVM VM, see below |
KVM VMs need a list of disks as an additional parameter. For more specific information on the full format that a disk object can take please refer to vmadm(1). In the case of VMAPI, there are only two conditions that need to be met for a valid disks list:
- The first disk MUST have a 'image_uuid' property. This is required because the first disk of the VM is the disk where the OS gets installed. Passing 'image_uuid' at the top level of the VM payload is not allowed as it will not give the expected results.
When image_uuid is passed incorrectly for KVM VMs, VMAPI will return the following error response:
{
"code": "ValidationFailed",
"message": "Invalid VM parameters",
"errors": [
{
"field": "image_uuid",
"code": "Invalid",
"message": "'image_uuid' is not allowed as a top level attribute for a KVM VM"
}
]
}
- The second and following disks in the list MUST have a 'size' property. This is mandatory for any disk that is not the image disk of the VM
The following is a simple example of a valid disks list passed to VMAPI for a KVM VM provision:
"disks": [
{"image_uuid": "56108678-1183-11e1-83c3-ff3185a5b47f"},
{"size": 10240}
]
Additional information that the first disk of the VM needs before the provision is queued is obtained from the Image specified with image_uuid.
Specifying Networks for a VM
CreateVm expects a list of networks for provisioning a new VM. In its legacy interface (to be deprecated), a list network UUIDs can be specified like the following example:
[
'72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2',
'01b2c898-945f-11e1-a523-af1afbe22822
]
This format is suboptimal because it does not allow to specify two additional properties available for each of the network interfaces of the VM. By passing a list of network objects and not a list of UUIDs (strings) for the networks parameter, it is possible to manually assign an IP address to any of the networks and/or to specify which is the primary network interface of the VM.
Instead, the new form of provisioning is what we call 'Interface-centric provisioning'. The idea is that an interface allows to have both an IPv4 and IPv6 network associated with it, and it may have multiple addresses from those networks assigned to it. However, at this time, we only support a single IPv4 network and IP address. The format of this looks like:
[
{ "ipv4_uuid": "72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2", "ipv4_count": 1 },
{ "ipv4_uuid": "01b2c898-945f-11e1-a523-af1afbe22822", "ipv4_ips": [ "10.99.99.11" ] },
...
]
Each object refers to a NIC that will be created. The ipv4_uuid indicates that it is the UUID of an IPv4 network. From there, you can specify the number of IPs you'd like on the network and provide a list of specific IPs that you would like from the network. In the future, these will be able to be combined, but at this time you can only ask for a single IP address, whether specified or passed in with count. If neither of them is specified, or an older format is used, it is treated as though 'ipv4_count' was set to one in the payload.
An older version of the API looked like:
[
{ "uuid": "72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2", ip: "10.99.99.11" },
...
]
These are accepted and translated where 'uuid' becomes 'ipv4_uuid', and 'ip' becomes the 'ipv4_ips' array with a single entry. Note other keys that were specified, described below, are not modified. See the Future Directions section below for what will be coming for the future.
The following are examples of what you can do:
- Regular provision with no customization for networks
Network objects only have an ipv4_uuid property:
[
{ ipv4_uuid: '72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2' },
{ ipv4_uuid: '01b2c898-945f-11e1-a523-af1afbe22822' }
]
- Specifying a custom IP address for any of the networks
Network objects can have an ipv4_ips property. Be advised that manual IP addresses must not be specified without having knowledge of the IP in question
being available for allocation. If the IP is not available for allocation, the provision will fail:
[
{ ipv4_uuid: '72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2', ipv4_ips: [ '10.99.99.11' ] },
{ ipv4_uuid: '01b2c898-945f-11e1-a523-af1afbe22822 }
]
- Specifying the primary network for a VM
Network objects can only have one primary network interface (NIC). When not specified, the first network in the networks list becomes the primary NIC for the VM. A VM will set its default gateway and nameservers to the values obtained from its primary NIC. In the following example we make the second NIC of the VM its primary NIC:
[
{ ipv4_uuid: '72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2' },
{ ipv4_uuid: '01b2c898-945f-11e1-a523-af1afbe22822', 'primary': true }
]
- Specifying network names instead of network UUIDs
It is also possible to use a network's name instead of its UUID when passing the list of networks for the VM. The following example illustrates how to specify a payload of admin and external with external as a primary NIC:
[
{ name: 'admin' },
{ name: 'external', primary: true }
]
It should be noted that the order of the network objects in the networks parameter is significant. The resolvers of a VM will be configured in the same order as the networks were specified in the provision payload. Note, at this time, this form will not be adopted for future revisions and will be limited to only allowing a single IPv4 address.
- Specifying antispoof options for a nic
Network objects can contain boolean antispoof options that enable various types of spoofing. See the NAPI documentation for more details. In the following example we set all antispoof options for the NIC:
[
{
ipv4_uuid: '72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2',
allow_dhcp_spoofing: true,
allow_ip_spoofing: true,
allow_mac_spoofing: true,
allow_restricted_traffic: true
}
]
Future directions
When support for IPv6 and assigning a single VM multiple IPs from the same network, the payload that we have today will be expanded. In this case it will look something like:
[
{
"ipv4_uuid": "72a9cd7d-2a0d-4f45-8fa5-f092a3654ce2",
"ipv4_count": 4,
"ipv4_ips": [ "10.99.99.11", "10.99.99.12" ],
"ipv6_uuid": "22786760-9e96-11e4-8ba2-5bab126f5cf6",
"ipv6_count": 2,
},
...
]
This allows a consumer to say, for each NIC, they want the specified IPv4 network. They want us to provision four arbitrary IPs and they want an additional two IPs which are specified. They'll want the specified IPv6 netowrk and two IPs from that.
Provisioning with an SDC Package
VMs can optionally be provisioned by only providing a 'billing_id' SDC Package identifier. When providing an SDC Package, the following VM attributes can be omitted since they will be inherited from the Package definition:
| Param | Type |
|---|---|
| cpu_cap | Number |
| max_lwps | Number |
| max_physical_memory | Number (MiB) |
| max_swap | Number (MiB) |
| quota | Number (GiB) |
| zfs_io_priority | Number |
| zfs_snapshot_limit | Number |
| vcpus | Number |
However, these values can still be individualy overriden by providing new values for them in the VM provisionm payload. Note that for the purpose of having a 1:1 VM - SDC Package correspondence it is advised that individual values should not be overriden when it is needed to refer a VM back to its original SDC Package.
General Optional Inputs
These inputs can be passed and will be validated whether or not a 'billing_id' SDC Package parameter has been provided.
| Param | Type | Description |
|---|---|---|
| uuid | UUID | The UUID of the VM to be created |
| server_uuid | UUID | Manually specify a server for the provision |
| alias | String | VM alias |
| max_physical_memory | Number (MiB) | Same as RAM |
| max_swap | Number (MiB) | Defaults to 2 x RAM if not specified |
| zfs_io_priority | Number | ZFS IO Priority |
| zfs_snapshot_limit | Number | Number of ZFS snapshots a VM can take |
| cpu_cap | Number | CPU Cap |
| max_lwps | Number | Max. Lightweight Processes |
| quota | Number (GiB) | VM quota |
| tags | Object | VM tags |
| customer_metadata | Object | VM metadata |
| internal_metadata | Object | VM metadata |
| limit_priv | String | List of priviledges to the VM |
| locality | Object | Locates new VM near or far from certain VMs |
Advanced Inputs
The attributes listed above cover the most common VM creation scenarios. There
are additional advanced properties that can be set for a VM. The full set of
attributes that can be specified on VM creation or update are listed in the VM Object
section in this documentation.
Optional Inputs for OS VMs
| Param | Type | Description |
|---|---|---|
| filesystems | Array | Additional filesystems for the OS VM |
Optional Inputs for KVM VMs
| Param | Type | Description |
|---|---|---|
| cpu_type | String | One of qemu64, host |
| vcpus | Number | Number of virtual CPUs for the guest |
| disk_driver | String | One of virtio, ide, scsi |
| nic_driver | String | One of virtio, e1000, rtl8139 |
Response Codes
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 409 | Missing parameter | Error object |
| 409 | Invalid parameter | Error object |
Example: creating an OS VM
POST /vms -d '{
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"networks": ["a4457fc9-c415-4ac9-8738-a03b1a8e7aee"],
"ram": 128,
"quota": 10
}'
Example: creating an OS VM by specifying an SDC Package
POST /vms -d '{
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"networks": ["a4457fc9-c415-4ac9-8738-a03b1a8e7aee"],
"billing_id":"0ea54d9d-8d4d-4959-a87e-bf47c0f61a47"
}'
Example: creating a KVM VM
Note how image_uuid is specified for the first disk and not at the top level of the payload
POST /vms -d '{
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"brand": "kvm",
"ram": 256,
"networks": ["a4457fc9-c415-4ac9-8738-a03b1a8e7aee"],
"disks": [
{"image_uuid": "56108678-1183-11e1-83c3-ff3185a5b47f"},
{"size": 10240}
]
}'
Example: creating a VM with locality hints
Note that the VM uuids specified have to be owned by the same account as the new VM To make locality a hard requirement, set the value of "strict" to true
POST /vms -d '{
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"networks": ["a4457fc9-c415-4ac9-8738-a03b1a8e7aee"],
"ram": 128,
"quota": 10,
"locality": {
"strict": false,
"near": [
"48bb34cc-5f0f-4cf8-834d-06862a6e89b1",
"f7951441-5344-4114-88ce-a064820ed9fe"
],
"far": [
"fb82f801-b90e-475d-951b-028f48ca12c7"
]
}
}'
Updating or Modifying a VM (POST /vms/:uuid)
This endpoint queues an update operation on a VM. The folowing operations are supported: start, stop, reboot, reprovision, update, add_nics, remove_nics, create_snapshot, delete_snapshot and rollback_snapshot. Each of these operations is documented below.
General Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner. If specified, the VM object will be checked for ownership against this owner_uuid. If vm.owner_uuid does not match the provided value the call will result in a 404 VM Not Found error | No |
| action | String | start, stop, reboot, reprovision, update, add_nics, remove_nics, create_snapshot, delete_snapshot, rollback_snapshot | Yes |
| sync | Boolean | Wait for workflow to complete before returning | No |
Response Codes
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
| 409 | Missing parameter | Error object |
| 409 | Invalid parameter | Error object |
StartVm (POST /vms/:uuid?action=start)
See General Inputs
Also allows:
| Param | Type | Description |
|---|---|---|
| update | Object | Optional data to update the vm with before it's started. Currently limited to 'set_internal_metadata'. |
Example
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=start
StopVm (POST /vms/:uuid?action=stop)
No additional inputs are needed for this action.
Example
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=stop
RebootVm (POST /vms/:uuid?action=reboot)
See General Inputs
Also allows:
| Param | Type | Description |
|---|---|---|
| update | Object | Optional data to update the vm with before it's started. Currently limited to 'set_internal_metadata'. |
Example
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=reboot
ReprovisionVm (POST /vms/:uuid?action=reprovision)
Image UUID is a required input for reprovisioning a VM.
| Param | Type | Description |
|---|---|---|
| image_uuid | UUID | Image UUID to reprovision the VM with |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=reprovision -d \
'{ "image_uuid": "01b2c898-945f-11e1-a523-af1afbe22822" }'
Example with form parameters
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=reprovision \
-d image_uuid=01b2c898-945f-11e1-a523-af1afbe22822
UpdateVm (POST /vms/:uuid?action=update)
Similar to CreateVm, this endpoint allows updating a VM to a new SDC Package. Individual SDC Package related attributes can still be provided if one needs to override specific values. UpdateVm is only supported for OS VMs. See VM Resize for more information.
Updating VM to an SDC Package
| Param | Type | Description |
|---|---|---|
| billing_id | UUID | SDC Package UUID |
| force | Boolean | Force the update even if the Compute Node that hosts the VM doesn't have enough capacity |
The UpdateVm payload would automatically retrieve the following values from the provided SDC Package:
| Param | Type |
|---|---|
| cpu_cap | Number |
| max_lwps | Number |
| max_physical_memory | Number (MiB) |
| max_swap | Number (MiB) |
| quota | Number (GiB) |
| zfs_io_priority | Number |
| zfs_snapshot_limit | Number |
| vcpus | Number |
Updating a VM With Individual VM Values
In addition to 'billing_id', the following values can be specified to update additional attributes of the VM.
| Param | Type | Description |
|---|---|---|
| force | Boolean | Force the udpate even if the Compute Node that hosts the VM doesn't have enough capacity |
| alias | String | VM alias |
| new_owner_uuid | UUID | UUID of the new VM Owner |
| ram | Number | VM RAM |
| max_physical_memory (MiB) | Number | Same as RAM |
| max_swap (MiB) | Number | Defaults to 2 x RAM if not specified |
| zfs_io_priority | Number | ZFS IO Priority |
| zfs_snapshot_limit | Number | Number of ZFS snapshots a VM can take |
| cpu_cap | Number | CPU Cap |
| max_lwps | Number | Max. Lightweight Processes |
| quota (GiB) | Number | VM quota (disk) |
| flexible_disk_size (MiB) | Number | Total allowed VM disk space (Bhyve only) |
| tags | Object | VM tags |
| customer_metadata | Object | VM metadata |
| internal_metadata | Object | VM metadata |
| resolvers | Array | New set of resolvers for the VM |
| limit_priv | String | List of priviledges to the VM |
| fs_allowed | String (Comma separated list) | Filesystem types that the VM is allowed to mount |
Advanced Update Inputs
As stated in CreateVm, there are additional advanced properties that can be updated
for a VM. The full set of attributes available for update are listed in the
VM Object section in this documentation.
Example: Renaming a VM and updating its quota
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=update -d '{
"alias": "new-alias",
"quota": 20
}'
Example: Updating a VM to a new SDC Package
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=update -d '{
"billing_id": "73a1ca34-1e30-48c7-8681-70314a9c67d3"
}'
AddNics (POST /vms/:uuid?action=add_nics)
For adding NICs to a VM, either a networks or macs list parameter must be
specified (only one, not both). If networks is provided, NICs will be created
on the VM and in NAPI which attach to those networks. If macs is provided,
NICs will be created on the VM using details from already-created NIC objects in
NAPI.
For more information about the format of networks, see 'Specifying Networks
for a VM' in the CreateVM documentation.
| Param | Type | Description |
|---|---|---|
| networks | Array | List of networks. Same format as CreateVm |
| macs | Array | List of MAC addresses of NICs already created in NAPI |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=add_nics -d '{
"networks": [ { "uuid": "564ded48-c31d-5029-472a-98d5aa9e5a38" } ]
}'
Example with form parameters
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=add_nics \
-d macs=0a:fc:23:10:6e:ff
UpdateNics (POST /vms/:uuid?action=update_nics)
Updates NICs for a VM. Currently, this action serves three purposes: setting a new primary NIC for a VM, setting antispoof flags for a nic, or reordering its NICs. Each NIC object can only contain the following properties:
| Attribute | Type | Description |
|---|---|---|
| mac | MAC Address | NIC MAC Address |
| interface | String | NIC interface/order identifier |
| primary | Boolean | Primary NIC flag |
| allow_ip_spoofing | Boolean | Allow IP spoofing |
| allow_mac_spoofing | Boolean | Allow MAC spoofing |
| allow_restricted_traffic | Boolean | Allow unrestricted traffic |
For the UpdateNics action, a list of at least one NIC object must be specified. If the purpose of the request is to set a new primary NIC, then only one NIC object can have the primary attribute set. If the purpose of the request is to reorder the VM NICs, then every NIC object must have its interface attribute set and the number of NICs in the array must be the same as the number of NICs the VM currently has. The following table describes the only allowed input for UpdateNics:
| Param | Type | Description |
|---|---|---|
| nics | Array | List of NIC objects. See above |
Example: setting a new primary NIC
POST /vms/0cb0f7b1-b092-4252-b205-c9c268bfa148?action=update_nics -d '{
"nics":[{
"mac": "90:b8:d0:d4:02:f5",
"primary": true
}]
}'
Example: reordering the VM NICs
POST /vms/0cb0f7b1-b092-4252-b205-c9c268bfa148?action=update_nics -d '{
"nics":[{
"mac": "90:b8:d0:43:56:ba",
"interface": "net0"
},{
"mac": "90:b8:d0:d4:02:f5",
"interface": "net1"
}]
}'
RemoveNics (POST /vms/:uuid?action=remove_nics)
For removing NICs from a VM, a macs list parameter must be specified. This parameter can be an array of MAC addresses or a comma separated string of MAC addresses.
| Param | Type | Description |
|---|---|---|
| macs | Array | List of MAC addresses |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=remove_nics -d '{
"macs": [ "90:b8:d0:d9:f0:83" ]
}'
Example with form parameters
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=remove_nics \
-d macs=90:b8:d0:d9:f0:83 \
CreateDisk (POST /vms/:uuid?action=create_disk)
Create a virtual disk and attach it to a bhyve VM. VM must be currently stopped, and have flexible_disk_size set.
| Param | Type | Description |
|---|---|---|
| pci_slot | String | Optional. Free PCI slot of disk to create. This is typically in the 0:4:[0-7] and 0:5:[0-7] range. |
| disk_uuid | String | Optional. UUID to uniquely identify disk to create. Useful for client apps. |
| size | Number (MiB) | Size of new virtual disk. Can also use string "remaining" to use up all remaining free space in flexible_disk_size. |
If pci_slot is not provided when creating the disk, a slot will be
automatically assigned. See Disk PCI Slot for more
information about proper assignment of PCI slots.
Likewise with disk_uuid -- if not provided, one will be automatically
assigned.
Example of creating a new 5GiB virtual disk using a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=create_disk -d '{
"pci_slot": "0:4:3",
"size": 5120
}'
ResizeDisk (POST /vms/:uuid?action=resize_disk)
Resizes one of the virtual disks on a bhyve VM. VM must be currently stopped, and have flexible_disk_size set.
| Param | Type | Description |
|---|---|---|
| pci_slot | String | PCI slot of disk to resize |
| size | Number (MiB) | Size to change the virtual disk to |
| dangerous_allow_shrink | Boolean | Since resizing down potentially causes data loss due to internal filesystem truncation, this must be set when shrinking a disk. |
Example: resizing virtual disk "disk1" up to 10GiB using a JSON payload
POST /vms/0cb0f7b1-b092-4252-b205-c9c268bfa148?action=resize_disk -d '{
"slot": "0:4:1",
"size": 10240
}'
DeleteDisk (POST /vms/:uuid?action=delete_disk)
Removes and deletes a virtual disk from a bhyve VM. VM must currently be stopped, and have flexible_disk_size set.
| Param | Type | Description |
|---|---|---|
| pci_slot | String | PCI slot of disk to delete |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=delete_disk -d '{
"pci_slot": "0:4:6"
}'
CreateSnapshot (POST /vms/:uuid?action=create_snapshot)
If a name for the snapshot is not specified, VMAPI will generate a timestamp for its name with the UTC ISO date/time format (without colons or dashes):
YYYYMMDDTHHMMSSZ
Example:
20121018T222506Z
| Param | Type | Description |
|---|---|---|
| snapshot_name | String | Snapshot name or generated timestamp if not present |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=create_snapshot -d \
'{ "snapshot_name": "foobar" }'
Example with form parameters
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=create_snapshot \
-d snapshot_name=foobar
DeleteSnapshot (POST /vms/:uuid?action=delete_snapshot)
| Param | Type | Description |
|---|---|---|
| snapshot_name | String | Snapshot name |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=delete_snapshot -d \
'{ "snapshot_name": "foobar" }'
Example with form parameters
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=delete_snapshot \
-d snapshot_name=foobar
RollbackSnapshot (POST /vms/:uuid?action=rollback_snapshot)
If the VM is running at the moment of the request, it will be shutdown before executing the rollback and be booted again after the rollback has succeeded.
| Param | Type | Description |
|---|---|---|
| snapshot_name | String | Snapshot name |
Example with a JSON payload
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=rollback_snapshot -d \
'{ "snapshot_name": "foobar" }'
Example with form parameters
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=rollback_snapshot \
-d snapshot_name=foobar
DeleteVm (DELETE /vms/:uuid)
Deletes a VM. If the VM exists and has a server_uuid that refers to an actual
CN that is available, the VM will be physically destroyed and it will be marked
as destroyed in the cache database.
If the VM doesn't have a server_uuid, the request will result in an error.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner. If specified, the VM object will be checked for ownership against this owner_uuid. If vm.owner_uuid does not match the provided value the call will result in a 404 VM Not Found error | No |
Responses
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
| 409 | VM not allocated to a server yet | Error object |
On a successful response, a VM Job Response Object is returned in the response body.
Example
DELETE /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83
HTTP/1.1 202 Accepted
Connection: close
workflow-api: http://workflow.coal.joyent.us
Content-Type: application/json
Content-Length: 100
Content-MD5: as77tkERx4gj7igpE83PyQ==
Date: Mon, 24 Apr 2017 22:30:44 GMT
Server: VMAPI
x-request-id: d169bbdf-a54c-4f71-a543-8928cda5b152
x-response-time: 170
x-server-name: d6334b70-2e19-4af4-85ba-53776ef82820
{
"vm_uuid": "e9bd0ed1-7de3-4c66-a649-d675dbce6e83",
"job_uuid": "56aca67a-5374-4117-9817-6ac77060697e"
}
VM Metadata
There are three kinds of metadata a VM can store: customer_metadata, internal_metadata and tags. A metadata object is any valid set of key/value pairs that can be properly encoded to JSON. Values must be strings, numbers or booleans. Examples:
{
"ip": "10.99.99.9",
"boolean": true,
"string": "foobar",
"number": 42
}
VM Tags allow VMs to be grouped by any criteria. Tags are key/value pairs that can be assigned to any VM. For example, VMs can be grouped by tagging them as a database role with a tag such as '{ role: "database" }'.
Customer and internal metadata are used to store relevant information to the VM, such as IP addresses of dependent VMs or initialization scripts that run when the VM is being setup.
The following API endpoints are equivalent for tags, customer_metadata and internal_metadata since all three metadata types share the same representation.
ListMetadata (GET /vms/:uuid/(tags|customer_metadata|internal_metadata))
Returns metadata assigned to a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Metadata object | |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
GET /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
{
"role": "dns",
"customer": "tracy"
}
GetMetadata (GET /vms/:uuid/(tags|customer_metadata|internal_metadata)/:key)
Returns the value of a metadata key.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| key | String | Metadata Key | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | String value of the metadata key | |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
GET /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags/role
dns
AddMetadata (POST /vms/:uuid/(tags|customer_metadata|internal_metadata))
Adds a new metadata to a VM. Keep in mind that metadata gets appended, not overwritten.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| metadata | key-value/object | Metadata | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
POST /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
-d customer=tracy
POST /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
--data-binary '{ "customer": "tracy" }'
SetMetadata (PUT /vms/:uuid/(tags|customer_metadata|internal_metadata))
Sets new metadata to a VM. The provided metadata object replaces the current one present in the VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| metadata | key-value/object | Metadata | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
PUT /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
-d customer=tracy
PUT /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
--data-binary '{ "customer": "tracy" }'
DeleteMetadata (DELETE /vms/:uuid/(tags|customer_metadata|internal_metadata)/:key)
Deletes a metadata key from a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| key | String | Metadata Key | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
DELETE /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags/role
DeleteAllMetadata (DELETE /vms/:uuid/(tags|customer_metadata|internal_metadata))
Deletes all metadata keys from a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
Responses
| Code | Description | Response |
|---|---|---|
| 202 | New job created | VM response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
DELETE /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
VM Role Tags
Role Tags is a role based access control (RBAC) feature for Manta and CloudAPI. At the VMAPI level, VMs can be assigned a list of role tags (UUID strings) and then the API exposes functionality to allow searching for VMs that match a specific list of role UUIDs. The use of role tags doesn't have any effects on the lifecycle of VMs and doesn't make physical changes to them either. The use of this feature is optional.
CreateVm With Role Tags
CreateVm also accepts a role_tags parameter in order to provision a VM that will have role tags assigned from the moment it starts running. Role tags for new VMs are specified in the request body of the CreateVm request call exactly the same way as other allowed parameters.
Inputs
| Param | Type | Description |
|---|---|---|
| role_tags | String (comma-separated list of UUIDs) | Role Tags |
Example CreateVm Call with Role Tags
POST /vms -d '{
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"networks": ["a4457fc9-c415-4ac9-8738-a03b1a8e7aee"],
"ram": 128,
"quota": 10,
"role_tags": ["fd48177c-d7c3-11e3-9330-28cfe91a33c9"]
}'
ListVms With Role Tags
ListVms accepts a role_tags query parameter that enables filtering all VMs that match one or more role_tags provided. Since VM objects are returned without role_tags by default, clients need to additionally pass which fields they want to be returned as part of the response, should they need each VM's role_tags in addition to their default properties.
Inputs
| Param | Type | Description |
|---|---|---|
| role_tags | String (comma-separated list of UUIDs) | Role Tags |
| fields | String (comma-separated values) | Specify which VM fields to return |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK | Array of VM objects |
| 409 | Invalid Role Tags | Error object |
Examples
Specify one or more role_tags:
GET /vms?role_tags=c4cbe913-f15a-4232-985b-950c23d68873
HTTP/1.1 200 OK
x-joyent-resource-count: 1
Connection: close
Content-Type: application/json
Content-Length: 1047
Content-MD5: DE97n7WReix5z/TC4B/zig==
Date: Fri, 18 Apr 2014 00:00:28 GMT
Server: VMAPI
...
[
{
"uuid": "6cfa6474-d838-42ef-9f38-4e66b604deb7",
"alias": null,
"autoboot": true,
"brand": "joyent-minimal",
...
GET /vms?role_tags=c4cbe913-f15a-4232-985b-950c23d68873,f8b5ed20-c598-11e3-8bd4-f74769a100ec
HTTP/1.1 200 OK
x-joyent-resource-count: 2
Connection: close
Content-Type: application/json
Content-Length: 3119
Content-MD5: ePnd9pbA/jcxugimI9Flyw==
Date: Fri, 18 Apr 2014 00:01:44 GMT
Server: VMAPI
...
[
{
"uuid": "c4cbe913-f15a-4232-985b-950c23d68873",
"alias": "adminui0",
"autoboot": true,
"brand": "joyent-minimal",
...
...
...
},
{
"uuid": "6cfa6474-d838-42ef-9f38-4e66b604deb7",
"alias": null,
"autoboot": true,
"brand": "joyent-minimal",
...
...
...
}
]
Return role_tags and additional fields for every VM object:
GET /vms?role_tags=c4cbe913-f15a-4232-985b-950c23d68873,f8b5ed20-c598-11e3-8bd4-f74769a100ec&fields=uuid,state,role_tags
HTTP/1.1 200 OK
x-joyent-resource-count: 2
Connection: close
Content-Type: application/json
Content-Length: 241
Content-MD5: G/U2xT9peoZ8ZozkH60ZEg==
Date: Fri, 18 Apr 2014 00:03:38 GMT
Server: VMAPI
...
[
{
"uuid": "c4cbe913-f15a-4232-985b-950c23d68873",
"state": "running",
"role_tags": [
"f8b5ed20-c598-11e3-8bd4-f74769a100ec"
]
},
{
"uuid": "6cfa6474-d838-42ef-9f38-4e66b604deb7",
"state": "destroyed",
"role_tags": [
"c4cbe913-f15a-4232-985b-950c23d68873"
]
}
]
GetVm With Role Tags
Similarly to ListVms, The VM object returned by GetVm doesn't have a role_tags attribute by default, clients need to make that explicity via the fields query parameter.
Inputs
| Param | Type | Description |
|---|---|---|
| fields | String (comma-separated values) | Specify which VM fields to return |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK | VM object |
| 409 | Invalid Role Tags | Error object |
Example
Return basic VM attributes in addition to role_tags
GET /vms/c4cbe913-f15a-4232-985b-950c23d68873?fields=uuid,alias,ram,state,nics,role_tags
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 294
Content-MD5: eNeaJ38SPtlU8Xa4osHgrg==
Date: Mon, 21 Apr 2014 17:31:40 GMT
Server: VMAPI
...
{
"uuid": "c4cbe913-f15a-4232-985b-950c23d68873",
"alias": "adminui0",
"ram": 2048,
"state": "running",
"nics": [
{
"interface": "net0",
"mac": "82:6e:d6:5c:e4:36",
"vlan_id": 0,
"nic_tag": "admin",
"ip": "10.99.99.32",
"netmask": "255.255.255.0",
"primary": true
}
],
"role_tags": [
"f8b5ed20-c598-11e3-8bd4-f74769a100ec"
]
}
AddRoleTags (POST /vms/:uuid/role_tags)
Appends one or more role tags to a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| role_tags | Array of UUID | Role Tags | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK. Role Tags Added | VM Role Tags. Array of UUID |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
| 409 | Invalid Role Tags | Error object |
Example
POST /vms/a1593802-79c9-4bf1-a7af-c6d43a36852c/role_tags
-d '{ "role_tags": ["d034f9e0-c97b-11e3-a970-7bd3b454fb1a"] }'
[
"b6368edf-464f-4c72-a134-a21bb6bae434",
"d034f9e0-c97b-11e3-a970-7bd3b454fb1a"
]
SetRoleTags (PUT /vms/:uuid/role_tags)
Sets new role tags for a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| role_tags | Array of UUID | Role Tags | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK. Role Tags Replaced | New VM Role Tags. Array of UUID |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
| 409 | Invalid Role Tags | Error object |
Example
PUT /vms/a1593802-79c9-4bf1-a7af-c6d43a36852c/role_tags
-d '{ "role_tags": ["d034f9e0-c97b-11e3-a970-7bd3b454fb1a"] }'
[
"d034f9e0-c97b-11e3-a970-7bd3b454fb1a"
]
DeleteRoleTag (DELETE /vms/:uuid/role_tags/:role_tag)
Deletes a role tag from a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
| role_tag | UUID | Role Tag | Yes |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK. Role Tag removed | New VM Role Tags. Array of UUID |
| 404 | VM or Role Tag Not Found. VM or Role Tag do not exist or VM does not belong to the specified owner | Error object |
Example
DELETE /vms/a1593802-79c9-4bf1-a7af-c6d43a36852c/role_tags/d034f9e0-c97b-11e3-a970-7bd3b454fb1
[
"b6368edf-464f-4c72-a134-a21bb6bae434"
]
DeleteAllRoleTags (DELETE /vms/:uuid/role_tags)
Deletes all role tags from a VM.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | VM UUID | Yes |
| owner_uuid | UUID | VM Owner | No |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Response OK. Role Tags removed | No response body |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Example
DELETE /vms/da0dfac1-341e-4e51-b357-99f7355f1008/tags
Jobs
Jobs are created when an operation needs to be performed on a VM. Examples of jobs that can be created are VM lifecycle tasks such as start and reboot. Provision jobs are created from calling "POST /vms".
ListJobs (GET /jobs)
Returns all jobs matching the specified search filters.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| vm_uuid | UUID | Return all jobs for this VM UUID | No |
| execution | String | Job state. See below | No |
| task | String | Type of job. See below | No |
Job 'execution' State Inputs
| Execution |
|---|
| running |
| succeeded |
| failed |
Job 'task' Type Inputs
NOTE Any metadata endpoint that returns a Job response object is an 'update' job for the backend system.
| Task |
|---|
| provision |
| start |
| stop |
| reboot |
| update |
| destroy |
Example
GET /jobs?execution=failed
GET /jobs?task=provision
ListVmJobs (GET /vms/:uuid/jobs)
Returns all VM jobs matching the specified search filters. This is the same implementation as the previous endpoint, but with a more convenient path when the VM UUID is known.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | Return all jobs for this VM UUID | No |
| execution | String | Job state. See above | No |
| task | String | Type of job. See above | No |
Example
GET /vms/da0dfac1-341e-4e51-b357-99f7355f1008/jobs?execution=failed
GET /vms/da0dfac1-341e-4e51-b357-99f7355f1008/jobs?task=provision
GetJob (GET /jobs/:uuid)
Returns a job with the specified UUID.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | Job UUID | Yes |
Example
GET /jobs/6ad3a288-31cf-44e0-8d18-9b3f2a031067
{
"name": "provision-4e4ff04b-5cc4-437e-92da-2403a634e74f",
"uuid": "6ad3a288-31cf-44e0-8d18-9b3f2a031067",
"execution": "succeeded",
"params": {
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"ram": "128",
"zonename": "e9bd0ed1-7de3-4c66-a649-d675dbce6e83",
"uuid": "e9bd0ed1-7de3-4c66-a649-d675dbce6e83",
"server_uuid": "564da914-5047-48f0-ba5e-26761097330a",
"task": {
"id": "70129767",
"progress": 100,
"status": "complete"
}
},
"exec_after": "2012-04-13T18:17:15.194Z",
"created_at": "2012-04-13T18:17:15.198Z",
"timeout": 180,
"chain_results": [
{
"result": "All parameters OK!",
"error": "",
"started_at": "2012-04-13T18:17:17.512Z",
"finished_at": "2012-04-13T18:17:18.619Z"
},
{
"result": "Got servers!",
"error": "",
"started_at": "2012-04-13T18:17:18.628Z",
"finished_at": "2012-04-13T18:17:21.737Z"
},
{
"result": "Server allocated!",
"error": "",
"started_at": "2012-04-13T18:17:21.743Z",
"finished_at": "2012-04-13T18:17:23.137Z"
},
{
"result": "Provision succeeded!",
"error": "",
"started_at": "2012-04-13T18:17:23.197Z",
"finished_at": "2012-04-13T18:18:42.726Z"
}
]
}
WaitJob (GET /jobs/:uuid/wait)
Waits until the given job with the specified UUID is finished (i.e. when the job execution state is one of "succeeded", "failed" or "canceled").
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuid | UUID | Job UUID | Yes |
Example
GET /jobs/6ad3a288-31cf-44e0-8d18-9b3f2a031067/wait
{
"name": "provision-4e4ff04b-5cc4-437e-92da-2403a634e74f",
"uuid": "6ad3a288-31cf-44e0-8d18-9b3f2a031067",
"execution": "succeeded",
"params": {
"owner_uuid": "930896af-bf8c-48d4-885c-6573a94b1853",
"image_uuid": "28445220-6eac-11e1-9ce8-5f14ed22e782",
"brand": "joyent",
"ram": "128",
"zonename": "e9bd0ed1-7de3-4c66-a649-d675dbce6e83",
"uuid": "e9bd0ed1-7de3-4c66-a649-d675dbce6e83",
"server_uuid": "564da914-5047-48f0-ba5e-26761097330a",
"task": {
"id": "70129767",
"progress": 100,
"status": "complete"
}
},
"exec_after": "2012-04-13T18:17:15.194Z",
"created_at": "2012-04-13T18:17:15.198Z",
"timeout": 180,
"chain_results": [
{
"result": "All parameters OK!",
"error": "",
"started_at": "2012-04-13T18:17:17.512Z",
"finished_at": "2012-04-13T18:17:18.619Z"
},
{
"result": "Got servers!",
"error": "",
"started_at": "2012-04-13T18:17:18.628Z",
"finished_at": "2012-04-13T18:17:21.737Z"
},
{
"result": "Server allocated!",
"error": "",
"started_at": "2012-04-13T18:17:21.743Z",
"finished_at": "2012-04-13T18:17:23.137Z"
},
{
"result": "Provision succeeded!",
"error": "",
"started_at": "2012-04-13T18:17:23.197Z",
"finished_at": "2012-04-13T18:18:42.726Z"
}
]
}
VM Migration
It is possible to migrate (move a VM) to another CN using these APIs. See RFD 34 for the background on how and why instance migration works the way it does.
VM migration operates in three distinct phases, the begin phase creates a hidden target placeholder vm for which to migrate into, the sync phase will synchronize the underlying filesystems and the switch phase will shutdown the original source vm, perform a final filesystem synchronization, hide the original source VM and then enable and restart the target VM.
A migration can be set to run all of these phases in one (automatic migration) or these phases can each be run manually (on demand migration).
For any migration action (e.g. begin, sync, switch or abort) you can use the migration watch endpoint to show progress information for the running migration action.
After performing a migration switch (or full automatic migration), if everything is working in the newly migrated instance you can then use the migration finalize action, which will remove the original (now hidden) source instance and complete the migration process, else if the new instance is not working correctly, you can perform a migration rollback action, which will reinstate the original source instance and delete the migration target instance, reverting to the state of the instance before the migration switch action.
User migrations are disabled by default, but that can be changed globally by setting the VMAPI/SAPI user_migration_allowed setting to true, or changed on a per-instance basis by updating vm.internal_metadata.user_migration_allowed to true.
VmMigrateList (GET /migrations)
Returns the list of Migration Objects.
Optional Inputs
| Param | Type | Description |
|---|---|---|
| format | String | Can be set to 'raw' to receive the raw (full) migration objects. |
| owner_uuid | UUID | VM Owner |
| state | String | Query for migrations in a certain state. Can be one of the defined Migration States, or "active". The "active" query will return all migrations in one of the states "running", "paused" or "failed". |
VmMigrateList Examples
GET /migrations
GET /migrations?owner_uuid=77118fd1-b0f0-4e72-9d1d-aea57fe8b47c
GET /migrations?state=active&format=raw
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Successful | JSON array of Migration Objects. |
VmMigrateGet (GET /migrations/:uuid)
Returns the list of Migration Objects.
Optional Inputs
| Param | Type | Description |
|---|---|---|
| format | String | Can be set to 'raw' to receive the raw (full) migration object. |
| owner_uuid | UUID | VM Owner |
VmMigrateGet Examples
GET /migrations/5ad11be4-605c-4f64-b673-e0920ac0ac64
GET /migrations/5ad11be4-605c-4f64-b673-e0920ac0ac64?format=raw&owner_uuid=77118fd1-b0f0-4e72-9d1d-aea57fe8b47c
Responses
| Code | Description | Response |
|---|---|---|
| 200 | Successful | A JSON Migration Object. |
VmMigrateDelete (DELETE /migrations/:uuid)
Forcibly delete a Migration Object. This should only be used when the abort/rollback migration actions have failed.
VmMigrateDelete Examples
DELETE /migrations/5ad11be4-605c-4f64-b673-e0920ac0ac64
VmMigrateDelete Responses
| Code | Description | Response |
|---|---|---|
| 200 | Successful | Nothing. |
VmMigrateEstimate (POST /vms/:uuid?action=migrate&migration_action=estimate)
Get an estimate for how long a migration would take to complete.
Optional Inputs
| Param | Type | Description |
|---|---|---|
| owner_uuid | UUID | VM Owner |
Responses
| Code | Description | Response |
|---|---|---|
| 200 | OK - estimate was completed. | Migration Estimate Object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Migration Estimate Object
Migration objects store the state of a migration operation.
| Field | Type | Description |
|---|---|---|
| size | Number | Number of filesystem bytes that will need to be migrated. |
| eta_ms | Number | Estimate of the number of milliseconds until the task is completed. |
| transfer_bytes_second | Number | Estimate for the number of bytes that would be sent per second between the source and target instances during the "sync" phase. |
Example:
{
"eta_ms": 3600142,
"size": 484302896,
"transfer_bytes_second": 10000000
}
VmMigrate (POST /vms/:uuid?action=migrate&migration_action=ACTION)
Starts the specified migration action.
Inputs
| Param | Type | Description |
|---|---|---|
| migration_action | String | One of "begin", "sync", "switch", "pause", "abort", "finalize" or "rollback". |
Optional Inputs
| Param | Type | Description |
|---|---|---|
| migration_automatic | Boolean | Use to enable full automatic migration. A full migration will perform begin, multiple syncs and switch. |
| owner_uuid | UUID | VM Owner |
| override_server_uuid | UUID | Migration target will be provisioned to this server. |
Migrate Begin
The "begin" action starts a workflow job that will create (provision) a target vm instance on a different CN that will be used to perform the migration. Once a begin job is completed successfully, you can then run the migration sync action.
The begin phase will utilize the existing Triton provisioning and allocation APIs to ensure proper placement of the migrated VM.
Migrate Sync
The "sync" action starts a workflow job that will synchronize the filesystems between the source and target VMs.
This phase can be run multiple times, with each subsequent sync operation only transferring the filesystem differences since the last sync. When two or more sync jobs have completed successfully, you can then run migration switch.
Migrate Switch
The "switch" action starts a workflow job that will switch over control to the target (migrated) vm and hide the original source vm.
This phase will shutdown the source vm, perform a final sync, deactivate the source vm, then activate the target vm and finally start up the target vm (if the source vm was originally running).
Migrate Pause
This action is only actionable when migration sync is running. It is used to stop the migration sync operation and place the migration into a paused state.
Migrate Abort
This action is only actionable when the migration is paused or failed. It is used to abort the migration, removing the target placeholder vm and ensuring the source vm is returned to it's original state.
Migrate Rollback
The "rollback" action will remove (decommission) the newly migrated target instance and restore the original source instance back as the primary (and visible) instance. Any filesystem changes made to the target instance since it was primary (i.e. since the migration switch) will be lost. After a successful migration rollback, the migration record will have been removed.
Migrate Finalize
The "finalize" action will remove (decommission) the original source vm (which was hidden during the "switch" action). Finalize will return a 200 status code when successful and the migration record will have been removed.
VmMigrate Response
On a successful response, a Migration Job Response Object is returned in the response body and you can use the migration watch endpoint to follow the progress of the migration.
| Code | Description | Response |
|---|---|---|
| 200 | Action was successful | None |
| 202 | New job created, use migration watch to track the progress | VM job response object |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
| 409 | VM failed to validate. | Error object |
Examples
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=migrate&migration_action=begin
HTTP/1.1 202 Accepted
Connection: close
workflow-api: http://workflow.coal.joyent.us
Content-Type: application/json
Content-Length: 100
Content-MD5: as77tkERx4gj7igpE83PyQ==
Date: Mon, 24 Apr 2017 22:30:44 GMT
Server: VMAPI
x-request-id: d169bbdf-a54c-4f71-a543-8928cda5b152
x-response-time: 170
x-server-name: d6334b70-2e19-4af4-85ba-53776ef82820
{
"job_uuid": "56aca67a-5374-4117-9817-6ac77060697e",
"migration": {
... see (Migration Object)
}
}
POST /vms/e9bd0ed1-7de3-4c66-a649-d675dbce6e83?action=migrate&migration_action=finalize
HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
Content-Length: 2
Content-MD5: bs77tdERx4Kj7igpE33AbZ==
Date: Mon, 24 Apr 2019 10:30:00 GMT
Server: VMAPI
x-request-id: d169bbdf-a54c-4f71-a543-8928cda5b152
x-response-time: 1970
x-server-name: d6334b70-2e19-4af4-85ba-53776ef82820
{}
Migration Job Response Object
Most migration actions on a VM will result in a new Job being created on the backend. The job uuid will be returned, along with the migration record itself in the response object.
Example:
{
"job_uuid": "6ad3a288-31cf-44e0-8d18-9b3f2a031067",
"migration": {
"automatic": false,
"created_timestamp": "2019-04-02T23:34:30.135Z",
"phase": "begin",
"state": "running",
"vm_uuid": "658e2899-5c9a-4e24-f768-f0d44aed5902",
"progress_history": []
}
}
Migration Objects
Migration objects store the state of a migration operation.
| Field | Type | Description |
|---|---|---|
| vm_uuid | UUID | Instance UUID of the instance being migrated. |
| automatic | Boolean | Whether this migration will run all phases without any user intervention. |
| created_timestamp | String | ISO timestamp for the creation of the migration request. |
| phase | String | Current migration phase - see Migration Phases. |
| state | String | Current migration state - see Migration States. |
| progress_history | Array | An Array of completed JSON progress events - see Migration Progress Events. |
| error | String | If a migration fails - this is the error message of why it failed. |
Migration States
The state the migration operation is currently in. It can be one of the following states:
| State | Description |
|---|---|
| running | Migration running, see also progress_history. |
| paused | The "begin" phase (and possibly "sync" phase) has been run - now waiting for a call to "sync" or the final call to "switch". |
| failed | Migration operation could not complete, see migration "error" field. |
| successful | Migration was successfully completed. |
Migration Phases
The workflow stage that the migration is currently running, one of:
| Phase | Description |
|---|---|
| begin | This phase starts the migration process, creates a new migration database entry and provisions the target instance. |
| sync | This phase synchronizes the zfs datasets of the source instance with the zfs datasets in the target instance (without stopping the instance). |
| switch | This phase stops the instance from running, synchronizes the zfs datasets of the source instance with the zfs datasets in the target instance, moves the NICs from the source to the target instance, moves control to the target instance and then restarts the target instance. |
| abort | This phase is used when aborting a migration. |
VmMigrateWatch (GET /migrations/:uuid/watch)
Receive progress for an existing migration.
Optional Inputs
| Param | Type | Description |
|---|---|---|
| owner_uuid | UUID | VM Owner |
VmMigrateWatch Response
On success, you will receive a newline delimited JSON stream of Migration Progress Events, which will continue whilst the migration is running. At the end of the migration action (or if no action was running) a final Migration End Event will be sent and the connection will be closed.
| Code | Description | Response |
|---|---|---|
| 200 | OK - watching migration. | Migration Progress Events |
| 404 | VM Not Found. VM does not exist or VM does not belong to the specified owner | Error object |
Migration Progress Events
The migration watch endpoint will send progress events to inform what is
occurring during the migration. There are actually two styles of progress
events - one for major events (and/or warnings) and one to show the sync
progress (bandwidth and eta).
| Field | Type | Description |
|---|---|---|
| type | String | Type is "progress". |
| phase | String | Current phase. See Migration Phases. |
| state | String | State is "running". See Migration States. |
| current_progress | Number | This is how much progress has been made. For the sync phase, this is the number of bytes that have been sent to the target. |
| total_progress | Number | This is total possible progress. For the sync phase, this is the number of bytes that will need to be sent to the target. |
| message | String (optional) | Additional description message for this task. |
| error | String (optional) | Error occurred in this task - this is the description for that error. |
| started_timestamp | String (optional) | The ISO timestamp when the phase was started. |
| duration_ms | Number (optional) | The number of milliseconds the phase has taken. |
| eta_ms | Number (optional) | Estimate of the number of milliseconds until the task is completed. |
| transfer_bytes_second | Number (optional) | The number of bytes being sent per second between the source and target instances during the "sync" phase. |
Migration End Event
At the end of a migration watch a final end event is sent containing these fields:
| Field | Type | Description |
|---|---|---|
| type | String | Type is "end". |
| phase | String | Phase that just ended. See Migration Phases. |
| state | String | State, one of "running", "paused", "failed" or "successful". See Migration States. |
Running Status for VMs
When querying one of the VM endpoints such as the single and collection VM URLs, the 'state' attribute of the VM object let us know what is the running status of the machine. In addition to this, a '/statuses' endpoint is provided to give information about specific VM UUIDs instead of returning VM objects for machines that satisfy a search criteria.
ListStatuses (GET /statuses)
Returns the running status for all of the VM UUIDs specified in the request parameters.
Inputs
| Param | Type | Description | Required? |
|---|---|---|---|
| uuids | Array of UUIDs | Comma separated list of UUIDs | Yes |
Note
When one of the UUIDs in the request parameters corresponds to a machine that does not exist, it is ignored in the response object instead of returning null.
Example
GET /statuses?uuids=54e21a72-5921-4c5a-92db-fb662c8a812a,4f11fbab-dcc0-483f-bb14-e1434465032a
{
"54e21a72-5921-4c5a-92db-fb662c8a812a": "running",
"4f11fbab-dcc0-483f-bb14-e1434465032a": "stopped"
}
Miscellaneous / Internal
There are some VMAPI endpoints that are intended for internal use by other
Triton services such as vm-agent and workflow, and are not intended for use
by operators. We document them here for the benefit of other developers.
PutVm (PUT /vms/:uuid)
Typically used by vm-agent and workflow to tell VMAPI to update the
Moray object that represents the VM in question.
PutVms (PUT /vms?vms=vms)
Just like PutVm but operates on a list of VMs.
JobResults (POST /job_results)
This is used by workflow pass the results of a job back to VMAPI. In other
words, it is the moral equivalent of a return statement.
Operator Guide
This section is intended to give necessary information for diagnosing and dealing with issues with VMAPI in a SmartDataCenter installation.
There is one VMAPI service per datacenter. There might actually be more than one "vmapi" zone for HA. Use this to list the vmapi zones in a DC:
sdc-vmapi /vms?owner_uuid=$(bash /lib/sdc/config.sh -json | json ufds_admin_uuid) \
| json -H -c "this.tags.smartdc_role=='vmapi'"
VMAPI Configuration File
By default, VMAPI's configuration file is located at "./config.json". Any value in the table below that has a default value can be overrided in the configuration file. Note that this file should only be modified if any other service depending on VMAPI is updated as well.
| var | type | default | description |
|---|---|---|---|
| port | Number | 80 | Port number on which to listen. |
| logLevel | String or Number | debug | Level at which to log. One of the supported Bunyan log levels. |
| maxSockets | Number | 100 | Maximum number of sockets for external API calls |
| api | Object | - | VMAPI configuration |
| api.port | Number | - | VMAPI port |
| wfapi | Object | - | WFAPI configuration |
| wfapi.url | String | - | WFAPI URL |
| wfapi.forceReplace | Boolean | false | Replace workflows every time VMAPI restarts |
| wfapi.workflows | Array | - | List of workflows to load on start |
| cnapi | Object | - | CNAPI configuration |
| cnapi.url | String | - | CNAPI URL |
| napi | Object | - | NAPI configuration |
| napi.url | String | - | NAPI URL |
| moray | Object | - | Moray configuration |
| moray.host | String | - | Moray hostname |
| moray.port | Number | - | Moray port |
| moray.connectTimeout | Number | - | Moray connection timeout |
| moray.retry | Object | - | Moray retry object |
| moray.retry.minTimeout | Number | - | Moray minimum retry timeout |
| moray.retry.maxTimeout | Number | - | Moray maximum retry timeout |
| docker_tag_re | String | - | Tags matching regex are treated with Docker tag semantics |
SAPI Configuration
When using the config-agent service in a VMAPI zone, which draws metadata from
SAPI, it's possible to change some of the defaults outlined in the
VMAPI Configuration File section above.
In the SAPI "vmapi" service, adding or changing the following keys in
metadata can change some VMAPI behaviours for specialized circumstances in
production.
| Key | Type | Description |
|---|---|---|
| experimental_fluentd_host | String | |
| docker_tag_re | String | Tags matching regex are treated with Docker tag semantics |
| migration_send_mbps_limit | Number | Limit of transfer rate, in megabits per second, for individual migrations |
| user_migration_allowed | Boolean | Whether user migrations are allowed (default is false). This setting can also be overruled on a per-instance basis through the vm.internal_metadata.user_migration_allowed setting. |
| server_state_affects_vm_state | Boolean | When enabled (default is false) each running vm that is on a server that is not running (CNAPI.server.status) will have it's state changed to 'unknown'. |
docker_tag_re must be a valid regular expression string -- more concretely,
what Javascript's RegExp() considers valid. Docker tags can be added during
provisioning, but otherwise cannot later be altered or removed, and may have
special significance to Docker. It's recommended to not change docker_tag_re
unless you're aware of the semantics and effects of Docker tags.
Health
As seen in the API actions documentation, VMAPI has a "/ping" endpoint to indicate if it is up
$ sdc-vmapi /ping
or if there are multiple VMAPI servers:
$ for ip in $(bash /lib/sdc/config.sh -json | json vmapi_admin_ips | tr ',' ' '); do \
echo "# $ip" ; \
curl -sS http://$ip/ping | json ; \
done
Logs
TODO: how to dynamically change log levels
VMAPI is a single SMF service that operates on a SmartOS VM. The following is the location/command for accessing the log file written by the VMAPI service:
| service/path | where | format | tail -f |
|---|---|---|---|
| vmapi | in each "vmapi" zone | Bunyan | `` sdc-login vmapi; tail -f svcs -L vmapi |
Note that the logs for the VMAPI service are rotated, so one might need the directory where these files are being written in case older log files contain the information that we are looking for. Use the following command to find the directory where the VMAPI SMF service writes its files:
Analysing Logs
VMAPI uses Bunyan as its logging module. This allows users to find useful
debugging information in a very straightforward way since each log message
produced by Bunyan is a JSON object. VMAPI logs are structured so that they can
be filtered by component, API action, VM UUID and Server UUID when using the
bunyan command line utility.
The following are the components that describe each of the pieces in the VMAPI application and allow for more specific log filtering:
| Component Name | Description |
|---|---|
| api | API requests/responses |
| napi | NIC add/removal activity |
| cnapi | machine_load requests/responses |
| wfapi | WFAPI requests/responses (for queueing VM jobs) |
| moray | Moray database operations (read/write VM data) |
In order to filter a VMAPI log file by component we make use of Bunyan's '-c' option:
-c, --condition CONDITION
Run each log message through the condition and
only show those that return truish. E.g.:
-c 'this.pid == 123'
-c 'this.level == DEBUG'
-c 'this.msg.indexOf("boom") != -1'
'CONDITION' must be legal JS code. `this` holds
the log record. The TRACE, DEBUG, ... FATAL values
are defined to help with comparing `this.level`.
The 'this' variable inside a condition refers to the JSON object that was logged by Bunyan at any given point in time. If we wanted to see all messages that have been produced by the moray module we would issue the following command:
cat /var/svc/log/smartdc-site-vmapi\:default.log | bunyan -c "this.component === 'wfapi'"
...
[2015-11-23T19:28:00.755Z] INFO: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: Connected to Workflow API
[2015-11-23T19:28:00.873Z] DEBUG: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: provision-7.2.6 workflow exists
[2015-11-23T19:28:00.895Z] DEBUG: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: start-7.0.6 workflow exists
[2015-11-23T19:28:00.918Z] DEBUG: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: stop-7.0.7 workflow exists
[2015-11-23T19:28:00.929Z] DEBUG: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: kill-7.0.1 workflow exists
...
Bunyan still allows us to filter logs by level, so in case we were looking for an exception produced while starting up the workflow connection we can do the following:
cat /var/svc/log/smartdc-site-vmapi\:default.log | bunyan -c "this.component === 'wfapi'" -l error
...
[2015-11-23T19:27:07.588Z] ERROR: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: Ping failed
error: {
"code": "ENOTFOUND",
"errno": "ENOTFOUND",
"syscall": "getaddrinfo"
}
[2015-11-23T19:27:07.589Z] ERROR: vmapi/wfapi/14012 on e1c43507-9923-47d2-926f-2bba86963cac: Ping failed
error: {
"code": "ENOTFOUND",
"errno": "ENOTFOUND",
"syscall": "getaddrinfo"
}
...
Filtering specific VM activity
In addition to components, logs can be filtered by VM UUID and API action. This enables operators to better track all the API actions called for a VM of interest.
Again, by using the '-c' option in Bunyan, we use the vm_uuid attribute to find all log entries related to a single VM:
cat tmp/local.log | bunyan -c "this.vm_uuid === '0c81af15-d3b2-47f9-a75a-db7f16a65434'"
[2013-03-12T16:46:23.091Z] TRACE: vmapi/api/79487: GetVm start (vm_uuid=0c81af15-d3b2-47f9-a75a-db7f16a65434)
[2013-03-12T16:46:23.092Z] INFO: vmapi/api/79487: handled: 200 (vm_uuid=0c81af15-d3b2-47f9-a75a-db7f16a65434, audit=true, remoteAddress=127.0.0.1, remotePort=65466, latency=11, _audit=true, req.body="")
GET /vms/0c81af15-d3b2-47f9-a75a-db7f16a65434?owner_uuid=00000000-0000-0000-0000-000000000000 HTTP/1.1
accept: application/json
user-agent: restify/2.2.2 (x64-darwin; v8/3.11.10.25; OpenSSL/1.0.0f) node/0.8.18
accept-version: *
date: Tue, 12 Mar 2013 16:46:23 GMT
host: localhost:8080
connection: close
...
...
[2013-03-12T16:46:23.105Z] TRACE: vmapi/api/79487: DeleteVm start (vm_uuid=0c81af15-d3b2-47f9-a75a-db7f16a65434)
If there were both API and other log records for the VM in question. Going further we could filter this information by adding an additional component condition like:
cat tmp/local.log | bunyan -c "this.vm_uuid === '0c81af15-d3b2-47f9-a75a-db7f16a65434' && this.component === 'api'"
Now, if we wanted to focus our attention on specific API actions for a VM we can also filter logs by route name. The following is a list of API actions in VMAPI that can be filtered in the logs. The route name to be used for the Bunyan utility is just the lower case version of the API action that can be found on this documentation. Note that some routes accept a vm_uuid parameter when they are actions specific to a single VM and not a collection of VMs.
| API Action | Route Name | Accepts vm_uuid? |
|---|---|---|
| ListVms | listvms | No |
| CreateVm | createvm | No |
| GetVm | getvm | Yes |
| StartVm | startvm | Yes |
| StopVm | stopvm | Yes |
| RebootVm | rebootvm | Yes |
| ChangeVm | changevm | Yes |
| DeleteVm | deletevm | Yes |
| AddNics | addnics | Yes |
| RemoveNics | removenics | Yes |
| CreateSnapshot | createsnapshot | Yes |
| RollbackSnapshot | rollbacksnapshot | Yes |
| DeleteSnapshot | deletesnapshot | Yes |
| ListMetadata | listmetadata | Yes |
| GetMetadata | getmetadata | Yes |
| AddMetadata | addmetadata | Yes |
| SetMetadata | setmetadata | Yes |
| DeleteMetadata | deletemetadata | Yes |
| DeleteAllMetadata | deleteallmetadata | Yes |
As an example, we can run this command to get the logs of all the GetVm calls to VMAPI:
cat tmp/local.log | bunyan -c "this.route === 'getvm'"
[2013-03-13T21:12:00.788Z] INFO: vmapi/api/91013 on Andres-Rodriguezs-MacBook-Pro.local: handled: 200 (vm_uuid=00b70fd9-731d-4c9c-bf9a-7f859bf6c3cf, route=getvm, audit=true, remoteAddress=127.0.0.1, remotePort=61123, latency=21, _audit=true, req.body="")
GET /vms/00b70fd9-731d-4c9c-bf9a-7f859bf6c3cf HTTP/1.1
user-agent: curl/7.27.0
host: 0.0.0.0:8080
accept: */*
--
HTTP/1.1 200 OK
content-type: application/json
content-length: 7842
content-md5: Z+XMCqoiyRTX0Oy88MJA9Q==
...
...
Use Cases and Examples
The following examples make use of the json tool (https://github.com/trentm/json)
as a very convenient way to "pretty print" the output produced by VMAPI. In addition,
we assume VMAPI is being queried from an SDC Compute Node, thus implying the availability
of the sdc-vmapi command.
Counting VMs
Use the HEAD HTTP method to get the number of VMs that match a specific criteria. If HEAD is used, VMAPI won't return any objects as specified by the HTTP standard. The number of VMs that match the query will be available as the x-joyent-resource-count response header
Count all VMs:
sdc-vmapi /vms -X HEAD
HTTP/1.1 200 OK
x-joyent-resource-count: 21
Connection: close
Date: Tue, 26 Mar 2013 09:54:21 GMT
Count all 128M Vms:
sdc-vmapi /vms -X HEAD
HTTP/1.1 200 OK
x-joyent-resource-count: 8
Connection: close
Date: Tue, 26 Mar 2013 09:54:21 GMT
Query String vs LDAP Search Query
Use a query string when you need to match specific values for VM attributes. Examples of this are "ram=128" or "alias=my-vm". This is the classic behavior for passing data values to an HTTP API and it allows client UIs to have tables that display data that can be filtered by any given attribute.
VMAPI also allows clients to pass an LDAP search query that can be used when just the equality operator is not enough. As an example, one might neeed to get the UUIDs of all machines that have less than or equal to 256M of RAM:
sdc-vmapi "/vms?query=(ram<=256)" | json -H -a uuid ram
6472ed54-0783-4b2a-b052-ed2991284314 256
c6de897f-c5af-4dd2-9659-c1893c95ca31 128
20aaee31-7f94-4a5a-b724-48a5b42d4066 128
dfcbc0d4-b423-4f13-9583-d6e87aae5801 256
cc57ab8b-1f50-4779-828a-2a0109aed360 256
d848d326-2502-4200-ace8-8830259f4ef1 128
ae21f197-a005-476f-9423-b5d63279686f 128
b95db5f7-8b02-472c-a6cc-719bc7566b2a 128
47c36d58-b5b8-4e4d-a505-080feeea3386 128
a564b236-b158-4231-b060-9a24ba0c257e 128
720426ef-82de-4289-9813-44f0badf0b06 128
Or we can also find all the machines created in a period of time:
sdc-vmapi "/vms?query=(%26(create_timestamp<=1364329137198)(create_timestamp>=1354321137198))" | json -H -a alias
assets0
sapi0
zookeeper0
manatee0
moray0
redis0
ufds0
workflow0
amon0
napi0
rabbitmq0
imgapi0
cnapi0
dhcpd0
dapi0
fwapi0
vmapi0
ca0
adminui0
TODO: modifying vms
Debugging Common Issues
VMAPI has no VMs, or VMs are not being updated
This is almost always an issue with the vm-agent, since VMAPI should always have VMs. Even if VMs are not created from VMAPI they are discovered by the vm-agent.
What To Do?
-
Make sure the vm-agents on your CNs are not having problem to process data. Check the vm-agent service logs on the CNs and then check the VMAPI service log file in the VMAPI zone and see if there are any errors being logged in it.
-
If vm-agent is having problems, it is recommended that you take a gcore of the vm-agent node process and then restart the vm-agent service.
TODO: job failed
TODO: provision failed
TODO: vm destroyed but still there
Changelog
Changes post 2014-07-31
2014-07-31
- Added search predicate support to GET /vms
2014-04-28
- Added wildcard ('*') support for
fieldsquery parameter
2014-04-17
- Added support for VM Role Tags
- Added support for
fieldsquery parameter in ListVms and GetVm
2013-11-29
- Added wfapi to services property in /ping response
2013-04-30
- Property resolvers added to VM response object
2013-04-29
- Added reprovision action to POST /vms/:uuid
2013-03-11
- Added status to /ping response
2013-02-04
- Added process pid to /ping response
2012-12-18
- Added support for delete_snapshot
- Updated endpoints for create_snapshot and rollback_snapshot. They are now part of UpdateVm
2012-12-13
- Added support add_nics and remove_nics on UpdateVm
2012-11-30
- Added support for advanced search on ListVms (LDAP search filters)
2012-11-21
- New /ping endpoint to report on service status
2012-11-19
- VM response object now returns the snapshot property for vms
2012-11-08
- updateVm endpoint now takes new_owner_uuid instead of owner_uuid to indicate the new owner of the VM
2012-10-18
- Added snapshot and rollback support
2012-09-11
- Updating VM metadata with an updateVm operation replaces existing metadata. It is no longer an append
2012-08-29
- Adds an error response when trying to delete unallocated VMs
2012-08-10
- Added new format for networks parameter in CreateVm. See deprecation note
2012-08-08
- Added /statuses
2012-06-12
- Added /jobs and /vms/:uuid/jobs
2012-06-11
- dataset_uuid is deprecated. image_uuid should now be used
- Added SetMetadata (PUT /vms/:uuid/:metadata)
2012-06-07
- Reverted dataset_url as a allowed parameter
- Can now pass nics as a parameter. Will override networks
2012-06-06
- Brand 'joyent-minimal' is now supported
2012-06-05
- When creating a new VM you can now pass dataset_url
- When creating a new VM you can now pass server_uuid
2012-06-04
- VM actions now return a Job Response Object
2012-06-01
- VM API endpoints are now named /vms instead of /machines
- /machines is still aliased but deprecated
2012-05-28
- Search VMs by tags
2012-05-23
- 'networks' is a required parameter for POST /vms
- Add sync=true parameter to GET /vms/uuid
2012-05-22
- Add sync=true parameter to DELETE /vms/uuid