Using the API

ZStack ZSphere provides RESTful APIs. You can use any HTTP-capable programming language or tool to access API endpoints, authenticate requests, query resources, and perform resource operations.

This chapter describes the general rules for API requests, authentication, responses and error handling, asynchronous APIs, query APIs, ZQL, and batch API responses. For request parameters and response fields of a specific API, see the corresponding API topic.

Getting Started

Calling a ZStack ZSphere API generally involves the following steps:

  1. Determine the management node address, API endpoint, and HTTP method.
  2. Obtain a session UUID through a login API, or prepare an AccessKey.
  3. Pass URL, query string, or HTTP body parameters as defined by the API topic.
  4. Send the request and process a synchronous result, asynchronous polling location, or error according to the HTTP status code.
  5. If session authentication is used, call LogOut when the session is no longer needed.
GET http://MANAGEMENT_NODE_IP:8080/zstack/v1/vm-instances?limit=10
Authorization: OAuth SESSION_UUID

A successful query returns HTTP 200 and a resource list in the response body.

Making API Requests

Construct each request by using the endpoint, HTTP method, parameter locations, and HTTP headers defined in the corresponding API topic.

API Endpoints and Request URLs

A REST API URL consists of the protocol, management node address, port, API context path, and resource path:

http://MANAGEMENT_NODE_IP:8080/zstack/v1/RESOURCE_PATH

For example:

GET http://MANAGEMENT_NODE_IP:8080/zstack/v1/vm-instances
Note: Use the protocol, management node address, and port of your environment. Use the resource path documented in the corresponding API topic.

HTTP Methods and API Operations

MethodPurpose
GETQueries or retrieves resources. Query and Get APIs use this method.
POSTCreates a resource.
PUTUpdates a resource or performs an RPC-like operation such as starting or stopping a VM. RPC-like operations usually use the actions subpath.
DELETEDeletes a resource.

For example:

PUT zstack/v1/vm-instances/VM_UUID/actions

{"startVmInstance": {}}

For each API, use the HTTP method, URL, and body field defined in its API topic.

Passing Request Parameters

Parameters can be passed in URLs, query strings, and HTTP bodies, as defined by each API.

URL Parameters

A resource UUID is usually encoded in the URL path:

GET zstack/v1/vm-instances/VM_UUID

Query String Parameters

GET requests pass query conditions, pagination settings, and field selections in a query string. Separate parameters with & and URL-encode parameter values.

GET zstack/v1/vm-instances?q=state=Running&limit=20

HTTP Body Parameters

POST and PUT requests usually pass parameters in a JSON body. Use the top-level field and parameter structure defined by the API.

{"params": {"name": "vm1", "description": "example"}}

HTTP Headers

HeaderDescription
AuthorizationFor session authentication, use OAuth SESSION_UUID. For AccessKey authentication, use ZStack ACCESS_KEY_ID:SIGNATURE.
DateRequest time used for AccessKey authentication. It must be identical to the time used to calculate the signature.
X-Job-UUIDSpecifies the UUID of an asynchronous API job. Use a UUID v4 string without hyphens. If omitted, the server generates one.
X-Web-HookSpecifies the callback URL that receives an asynchronous API result.
X-Job-SuccessIn a webhook callback, indicates whether the asynchronous API succeeded.

Authentication

Except for APIs that do not require authentication, such as login APIs, authenticate requests with a session or an AccessKey.

Session Authentication

After LogInByAccount or another login API succeeds, obtain the session UUID from the returned session inventory and pass it in subsequent requests:

Authorization: OAuth SESSION_UUID
Note: Separate OAuth and the session UUID with one space.

A session has an expiration time. Call LogOut when the session is no longer needed.

AccessKey Authentication

An AccessKey consists of an AccessKey ID and an AccessKey Secret. The caller uses the AccessKey Secret to sign request information, and the server verifies the caller based on the signature. The AccessKey Secret is returned only when the AccessKey is created.

Warning: Do not store a real AccessKey Secret in source code, logs, command history, or public documents. All values in the examples are placeholders.

Using an AccessKey with an SDK

Java and Python SDK action objects provide accessKeyId and accessKeySecret.

Java SDK:

QueryVmInstanceAction action = new QueryVmInstanceAction();
action.limit = 1;
action.accessKeyId = "ACCESS_KEY_ID";
action.accessKeySecret = "ACCESS_KEY_SECRET";
QueryVmInstanceAction.Result result = action.call();

Python SDK:

action = QueryVmInstanceAction()
action.conditions = []
action.limit = 1
action.accessKeyId = 'ACCESS_KEY_ID'
action.accessKeySecret = 'ACCESS_KEY_SECRET'
result = action.call()

The SDK generates the Date and Authorization headers. Do not set both a session and an AccessKey on the same action.

Using an AccessKey with the REST API

When directly calling the REST API, generate the signature as follows:

  1. Generate the request time DATE. It must be identical to the value used for signature calculation.
  2. Construct the string to sign:
    HTTP_METHOD + "\n" + DATE + "\n" + API_URI

    API_URI starts with /v1 and excludes the protocol, management node address, port, context path, and query string. For example: /v1/vm-instances.

  3. Use the AccessKey Secret as the key, calculate HMAC-SHA1 for the string, and Base64-encode the digest to obtain SIGNATURE.
  4. Set both headers:
    Date: DATE
    Authorization: ZStack ACCESS_KEY_ID:SIGNATURE
GET http://MANAGEMENT_NODE_IP:8080/zstack/v1/vm-instances?limit=1
Date: DATE
Authorization: ZStack ACCESS_KEY_ID:SIGNATURE
Note: Recalculate the signature whenever the HTTP method, Date, or API URI changes. Do not insert additional spaces in the signed fields.

API Responses and Error Handling

Check both the HTTP status code and the response body. An accepted HTTP request does not necessarily mean that an asynchronous job or every item in a batch operation succeeded.

API Responses

A completed synchronous API usually returns HTTP 200 and a JSON body. Resource APIs commonly return one resource in inventory. Query APIs commonly return a list in inventories and can also return total.

An accepted asynchronous API returns HTTP 202. Its body contains a polling URL in location and a timeout in apiTimeout. Poll the URL or use a webhook to obtain the final result.

For the exact response structure, see the response example and field table in the corresponding API topic.

HTTP Status Codes

Status codeDescription
200The API succeeded. The response body contains the result.
202The asynchronous API request was accepted. Poll for the result or wait for a webhook callback.
400A required parameter is missing or a parameter is invalid. See the response body.
404The URL does not exist. For a polling URL, it can indicate that the URL expired.
405The HTTP method does not match the API definition.
500An internal error occurred in the RESTful API service.
503The operation performed by the API failed. See the response body for details.

Handling API Errors

When a request fails, the error object in the response body describes the error. Process at least the following fields:

  • code: identifies the error type.
  • description: summarizes the error.
  • details: provides details specific to the failure.

An error can also contain cause, causes, elaboration, or other extended fields. For an asynchronous API, check its final polling or webhook result. For a batch API, check each item result.

Using Asynchronous APIs

An asynchronous API first accepts a request and then returns its final result through polling or a webhook. Save the job identifier and use the final result to determine whether the operation succeeded.

Synchronous and Asynchronous APIs

All GET APIs are synchronous and return the API result directly. Except for login APIs, APIs that do not use GET are generally asynchronous.

An accepted asynchronous request returns HTTP 202:

Status Code: 202

{"apiTimeout": 1800000,
 "location": "http://MANAGEMENT_NODE_IP:8080/zstack/v1/api-jobs/JOB_UUID"}

apiTimeout is in milliseconds, and location is the URL used to query the final result.

Polling for API Results

Periodically send a GET request to the location returned by the asynchronous API:

GET POLLING_LOCATION
Authorization: OAuth SESSION_UUID
  • 202: The API is still processing. Continue polling.
  • 200: The API succeeded. The body contains the final result.
  • 503: The API failed. The body contains error information.
  • 404: The polling URL is invalid or expired.

Set the polling interval and total wait time according to apiTimeout and the caller's timeout policy.

Using Webhooks

A webhook pushes the final result of an asynchronous API to the caller. Specify these headers in the asynchronous request:

X-Job-UUID: JOB_UUID
X-Web-Hook: https://CALLBACK_ENDPOINT/api-result

The server still returns HTTP 202 and a polling URL. When the job completes, it sends a POST request to the callback URL:

POST https://CALLBACK_ENDPOINT/api-result
X-Job-Success: true
X-Job-UUID: JOB_UUID

X-Job-Success indicates whether the API succeeded. X-Job-UUID correlates the callback with the original request.

Using Query APIs

Query APIs use GET to query resources and support combined conditions, cross-resource queries, sorting, field selection, and pagination. If no condition is specified, resources are returned up to the limit.

ParameterTypeDescription
qListA query condition. It can be specified multiple times; multiple conditions have an AND relationship.
limitIntegerMaximum number of records to return. The default is 1000.
startIntegerStarting record position. Use it with limit for pagination.
countBooleanIf true, returns only the number of matching records.
groupByStringGroups results by a field.
replyWithCountBooleanIf true, returns the total number of matching records with the resource list.
sortStringUses +field for ascending order or -field for descending order.
fieldsListSpecifies native resource fields to return.

Specifying Query Conditions

A condition consists of a field, operator, and value without spaces between them:

GET zstack/v1/vm-instances?q=name=vm1&q=state=Running

Multiple q parameters have an AND relationship.

OperatorMeaningExample
=Equal tostate=Running
!=Not equal tostate!=Stopped
>, <, >=, <=Range comparisoncpuNum>=8
?=In a setuuid?=UUID_1,UUID_2
!?=Not in a setname!?=vm1,vm2
~=Fuzzy string match. % matches multiple characters and _ matches one.name~=web%
!~=Negative fuzzy matchname!~=test%
=nullField is nullhostUuid=null
!=nullField is not nullhostUuid!=null
Note: URL-encode special characters in the query string. Use CLI completion and the resource model to determine queryable fields.

Querying Across Resources

Use a period to connect a resource relationship and field. For example, query a VM by NIC IP address:

GET zstack/v1/vm-instances?q=vmNics.ip=192.168.10.100

Query VMs running on a host:

GET zstack/v1/vm-instances?q=host.managementIp=192.168.10.10

Relationships can continue to another level, such as vmNics.eip.ip. Use Tab completion for a Query API in the CLI to view supported relationships and fields.

Note: Because relationships can form loops, use the shortest relationship path that expresses the query target.

Sorting Results and Selecting Fields

Use sort to sort results. A leading plus sign indicates ascending order and a leading minus sign indicates descending order:

GET zstack/v1/vm-instances?sort=+name
GET zstack/v1/vm-instances?sort=-createDate

Use one or more fields parameters to select returned fields:

GET zstack/v1/vm-instances?fields=uuid&fields=name
Note: Only native fields of the queried resource can be selected. User tags, system tags, and cross-resource fields cannot be used as fields values.

Paginating Query Results

Use start, limit, and replyWithCount together for pagination:

  • start: position of the first record on the page.
  • limit: maximum records on the page.
  • replyWithCount=true: returns the total number of matching records.
GET zstack/v1/vm-instances?start=0&limit=100&replyWithCount=true

If total is 1000, set start to 100 for the next page and keep the same limit and conditions. Specify sort when stable ordering is required.

Finding Queryable Fields

Use CLI completion to view queryable fields and relationships supported by the current environment.

  1. Run zstack-cli.
  2. Enter a Query API name followed by a space, such as QueryVmInstance .
  3. Press Tab to view native fields, common query parameters, and relationships.
  4. Enter a relationship followed by a period and press Tab again, such as QueryVmInstance vmNics..

__systemTag__ and __userTag__ are special query conditions. Other fields without a period are generally native resource fields. The completion results of the current CLI version determine whether a query path is supported.

ZQL

ZQL (ZStack Query Language) is a dedicated language provided by ZStack ZSphere for querying cloud platform resources and services. It provides SQL-like query syntax and applies to scenarios that require complex queries.

ZQL Statement Structure

ZQL provides query statements that start with the three keywords query, count, and sum. Each statement consists of a query keyword, query fields, and clauses. The clauses supported by the query statements that start with these three keywords are slightly different. The statement structures are as follows:
  • Structure of a query statement that starts with the query keyword:
    query queryTargetWithFunction (WHERE condition+)? restrictBy? returnWith? groupBy? orderBy? limit? offset? filterBy? namedAs?
  • Structure of a query statement that starts with the count keyword:
    count queryTargetWithFunction (WHERE condition+)? restrictBy? groupBy? orderBy? limit? offset? namedAs?
  • Structure of a query statement that starts with the sum keyword:
    sum queryTarget by sumByValue (WHERE condition+)? orderBy? limit? offset? namedAs?
  • Note: ? indicates that the corresponding clause is optional.

ZQL Syntax Description

The functions and meanings of each component in a ZQL statement are as follows:
  • Query keywords:
    • query: Queries and returns the inventory of resources, similar to select * in SQL. For example, query vminstance is similar to select * from VmInstanceVO.
    • count: Queries and returns the number of resources that meet the query conditions, similar to select count(*) in SQL. For example, count vminstance is similar to select count(*) from VmInstanceVO.
    • sum: Queries and returns the sum of the specified field, similar to select sum(inv.cpuNum) in SQL. For example, sum instanceoffering.cpuNum is similar to select sum(cpuNum) from InstanceOfferingVO.
  • Query fields:
    • querytarget: The target resource information to query. The resource name is formed by removing the VO suffix from the resource name and converting it to lowercase. For example, if the resource is VmInstanceVO, the resource name of querytarget is vminstance. querytarget supports querying only certain fields of a resource. For example, query vminstance.uuid,name queries the virtual machine UUID and name. This statement is similar to select uuid,name from VmInstanceVO in SQL.
    • function: The function that processes resource fields. querytarget supports specifying fields directly and specifying fields processed by functions. Currently, the query and count keywords support function processing, while subqueries do not support function processing. The function supported by ZStack ZSphere is distinct. For example, query distinct(vminstance.name) queries and returns distinct virtual machine names. This statement is similar to select distinct name from VmInstanceVO or select distinct(name) from VmInstanceVO.
  • Query clauses:
    • where: Similar to the where clause in SQL, used to specify query conditions. If the query condition value is a string, enclose it in single quotation marks.
      • Similar to Query APIs, the query conditions specified in the where clause can be fields of the current resource or cross-table join query conditions. For example:
        • In query vminstance where name='webvm', the name field is a field of vminstance itself.
        • In query vminstance where vmNics.ip='192.168.0.100', vmNics.ip is a field after automatic join query with the VmNicVO table.
      • The where clause supports AND/OR logic and supports logical nesting with parentheses. For example:
        query vminstance where (name = 'webvm' or cpuNum > 10) and description is not null
    • sub query: The query conditions specified in the where clause support subqueries (sub query), for example:
      query vminstance where hostUuid in (query host.uuid where state = 'Disconnected') and state = 'Running'
      Note:
      • The querytarget in a sub query clause supports selecting only one field, such as host.uuid. An error is reported if no field or multiple fields are selected. The where clause in a sub query is the same as the where clause in a common query statement.
      • A sub query does not support restrict by or return with clauses, nor does it support the limit, order by, or offset keywords.
    • restrict by: Used to solve resource association query issues. For example, query eip restrict by (zone.uuid = '28818693f3924d92af2b19b2407317ff') queries EIPs in the zone whose UUID is 28818693f3924d92af2b19b2407317ff. Because EIP resources do not contain fields associated with Zone, you can specify the restrict by clause for the query.
      • The condition name specified by restrict by has the same field query format as that in querytarget. Both use resource name.field name, such as zone.uuid.
      • The conditions in the restrict by clause support only AND logic. For example:
        restrict by (zone.uuid = '28818693f3924d92af2b19b2407317ff', zone.name like '%east-%')
    • return with: Used to return attached data. Currently, two types of attached data are supported: total and zwatch.
      • total is used to specify the number of data records that meet the query conditions. For example, for the query vminstance where cpuNum > 8 return with (total) statement, the query result returns the total field value.
      • zwatch is used to specify that monitoring data that meets the query conditions is returned. After the zwatch clause is specified in the return with clause, the zwatch query is executed together with the database query. The working mechanism is: l
        1. Execute the database query conditions in the where clause first to obtain data that meets the query conditions.
        2. Inject the data returned by the query in the where clause as input conditions into the zwatch query.
        For example, in the following ZQL statement, the data query is executed first to find VMs that meet the cpuNum > 8 condition, and then the UUIDs of the VMs are merged into a zwatch label and injected into the subsequent zwatch query conditions:
        query vminstance where cpuNum > 8 return with (zwatch{metricName='CPUUsedUtilization',offsetAheadOfCurrentTime=3600,period=10,labels='CPUNum=10',labels='CPUNum=100', functions=limit(limit=10), functions=top(num=2)})
        The zwatch clause starts with the zwatch keyword, and query conditions are placed in braces {}. The query conditions are the fields of the GetMetricData API. The parameters do not include the namespace field. This field is determined by the resource specified by querytarget. For example, vminstance represents ZStack/VM.
        private String metricName;
         private Long startTime;
         private Long endTime;
         private Long offsetAheadOfCurrentTime;
         private Integer period;
         private List<String> labels;
         private List<String> functions;
        • The zwatch clause usually passes the primary key of the object after query as a query parameter to the subsequent GetMetricData query. To use a non-primary-key field for a zwatch query, add the feildIndex parameter to the corresponding clause. fieldIndex=0 indicates that the first field after query is used. For example:
          query faulttolerancevmgroup.primaryVmInstanceUuid return with (zwatch{resultName='cpuAverageUsedUtilization',metricName='CPUAverageUsedUtilization',offsetAheadOfCurrentTime=0,period=10,fieldIndex=0})
        • String parameters must be marked with single quotation marks. For the labels and functions parameters of the list type, use multiple inputs. The order in the list is determined by the order in which the parameters appear, and parameters are separated by commas (,). For example:
          labels='CPUNum=10', labels='CPUNum=8'
        • The number of monitoring data records returned by the zwatch clause may be different from the number of database records that meet the where clause. For example, in the following ZQL statement, there may be 100 VMs that meet cpuNum > 8, but the zwatch clause uses the top(num=2) function, so only two monitoring data records are returned:
          query vminstance.name where cpuNum > 8 return with (zwatch{metricName='CPUUsedUtilization',offsetAheadOfCurrentTime=3600,period=10,labels='CPUNum=10',labels='CPUNum=100',functions=limit(limit=10), functions=top(num=2)})
        • If only monitoring data is of concern, the querytarget of ZQL should specify a field rather than the resource itself. For example, in the following ZQL statement, the returned data contains only the VM name and monitoring data, which greatly reduces the amount of data transmitted by the API:
          query vminstance.name where cpuNum > 8 return with (zwatch{metricName='CPUUsedUtilization',offsetAheadOfCurrentTime=3600,period=10,labels='CPUNum=10',labels='CPUNum=100',functions=limit(limit=10), functions=top(num=2)})
        The return with clause supports multiple zwatch clauses. When multiple clauses are used, specify the name of the returned data in the reurnWith object of the ZQL returned object by using resultName. For example:
        query vminstance.name where cpuNum > 8 return with (zwatch{resultName='zwatch1',metricName='CPUUsedUtilization',offsetAheadOfCurrentTime=3600,period=10,labels='CPUNum=10',labels='CPUNum=100', functions=limit(limit=10), functions=top(num=2)}, zwatch{resultName='zwatch2',metricName='CPUUsedUtilization',offsetAheadOfCurrentTime=3600,period=10,labels='CPUNum=10',labels='CPUNum=100', functions=limit(limit=10), functions=top(num=2)})
        In this example, two clauses specify resultName='zwatch1' and resultName='zwatch2' respectively, and the corresponding return values are named zwtach1 and zwatch2:
        "returnWith": {
        		"zwatch1": [{
        			"value": 105.0,
        			"time": 7.0,
        			"labels": {
        				"VMUuid": "bdbc971d1de74a91b8f3f0c7c9f5babe"
        			}
        		}, {
        			"value": 101.0,
        			"time": 1.0,
        			"labels": {
        				"VMUuid": "bdbc971d1de74a91b8f3f0c7c9f5babe"
        			}
        		}],
        		"zwatch2": [{
        			"value": 105.0,
        			"time": 7.0,
        			"labels": {
        				"VMUuid": "bdbc971d1de74a91b8f3f0c7c9f5babe"
        			}
        		}, {
        			"value": 101.0,
        			"time": 1.0,
        			"labels": {
        				"VMUuid": "bdbc971d1de74a91b8f3f0c7c9f5babe"
        			}
        		}]
        	}
    • group by: Similar to the group by clause in SQL, used to group results by resource fields. The group by clause supports only query and count queries. The by field of a sum query has the same meaning as the group by field. For example:
      • query vminstance group by name is similar to select * from VmInstanceVO group by name in SQL.
      • count vminstance where cpuNum > 8 group by name,memorySize is similar to select count(*) where cpuNum in SQL.
      The result format returned by query group by is the same as that returned by a common query. For example, the return result of the query vminstance.name return with (total) group by zoneUuid statement is:
      {
       "results": [
       {
       "inventories": [
       {
       "name": "win2016-new"
       }
       ],
       "total": 24
       }
       ],
       "success": true
      }
      Note: The total field value is different from the number after group by.
      The return result of count group by is different from that of a common count. For example, the return result of the count vminstance group by imageUuid order by groupCount asc statement is:
      {
       "results": [
       {
       "inventoryCounts": [
       [
       {
       "imageUuid": "20d8593c94934b4596af7109a1609811"
       },
       1
       ],
       [
       {
       "imageUuid": "4eabdabb64844f8eb2ae5d1aa2c44d7a"
       },
       2
       ]
       ],
       "total": 3
       }
       ],
       "success": true
      }
      Here, inventoryCounts is an ordered map type with complex keys, namely objects of fields specified by group by. It is converted to this jsonArray format through json.
      If the count vminstance group by imageUuid offset 2 statement is executed, the return result is:
      {
       "results": [
       {
       "total": 3
       }
       ],
       "success": true
      }
      In this result:
      • Because no query result exists under the offset condition, the inventoryCounts field is null.
      • The total field is still the total result before grouping.
    • order by: Similar to the order by clause in SQL, used to sort returned results by resource fields. For example:
      query vminstance orderby cpuNum asc
      or
      query vminstance orderby cpuNum desc
      Sorting results after count group by is supported. For example:
      count vminstance groupby imageUuid orderby groupCount asc
      Sorting results after sum is also supported. For example:
      sum VolumeSnapshot.size by volumeUuid orderby size asc
    • limit: Similar to the limit clause in SQL, used to limit the number of returned data records. For example:
      query vminstance limit 100
    • offset: Similar to the offset clause in SQL, used together with the limit clause to implement pagination. For example:
      query vminstance limit 100 offset 10
If you use the sum keyword for summation queries, you can implement a summation function similar to the SQL statement select sum(xxx) ... group by yyy. For example, the following query statement sums the cpuNum and memorySize fields of vminstance respectively, and groups the data by the uuid field.
sum vminstance.cpuNum,memorySize by uuid where cpuNum >0
This statement is equivalent to the following SQL statement:
select sum(vm.cpuNum),sum(vm.memorySize) from VmInstanceVO vm where vm.cpuNum > 0
The return result is:
{
	"results": [{
		"inventories": [
			["7dba128454014abc8a69e739f1c4e2ad", 2, 536870912],
			["e889cbf61cf6434f875e80e3b1c5a92d", 4, 8589934592]
		]
	}]
}
Each element in the return result is an array: the first element is always the group by field specified by the by keyword, which can be used to identify the resource corresponding to the subsequent summation values. The second element and later elements are summation results, and their order is the same as the field order after the sum keyword. For example, 2 corresponds to vm.cpuNum, and 536870912 corresponds to vm.memorySize.
ZQL provides the query comparison operators has and not has, which apply to cascaded resource query scenarios:
  • Because cascaded resources have a one-to-many characteristic, you can use has to query results that have multiple cascaded resources at the same time. For example, query virtual machines with HA paused:
    query vminstance where __systemTag__ has ('ha', 'inhibitHA')
    Note: has currently supports only definite values and does not support subqueries.
  • not has can be used to query results that do not have a certain cascaded resource. For example, query virtual machines that do not use ipv4:
    query vminstance where vmNics.ipVersion nothas ('4')
ZQL supports specifying multiple ZQL statements in one query to implement batch queries. Multiple ZQL statements are separated by semicolons (;).
  • The named as clause is supported to name ZQL statements, making it easy to view the execution result corresponding to each ZQL statement. To use the named as clause, add a string after the named as keywords as the name of the ZQL statement.
    • The name of a ZQL statement must be globally unique. Otherwise, a later ZQL statement overwrites the result of an earlier statement with the same name.
    • The named as clause is optional. When it is omitted, the returned result does not contain the name field, and you can identify its correspondence with the ZQL statement only by the order of results in the array.
For example:
query host named as 'host';
query zone return with (total) named as 'zone'
The return result format is as follows:
{
	"results": [{
		"inventories": [{
			"username": "root",
			"password": "password",
			"sshPort": 22,
			"zoneUuid": "1a29060d81724b6083caaf530b4c6ab5",
			"name": "kvm",
			"uuid": "f1e112cf4f3c4bbd939fdf18f72ac5e8",
			"clusterUuid": "324fece70aa848ed917b9134ef7072c1",
			"managementIp": "localhost",
			"hypervisorType": "KVM",
			"state": "Enabled",
			"status": "Connected",
			"totalCpuCapacity": 320,
			"availableCpuCapacity": 314,
			"cpuSockets": 2,
			"totalMemoryCapacity": 34359738368,
			"availableMemoryCapacity": 25232932864,
			"cpuNum": 32,
			"createDate": "Jul 10, 2018 5:32:56 PM",
			"lastOpDate": "Jul 10, 2018 5:32:58 PM"
		}],
		"name": "host"
	}, {
		"inventories": [{
			"uuid": "1a29060d81724b6083caaf530b4c6ab5",
			"name": "zone",
			"description": "test",
			"state": "Enabled",
			"type": "zstack",
			"createDate": "Jul 10, 2018 5:32:54 PM",
			"lastOpDate": "Jul 10, 2018 5:32:54 PM"
		}],
		"total": 1,
		"name": "zone"
	}]
}
ZStack ZSphere supports embedding API results into ZQL statements. The API is not limited to Get APIs. Query APIs can also be embedded, but the request must return synchronously. The following examples are given for different conditions or parameters:
  • Condition is in:
    query vminstance.hostUuid where hostUuid in getapi(api='GetVmStartingCandidateClustersHosts', output='hosts.uuid', uuid='${vm1.uuid}') limit 1
  • Condition is =:
    query vminstance.hostUuid where hostUuid = getapi(api='GetVmStartingCandidateClustersHosts', output='hosts.uuid', uuid='${vm1.uuid}') limit 1
  • Parameter is boolean:
    query vminstance.hostUuid where hostUuid ingetapi(api='GetCandidateMiniHosts', output='hosts.hostname', local=true, configure=false) limit 1
  • Parameter is list:
    query vminstance.hostUuid where hostUuid ingetapi(api='GetPciDeviceCandidatesForNewCreateVm',output='inventories.uuid', clusterUuids=list('${cluster.uuid}','${vm1.uuid}')) limit 1

Use Curl to Call a ZQL Query

Curl sample:
curl http://localhost:8080/zstack/v1/zql?zql=yourZQL -X GET -H 'Connection:close' -H 'Content-Type:application/json' -H 'Authorization:OAuth SesionID'
In this sample:
  • yourZQL: The ZQL statement used for the query. It must be encoded by using a URL.
  • SessionID: The Sesion ID required for calling the ZQL statement, such as 376c223518e347bcbeca40d2c7c515b9.
ZQL statement sample:
query vminstance where name='webvm' and vmnics.ip='192.168.0.10' or (vmnics.eip = '172.20.100.100' and (cpuNum >= 8 or clusterUuid in ('fe13b725c80e45709f0414c266a80239','73ca1ca7603d454f8fa7f3bb57097f80')))
restrict by (zone.uuid != 'fec2889fef2d49b1967c7e39025f4eb4') return with (total, zwatch{metricName='CPUUsedUtilization',offsetAheadOfCurrentTime=3600,period=10,labels='CPUNum=10', functions=limit(limit=10), functions=top(num=2)}) order by cpuNum desc limit 100 offset 10
ZQL statement return result:
{
 "results": [
 {
 "inventories": [
 {
 "allVolumes": [
 {
 "actualSize": 10775166976,
 "createDate": "Nov 11, 2021 2:03:47 PM",
 "description": "Root volume for VM[uuid:0d62f2c34390464d9bfd166c270a261a]",
 "deviceId": 0,
 "format": "qcow2",
 "installPath": "sharedblock://e2402ed34190477cb9b4ae3a2cc58db6/fa75061b0fee4bc99bfba51d5191fc88",
 "isShareable": false,
 "lastOpDate": "Nov 16, 2021 11:42:25 PM",
 "name": "ROOT-for-22222-2",
 "primaryStorageUuid": "e2402ed34190477cb9b4ae3a2cc58db6",
 "rootImageUuid": "b5876869ad3d464f8915f8a3597b5688",
 "size": 42949672960,
 "state": "Enabled",
 "status": "Ready",
 "type": "Root",
 "uuid": "fa75061b0fee4bc99bfba51d5191fc88",
 "vmInstanceUuid": "0d62f2c34390464d9bfd166c270a261a"
 }
 ],
 "allocatorStrategy": "LeastVmPreferredHostAllocatorStrategy",
 "architecture": "x86_64",
 "clusterUuid": "110fcbd2f0c344fd9c33604bc51b8316",
 "cpuNum": 16,
 "cpuSpeed": 0,
 "createDate": "Nov 11, 2021 2:03:47 PM",
 "defaultL3NetworkUuid": "776aa4f32c704acba90811ca071919ed",
 "description": "",
 "guestOsType": "Windows",
 "hypervisorType": "KVM",
 "imageUuid": "b5876869ad3d464f8915f8a3597b5688",
 "instanceOfferingUuid": "05fe32439048403f9577eed860ca9644",
 "lastHostUuid": "2926b5fce9384180a08d3cd46841e35c",
 "lastOpDate": "Nov 16, 2021 11:42:25 PM",
 "memorySize": 17179869184,
 "name": "22222-2",
 "platform": "Windows",
 "rootVolumeUuid": "fa75061b0fee4bc99bfba51d5191fc88",
 "state": "Stopped",
 "type": "UserVm",
 "uuid": "0d62f2c34390464d9bfd166c270a261a",
 "vmCdRoms": [
 {
 "createDate": "Nov 11, 2021 2:03:47 PM",
 "deviceId": 0,
 "lastOpDate": "Nov 11, 2021 2:03:47 PM",
 "name": "vm-0d62f2c34390464d9bfd166c270a261a-cdRom",
 "uuid": "7bcf07ee5aba41399db62ef43ac9299c",
 "vmInstanceUuid": "0d62f2c34390464d9bfd166c270a261a"
 }
 ],
 "vmNics": [
 {
 "createDate": "Nov 11, 2021 2:03:47 PM",
 "deviceId": 0,
 "driverType": "e1000",
 "gateway": "172.25.0.1",
 "hypervisorType": "KVM",
 "internalName": "vnic8001.0",
 "ip": "172.25.201.6",
 "l3NetworkUuid": "776aa4f32c704acba90811ca071919ed",
 "lastOpDate": "Nov 11, 2021 2:03:47 PM",
 "mac": "fa:a7:65:4a:5b:00",
 "netmask": "255.255.0.0",
 "type": "VNIC",
 "usedIps": [
 {
 "createDate": "Nov 11, 2021 2:03:47 PM",
 "gateway": "172.25.0.1",
 "ip": "172.25.201.6",
 "ipInLong": 2887371014,
 "ipRangeUuid": "9bc64be8aec24ab8bbc9b03b5db3eebc",
 "ipVersion": 4,
 "l3NetworkUuid": "776aa4f32c704acba90811ca071919ed",
 "lastOpDate": "Nov 11, 2021 2:03:47 PM",
 "netmask": "255.255.0.0",
 "uuid": "688307033adb3bf081e5d9a0736ae0d3",
 "vmNicUuid": "eab9d08437db4f03a800f3b01c198eab"
 }
 ],
 "uuid": "eab9d08437db4f03a800f3b01c198eab",
 "vmInstanceUuid": "0d62f2c34390464d9bfd166c270a261a"
 }
 ],
 "zoneUuid": "5713bc952a904718be06f329222db7ce"
 },
 {
 "allVolumes": [
 {
 "actualSize": 9680674816,
 "createDate": "Oct 20, 2021 5:37:22 PM",
 "description": "Root volume for VM[uuid:1e77e04fccea43f2b5ce9c27f672879f]",
 "deviceId": 0,
 "format": "qcow2",
 "installPath": "/cloud_ps/rootVolumes/acct-36c27e8ff05c4780bf6d2fa65700f22e/vol-c6d41b9460ab497c989ed89b514202aa/c6d41b9460ab497c989ed89b514202aa.qcow2",
 "isShareable": false,
 "lastOpDate": "Oct 20, 2021 5:38:58 PM",
 "name": "ROOT-for-vm$xzt3",
 "primaryStorageUuid": "2116fa756e6f4e20a9f38ee5eabee186",
 "rootImageUuid": "e21d04f8fb2e4389acfe9030e108b6a9",
 "size": 10737418240,
 "state": "Enabled",
 "status": "Ready",
 "type": "Root",
 "uuid": "c6d41b9460ab497c989ed89b514202aa",
 "vmInstanceUuid": "1e77e04fccea43f2b5ce9c27f672879f"
 }
 ],
 "allocatorStrategy": "LeastVmPreferredHostAllocatorStrategy",
 "architecture": "x86_64",
 "clusterUuid": "110fcbd2f0c344fd9c33604bc51b8316",
 "cpuNum": 16,
 "cpuSpeed": 0,
 "createDate": "Oct 20, 2021 5:37:22 PM",
 "defaultL3NetworkUuid": "7dbaf58d89994042b0c1e3c6704cb3bd",
 "description": "cloned from vm[uuid:59404046cf6247a3bc1f4516762ec437]",
 "guestOsType": "Ubuntu 18",
 "hypervisorType": "KVM",
 "imageUuid": "e21d04f8fb2e4389acfe9030e108b6a9",
 "instanceOfferingUuid": "05fe32439048403f9577eed860ca9644",
 "lastHostUuid": "2926b5fce9384180a08d3cd46841e35c",
 "lastOpDate": "Nov 11, 2021 10:45:30 AM",
 "memorySize": 17179869184,
 "name": "vm$xzt3",
 "platform": "Linux",
 "rootVolumeUuid": "c6d41b9460ab497c989ed89b514202aa",
 "state": "Stopped",
 "type": "UserVm",
 "uuid": "1e77e04fccea43f2b5ce9c27f672879f",
 "vmCdRoms": [
 {
 "createDate": "Oct 20, 2021 5:37:22 PM",
 "deviceId": 0,
 "lastOpDate": "Oct 20, 2021 5:37:22 PM",
 "name": "vm-1e77e04fccea43f2b5ce9c27f672879f-cdRom",
 "uuid": "5ace720b83d4439c80ceba532457945a",
 "vmInstanceUuid": "1e77e04fccea43f2b5ce9c27f672879f"
 }
 ],
 "vmNics": [
 {
 "createDate": "Oct 20, 2021 5:37:22 PM",
 "deviceId": 0,
 "driverType": "virtio",
 "gateway": "192.168.81.1",
 "hypervisorType": "KVM",
 "internalName": "vnic7810.0",
 "ip": "192.168.81.96",
 "l3NetworkUuid": "7dbaf58d89994042b0c1e3c6704cb3bd",
 "lastOpDate": "Oct 20, 2021 5:37:22 PM",
 "mac": "fa:53:4a:f0:9d:00",
 "netmask": "255.255.255.0",
 "type": "VNIC",
 "usedIps": [
 {
 "createDate": "Oct 20, 2021 5:37:22 PM",
 "gateway": "192.168.81.1",
 "ip": "192.168.81.96",
 "ipInLong": 3232256352,
 "ipRangeUuid": "e538dab6e1e84019bd7d0a78a333d071",
 "ipVersion": 4,
 "l3NetworkUuid": "7dbaf58d89994042b0c1e3c6704cb3bd",
 "lastOpDate": "Oct 20, 2021 5:37:22 PM",
 "netmask": "255.255.255.0",
 "uuid": "9f4cdecfe309317eb07cf8ae95caf3a6",
 "vmNicUuid": "482753eb89df4fe58b27192b12173dcb"
 }
 ],
 "uuid": "482753eb89df4fe58b27192b12173dcb",
 "vmInstanceUuid": "1e77e04fccea43f2b5ce9c27f672879f"
 }
 ],
 "zoneUuid": "5713bc952a904718be06f329222db7ce"
 },
 {
 "allVolumes": [
 {
 "actualSize": 4394319872,
 "createDate": "Sep 15, 2021 2:22:29 PM",
 "description": "Root volume for VM[uuid:077973f897a0453c8f7e0760c73689d0]",
 "deviceId": 0,
 "format": "qcow2",
 "installPath": "sharedblock://e2402ed34190477cb9b4ae3a2cc58db6/65338b21e7364387811c764140788f65",
 "isShareable": false,
 "lastOpDate": "Sep 15, 2021 2:24:25 PM",
 "name": "ROOT-for-000000-3",
 "primaryStorageUuid": "e2402ed34190477cb9b4ae3a2cc58db6",
 "rootImageUuid": "b5876869ad3d464f8915f8a3597b5688",
 "size": 42949672960,
 "state": "Enabled",
 "status": "Ready",
 "type": "Root",
 "uuid": "65338b21e7364387811c764140788f65",
 "vmInstanceUuid": "077973f897a0453c8f7e0760c73689d0"
 }
 ],
 "allocatorStrategy": "LeastVmPreferredHostAllocatorStrategy",
 "architecture": "x86_64",
 "clusterUuid": "110fcbd2f0c344fd9c33604bc51b8316",
 "cpuNum": 16,
 "cpuSpeed": 0,
 "createDate": "Sep 15, 2021 2:22:29 PM",
 "defaultL3NetworkUuid": "776aa4f32c704acba90811ca071919ed",
 "description": "MSCS3",
 "guestOsType": "WindowsServer 2016",
 "hypervisorType": "KVM",
 "imageUuid": "b5876869ad3d464f8915f8a3597b5688",
 "instanceOfferingUuid": "05fe32439048403f9577eed860ca9644",
 "lastHostUuid": "aa0ed44b22004d1a899007364ca0c7c8",
 "lastOpDate": "Jan 12, 2022 2:38:09 PM",
 "memorySize": 17179869184,
 "name": "Failover Cluster 2",
 "platform": "Windows",
 "rootVolumeUuid": "65338b21e7364387811c764140788f65",
 "state": "Stopped",
 "type": "UserVm",
 "uuid": "077973f897a0453c8f7e0760c73689d0",
 "vmCdRoms": [
 {
 "createDate": "Sep 15, 2021 2:22:30 PM",
 "deviceId": 0,
 "lastOpDate": "Sep 15, 2021 2:22:30 PM",
 "name": "vm-077973f897a0453c8f7e0760c73689d0-cdRom",
 "uuid": "df81cd2b02814b88a78d60d11c5b08c3",
 "vmInstanceUuid": "077973f897a0453c8f7e0760c73689d0"
 }
 ],
 "vmNics": [
 {
 "createDate": "Sep 15, 2021 2:22:30 PM",
 "deviceId": 0,
 "driverType": "virtio",
 "gateway": "172.25.0.1",
 "hypervisorType": "KVM",
 "internalName": "vnic6672.0",
 "ip": "172.25.201.186",
 "l3NetworkUuid": "776aa4f32c704acba90811ca071919ed",
 "lastOpDate": "Nov 11, 2021 11:50:01 AM",
 "mac": "fa:44:0b:42:24:00",
 "netmask": "255.255.0.0",
 "type": "VNIC",
 "usedIps": [
 {
 "createDate": "Sep 15, 2021 2:22:30 PM",
 "gateway": "172.25.0.1",
 "ip": "172.25.201.186",
 "ipInLong": 2887371194,
 "ipRangeUuid": "9bc64be8aec24ab8bbc9b03b5db3eebc",
 "ipVersion": 4,
 "l3NetworkUuid": "776aa4f32c704acba90811ca071919ed",
 "lastOpDate": "Sep 15, 2021 2:22:30 PM",
 "netmask": "255.255.0.0",
 "uuid": "bb634a32ed2731edbb71fd9a9a5469db",
 "vmNicUuid": "a62564e7600346bd9d42992403b2f416"
 }
 ],
 "uuid": "a62564e7600346bd9d42992403b2f416",
 "vmInstanceUuid": "077973f897a0453c8f7e0760c73689d0"
 }
 ],
 "zoneUuid": "5713bc952a904718be06f329222db7ce"
 },
 {
 "allVolumes": [
 {
 "actualSize": 15186984960,
 "createDate": "Sep 24, 2021 10:42:26 PM",
 "description": "Root volume for VM[uuid:1a9ccdc7f4854d93a3ad5e6e226c2a2c]",
 "deviceId": 0,
 "format": "qcow2",
 "installPath": "sharedblock://cf1e9c4f3d674f159505c234c3e5356b/007154f1864a457b8658f81641c89485",
 "isShareable": false,
 "lastOpDate": "Sep 24, 2021 10:45:18 PM",
 "name": "ROOT-for-111-3",
 "primaryStorageUuid": "cf1e9c4f3d674f159505c234c3e5356b",
 "rootImageUuid": "01ff0ca649604b1db590bf6ef641d957",
 "size": 32212254720,
 "state": "Enabled",
 "status": "Ready",
 "type": "Root",
 "uuid": "007154f1864a457b8658f81641c89485",
 "vmInstanceUuid": "1a9ccdc7f4854d93a3ad5e6e226c2a2c"
 }
 ],
 "allocatorStrategy": "LeastVmPreferredHostAllocatorStrategy",
 "architecture": "x86_64",
 "clusterUuid": "110fcbd2f0c344fd9c33604bc51b8316",
 "cpuNum": 16,
 "cpuSpeed": 0,
 "createDate": "Sep 24, 2021 10:42:26 PM",
 "defaultL3NetworkUuid": "a61146e6f2fe4ed382c47c09d968cea0",
 "description": "",
 "guestOsType": "WindowsServer 2016",
 "hypervisorType": "KVM",
 "imageUuid": "01ff0ca649604b1db590bf6ef641d957",
 "instanceOfferingUuid": "05fe32439048403f9577eed860ca9644",
 "lastHostUuid": "f740664d2688439abf620255eb05e843",
 "lastOpDate": "Oct 1, 2021 10:25:21 AM",
 "memorySize": 17179869184,
 "name": "111-3",
 "platform": "Windows",
 "rootVolumeUuid": "007154f1864a457b8658f81641c89485",
 "state": "Stopped",
 "type": "UserVm",
 "uuid": "1a9ccdc7f4854d93a3ad5e6e226c2a2c",
 "vmCdRoms": [
 {
 "createDate": "Sep 24, 2021 10:42:26 PM",
 "deviceId": 0,
 "lastOpDate": "Sep 24, 2021 10:42:26 PM",
 "name": "vm-1a9ccdc7f4854d93a3ad5e6e226c2a2c-cdRom",
 "uuid": "3af14b1eebf74b05bccead5455b21649",
 "vmInstanceUuid": "1a9ccdc7f4854d93a3ad5e6e226c2a2c"
 }
 ],
 "vmNics": [
 {
 "createDate": "Sep 25, 2021 11:38:22 PM",
 "deviceId": 0,
 "driverType": "e1000",
 "gateway": "172.26.0.1",
 "hypervisorType": "KVM",
 "internalName": "vnic6711.0",
 "ip": "172.26.201.214",
 "l3NetworkUuid": "a61146e6f2fe4ed382c47c09d968cea0",
 "lastOpDate": "Sep 25, 2021 11:38:22 PM",
 "mac": "fa:a8:c6:4b:1e:00",
 "netmask": "255.255.0.0",
 "type": "VNIC",
 "usedIps": [
 {
 "createDate": "Sep 25, 2021 11:38:22 PM",
 "gateway": "172.26.0.1",
 "ip": "172.26.201.214",
 "ipInLong": 2887436758,
 "ipRangeUuid": "63708e07fa374fe5b9d735b6455e5651",
 "ipVersion": 4,
 "l3NetworkUuid": "a61146e6f2fe4ed382c47c09d968cea0",
 "lastOpDate": "Sep 25, 2021 11:38:22 PM",
 "netmask": "255.255.0.0",
 "uuid": "39c53c8847e7351c84c42b57ccb64c1e",
 "vmNicUuid": "6a156d11879647228cf9a1cbc8b14538"
 }
 ],
 "uuid": "6a156d11879647228cf9a1cbc8b14538",
 "vmInstanceUuid": "1a9ccdc7f4854d93a3ad5e6e226c2a2c"
 }
 ],
 "zoneUuid": "5713bc952a904718be06f329222db7ce"
 }
 ],
 "returnWith": {
 "zwatch": [
 {
 "labels": {
 "CPUNum": "10",
 "VMUuid": "747d5c006d3a4654a84750772fdecf10"
 },
 "time": 1650601783,
 "value": 0.18
 },
 {
 "labels": {
 "CPUNum": "10",
 "VMUuid": "747d5c006d3a4654a84750772fdecf10"
 },
 "time": 1650601773,
 "value": 0.16
 }
 ],
 "zwatchTotal": 2
 },
 "total": 252
 }
 ],
 "success": true
}

Handling Batch API Responses

Batch API responses can be classified into two categories: responses of long jobs and responses of non-long jobs.

Non-Long Job API Response

For error responses of non-long jobs, the value of the success field in the first layer is true. The value of the success field in inner layers vary depending on the sub-task result. If a sub-task succeeded, success=true is returned. Otherwise, success=false is returned. The following shows a sample response of the APIBatchDeleteVolumeSnapshotMsg operation:

Error Response:
{
    "results": [
        {
            "error": {
                "code": "VOLUME_SNAPSHOT.1000",
                "description": "Snapshot is not in correct status for operation.",
                "details": "snapshot[uuid:e9c43724c6614aa488b63d6b33e30ebd, name:test1]'s status[Ready] is not allowed for message[org.zstack.header.storage.snapshot.VolumeSnapshotDeletionMsg], allowed status[Ready, Creating, Deleting]"
            },
            "snapshotUuid": "e9c43724c6614aa488b63d6b33e30ebd",
            "success": false
        },
        {
            "error": {
                "code": "VOLUME_SNAPSHOT.1000",
                "description": "Snapshot is not in correct status for operation.",
                "details": "snapshot[uuid:e9c43724c6614aa488b63d6b33e30ebd, name:test2]'s status[Ready] is not allowed for message[org.zstack.header.storage.snapshot.VolumeSnapshotDeletionMsg], allowed status[Ready, Creating, Deleting]"
            },
            "snapshotUuid": "63daa66726b24f9390216b8edf32190d",
            "success": false
        }
    ],
    "success": true
}
Successful Response:
{
    "results": [
        {
            "snapshotUuid": "1c8408e0f05d4fc39465d7db27d6bc32",
            "success": true
        },
        {
            "snapshotUuid": "e071e0ec42de4323bff23993a6a236d2",
            "success": true
        }
    ],
    "success": true
}

Long Job API Response

For error responses of long jobs, the value of the success field in the first layer is true. The value of the success field in inner layers vary depending on the sub-task result. If a sub-task succeeded, success=true is returned. Otherwise, success=false is returned. The following shows a sample response of the APIAddHostFromConfigFileMsg operation:

Error Response:
{
    "results": [
        {
            "error": {
                "code": "SYS.1006",
                "cost": "5ms",
                "description": "An operation failed",
                "details": "the host[10.0.231.23] ssh port[22] not open after 300 seconds, connect timeout",
                "elaboration": "Error message: SSH port [22] on host [10.0.231.23] was not open within 300 seconds. Connection timed out.",
                "location": "HostManagerImpl.java: send-connect-host-message (location:2/4)"
            },
            "ip": "10.0.231.23",
            "success": false
        },
        {
            "error": {
                "code": "SYS.1007",
                "description": "One or more API argument is invalid",
                "details": "A host with management IP [10.0.93.160] already exists."
            },
            "ip": "10.0.93.160",
            "success": false
        }
    ],
    "success": true
}
Successful Response:
{
    "results": [
        {
            "ip": "10.0.231.231",
            "success": true
        },
        {
            "ip": "10.0.93.160",
            "success": true
        }
    ],
    "success": true
}

Conclusion

  • The value of the success field in the first layer of the two categories of API responses istrue.
  • The value of the success field in the first layer indicates the result of a Restful API request. If the request succeeds, the value of the success field is true.
  • The value of the successfield in the inner layers indicates the result of a sub-task of a Restful API request. If a sub-task succeeds, succuess=true is returned for the sub-task. Otherwise, succee=false is returned for the sub-task.
API Reference | ZStack ZSphere · ZVF | ZStack Resource Center