新闻动态

NEWS
ZStack HTTP API使用

Frank_Zhang | 2017-03-01 16:13


1. 介绍


ZStack的API原语是JSON格式的消息,可以在各种消息总线上调用,目前ZStack使用的默认消息总线是RabbitMQ。由于这个特性,ZStack的API可以被封装成各种格式。为了方便大家使用,ZStack自带一个HTTP server,用户可以通过HTTP POST发送API JSON文本,该HTTP Server会自动将其转换成API消息实现调用。

我们未来会将ZStack API封装成Restful格式,但当前HTTP POST发送API JSON原语的方式将一直保留

ZStack的命令行工具(zstack-cli)是完全使用HTTP POST方法调用API的,为了方便用户阅读,我们用户手册对所有API的解释都是以zstack-cli为示例,每个cli命令都对应一个API。用户可以在中文用户手册获得每个API的详细解释。

通过zstack-cli的log,用户可以查看所有API调用和返回的具体格式(即HTTP POST的BODY)。

Log路径: /var/log/zstack/zstack-cli

我们建议用户通过tail -f /var/log/zstack/zstack-cli实时查看log,这样你可以在zstack-cli中执行API时实时观测到具体调用和输出。例如:

>>LogInByAccount accountName=admin password=password

执行了登录操作后,你会看到LOG中输出类似如下内容:

2016-02-16 16:29:48,664 DEBUG [apibinding.api] async call[url: http://localhost:8080/zstack/api/, request: {"org.zstack.header.identity.APILogInByAccountMsg": {"password": "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86", "session": {}, "accountName": "admin"}}]

2016-02-16 16:29:48,741 DEBUG [apibinding.api] async call[url: http://localhost:8080/zstack/api/, response: {"org.zstack.header.identity.APILogInReply":{"inventory":{"uuid":"083f3518d1bd469fa0ff789fc1a25382","accountUuid":"36c27e8ff05c4780bf6d2fa65700f22e","userUuid":"36c27e8ff05c4780bf6d2fa65700f22e","expiredDate":"Feb 17, 2016 12:29:48 PM","createDate":"Feb 16, 2016 4:29:48 PM"},"success":true}}]

这里http://localhost:8080/zstack/api/是HTTP调用的URL,request后的内容是API调用时HTTP POST的BODY,例如这里LogInByAccount这个API的HTTP POST BODY就是:

{
    "org.zstack.header.identity.APILogInByAccountMsg": {
    "password": "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86",
    "session": {},
    "accountName": "admin"
    }
}

response后的内容是API返回的HTTP response的BODY,例如这里LogInByAccount的返回是:

{
    "org.zstack.header.identity.APILogInReply": {
        "inventory": {
            "uuid": "083f3518d1bd469fa0ff789fc1a25382",
            "accountUuid": "36c27e8ff05c4780bf6d2fa65700f22e",
            "userUuid": "36c27e8ff05c4780bf6d2fa65700f22e",
            "expiredDate": "Feb 17, 2016 12:29:48 PM",
            "createDate": "Feb 16, 2016 4:29:48 PM"
        },
        "success": true
    }
}

2. API的格式

ZStack API的调用和返回都是以JSON原语描述的,格式统一为:只有一个entry的JSON map,该entry的key是API描述符,value是承载具体内容的一个map。API描述符用来唯一标示一个API调用或返回,用户可以把它看做API的名称。在上一节的例子中,API调用的描述符是org.zstack.header.identity.APILogInByAccountMsg,API返回的描述符是org.zstack.header.identity.APILogInReply

3. HTTP返回码

返回码 描述
200 HTTP调用成功。但并不代表API执行成功,API的执行结果由API返回中的success字段决定,true表示成功;false表示失败
其他 含义跟标准的HTTP返回码相同,例如500代表Internal Server Error;404代表No such page

4. HTTP Response Body

API的HTTP response返回的是一个Job结构,调用者需要用该Job的uuid去轮询查询API是否已经完成。API Job的格式如下:

字段 类型 描述
uuid 字符串 JOB UUID,用户可以用该UUID去查询一个API JOB当前的执行状态。当state == Done时,该字段可能为NULL
state 字符串 JOB状态。包括两种状态:Processing,该JOB还在执行;Done,JOB已经完成
result 字符串 API结果,JSON字符串。当state = Processing时,该字段为NULL
createdDate 字符串 JOB创建时间
finishedDatel 字符串 JOB完成时间


state == Processing的Job例子:

    {
        "uuid": "fee83ed8529340cd8528b3b408dc16b0",
        "state": "Processing",
        "createdDate": "Feb 16, 2016 5:01:11 PM"
    }

state == Done的Job例子:

    {
        "uuid": "fee83ed8529340cd8528b3b408dc16b0",
        "state": "Done",
        "createdDate": "Feb 16, 2016 5:01:11 PM",
        "finishedDate": "Feb 16, 2016 5:01:12 PM",
        "result": "{"org.zstack.header.zone.APICreateZoneEvent":{"inventory":{"uuid":"f1ed8f95163c4b6c88a8c0673b7913b7","name":"xx","state":"Enabled","type":"zstack","createDate":"Feb 16, 2016 5:01:12 PM","lastOpDate":"Feb 16, 2016 5:01:12 PM"},"success":true}}"
    }

4.1 查询API JOB的状态

当调用一个API后,HTTP response返回一个Job结构,其中包含有该Job的uuid,用户需要通过该uuid去查询该Job的状态。

查询的方法是向http://locahost:8080/api/result/{job uuid}发送一个HTTP Get请求,

curl  
http://localhost:8080/zstack/api/result/fee83ed8529340cd8528b3b408dc16b0

其HTTP response返回一个Job结构,用户可以通过判断Job的state字段来判断Job是否完成,从而决定是否需要继续轮询Job的状态

5. API的调用流程

ZStack API的调用的标准流程是:

调用LogInByAccount,获得一个Session UUID,作为后续API调用的token
调用API 1
调用API 2
... ...
调用API N
调用LogOut

5.1 登录

在调用其他API前,用户需要首先调用LogInByAccount以获得一个session UUID,以此作为后续API调用的token。该API的描述符为:org.zstack.header.identity.APILogInByAccountMsg,包含以下字段:

字段 描述
accountName 用户名。例如admin
password 密码。zstack不对密码进行任何处理,只是单纯将其与数据库中存储的密码数据进行字符串比对。我们建议在调用CreateAccount这样的API时,密码使用sha512加密

默认用户名密码:ZStack默认的用户名是admin,其密码明文为password,sha512哈希后的结果为

b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86

所以该API的JSON描述类似于:

{
    "org.zstack.header.identity.APILogInByAccountMsg": {
        "password": "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86",
        "accountName": "admin"
    }
}

用curl调用该API:

    curl -H "Content-Type: application/json" -d '{"org.zstack.header.identity.APILogInByAccountMsg": {"password": "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86", "accountName": "admin"}}' http://localhost:8080/zstack/api

返回的Job结构为:

{
    "state": "Done",
    "createdDate": "Feb 16, 2016 7:15:01 PM",
    "finishedDate": "Feb 16, 2016 7:15:01 PM",
    "result": "{"org.zstack.header.identity.APILogInReply":{"inventory":{"uuid":"9eba9754f8c2470cbb377088e61c4da2","accountUuid":"36c27e8ff05c4780bf6d2fa65700f22e","userUuid":"36c27e8ff05c4780bf6d2fa65700f22e","expiredDate":"Feb 17, 2016 3:15:01 PM","createDate":"Feb 16, 2016 7:15:01 PM"},"success":true}}"
}

其result字段包含的是API的结果,JSON表达为:

{
    "org.zstack.header.identity.APILogInReply": {
        "inventory": {
            "uuid": "9eba9754f8c2470cbb377088e61c4da2",
            "accountUuid": "36c27e8ff05c4780bf6d2fa65700f22e",
            "userUuid": "36c27e8ff05c4780bf6d2fa65700f22e",
            "expiredDate": "Feb 17, 2016 3:15:01 PM",
            "createDate": "Feb 16, 2016 7:15:01 PM"
        },
        "success": true
    }
}

其中uuid字段即是我们需要的Session UUID。

5.2 普通API调用

除登录(LogInByAccount)、登出(LogOut)等少数API外,剩下的都是普通API,在调用时需要传入LogIn拿到的Session UUID,其JSON原语为:

    {
        "API描述符": {
           "session": {
                "uuid": "LogIn时拿到的session UUID"
           },
           "API字段名1": ...,
           "API字段名2”: ...
        }
    }

再次提醒:你可以通过查看/var/log/zstack/zstack-cli得到你在zstack-cli执行的每个API的描述符、request和response。

5.3 登出

当你执行完需要的API后,应该调用LogOut API退出当前session。该API的描述符是org.zstack.header.identity.APILogOutMsg,其JSON原语是:

    {
        "org.zstack.header.identity.APILogOutMsg": {
            "sessionUuid": "你要LogOut的Session UUID"
        }
    }

用curl调用:

 curl -H "Content-Type: application/json" -d '{"org.zstack.header.identity.APILogOutMsg": {"sessionUuid": "083f3518d1bd469fa0ff789fc1a25382"}}' http://localhost:8080/zstack/api

6. 创建一个Zone的Curl示例

这里我们将用创建Zone这个例子,展示如何用Curl手动调用ZStack的API。

6.1 登录

调用:

curl -H "Content-Type: application/json" -d '{"org.zstack.header.identity.APILogInByAccountMsg": {"password": "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86", "accountName": "admin"}}' http://localhost:8080/zstack/api

返回:

{"state":"Done","createdDate":"Feb 16, 2016 7:53:14 PM","finishedDate":"Feb 16, 2016 7:53:14 PM","result":"{"org.zstack.header.identity.APILogInReply":{"inventory":{"uuid":"2f68cf0a5783400694bd8efdd536a2a8","accountUuid":"36c27e8ff05c4780bf6d2fa65700f22e","userUuid":"36c27e8ff05c4780bf6d2fa65700f22e","expiredDate":"Feb 17, 2016 3:53:14 PM","createDate":"Feb 16, 2016 7:53:14 PM"},"success":true}}"}

6.2 创建一个Zone

调用:

curl -H "Content-Type: application/json" -d '{"org.zstack.header.zone.APICreateZoneMsg": {"session": {"uuid": "2f68cf0a5783400694bd8efdd536a2a8"}, "name": "zone1"}}' http://localhost:8080/zstack/api

返回:

{"uuid":"2252332b14fb42599558577cb24fa168","state":"Processing","createdDate":"Feb 16, 2016 7:55:34 PM"}

这里我们得到了一个Job UUID 2252332b14fb42599558577cb24fa168,通过它我们可以轮询创建Zone这个API的结果。

轮询结果:

curl  http://localhost:8080/zstack/api/result/2252332b14fb42599558577cb24fa168

返回:

{"uuid":"2252332b14fb42599558577cb24fa168","state":"Done","createdDate":"Feb 16, 2016 7:55:34 PM","finishedDate":"Feb 16, 2016 7:55:34 PM","result":"{"org.zstack.header.zone.APICreateZoneEvent":{"inventory":    {"uuid":"dd625f8fb2074f4fa1c0870ef76bb24a","name":"zone1","state":"Enabled","type":"zstack","createDate":"Feb 16, 2016 7:55:34 PM","lastOpDate":"Feb 16, 2016 7:55:34 PM"},"success":true}}"}

这里我们看到该API已经完成了,state == Done。API的结果以一个JSON字符串的形式保存在result字段中。可以看到该API调用成功,因为success字段为true。

6.3 登出

调用:

curl -H "Content-Type: application/json" -d '{"org.zstack.header.identity.APILogOutMsg": {"sessionUuid": "2252332b14fb42599558577cb24fa168"}}' http://localhost:8080/zstack/api

返回:

{"state":"Done","createdDate":"Feb 16, 2016 8:04:36 PM","finishedDate":"Feb 16, 2016 8:04:37 PM","result":"{"org.zstack.header.identity.APILogOutReply":{"success":true}}"}

7. 创建一个Zone的Python示例

你可以'点击这里'获得完整代码。

import httplib
import json
import time

 # return a dict containing API return value
def api_call(session_uuid, api_id, api_content):
    conn = httplib.HTTPConnection("localhost", 8080)
    headers = {"Content-Type": "application/json"}

    if session_uuid:
        api_content["session"] = {"uuid": session_uuid}

    api_body = {api_id: api_content}

    conn.request("POST", "/zstack/api", json.dumps(api_body))
    response = conn.getresponse()

    if response.status != 200:
        raise Exception("failed to make an API call, %s, %s" % (response.status, response.reason))

    rsp_body = response.read()

    rsp = json.loads(rsp_body)

    if rsp["state"] == "Done":
        return json.loads(rsp["result"])

    job_uuid = rsp["uuid"]
    def query_until_done():
        conn.request("GET", "/zstack/api/result/%s" % job_uuid)
        response = conn.getresponse()
        if response.status != 200:
            raise Exception("failed to query API result, %s, %s" % (response.status, response.reason))

        rsp_body = response.read()
        rsp = json.loads(rsp_body)
        if rsp["state"] == "Done":
            return json.loads(rsp["result"])

        time.sleep(1)
        print "Job[uuid:%s] is still in processing" % job_uuid
        return query_until_done()

    return query_until_done()

def error_if_fail(rsp):
    success = rsp.values()[0]["success"]
    if not success:    
        error = rsp.values()[0]["error"]
        raise Exception("failed to login, %s" % json.dumps(error))

def login():
    content = {
            "accountName": "admin",
            "password": "b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86"
    }
    rsp = api_call(None, "org.zstack.header.identity.APILogInByAccountMsg", content)
    error_if_fail(rsp)

    session_uuid = rsp.values()[0]["inventory"]["uuid"]

    print "successfully login, session uuid is: %s" % session_uuid
    return session_uuid

def create_zone(session_uuid):
    content = {"name": "zone1"}

    rsp = api_call(session_uuid, "org.zstack.header.zone.APICreateZoneMsg", content)
    error_if_fail(rsp)

    print "successfully created zone1"

def logout(session_uuid):
    content = {"sessionUuid": session_uuid}
    rsp = api_call(None, "org.zstack.header.identity.APILogOutMsg", content)
    error_if_fail(rsp)

    print "successfully logout"
session_uuid = login()
create_zone(session_uuid)
logout(session_uuid)

最近文章

咨询

021-61733682

400-962-2212