且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

阿里云资源编排之异步通知

更新时间:2022-08-20 09:10:08

本文介绍阿里云资源编排服务(ROS)(下面简称ROS)的异步通知功能。

创建、更新或删除资源栈(下面简称Stack)时,为了判断操作是否完成,通常我们会起一个定时任务,轮询Stack的状态直至完成。这种做法比较低效,使用异步通知功能,可以避免这个问题。ROS会在资源栈的操作完成时,回调通知客户。

使用方法

  • 在创建Stack时,通过Webhook参数指定回调地址。
  • 回调地址可以是一个或多个,通过逗号分隔。
  • 回调目前只支持HTTP POST。
  • Stack至少包含一个输出。

示例

搭建HTTP服务器

申请一台拥有公网IP的ECS,并安全组入方向开放相应端口。这里我创建一台CentOS 7.6的机器,安全组开放8081端口。登录机器执行如下命令,启动一个Web服务。

pip install web.py

cat >website.py <<EOF
# -*- coding: utf-8 -*-

import web
import json


urls = (
    '/', 'Index'
)


class Index(object):

    def GET(self):
        return "Hello, world!"

    def POST(self):
        s = web.data()
        try:
            print(json.dumps(json.loads(s), sort_keys=True, indent=4, separators=(',', ': ')))
        except:
            print(s)
        return "Hello, world!"


if __name__ == "__main__":
    app = web.application(urls, globals())
    app.run()
EOF

python website.py 8081

创建Stack

以Python SDK为例,重点关注带注释部分。

# coding:utf-8

import json
import pprint

from aliyunsdkcore import client
from aliyunsdkros.request.v20150901 import CreateStacksRequest


AK = '<AK>'                           # Access Key
SECRET = '<SECRET>'                   # Access Key Secret
REGION = '<REGION>'                   # RegionId,比如cn-beijing
WEB_HOOK = 'http://<PUBLIC_IP>:8081'  # 回调地址,使用ECS的公网IP代替PUBLIC_IP


class RequestHelper(object):

    def __init__(self):
        self._clt = client.AcsClient(AK, SECRET, REGION)

    _instance = None

    @classmethod
    def instance(cls):
        if not cls._instance:
            cls._instance = cls()
        return cls._instance

    def run(self, request, body=None):
        if body is not None:
            request.set_content(json.dumps(body))
        request.set_content_type('application/json')

        status, headers, body = self._clt.get_response(request)

        pprint.pprint(status)
        pprint.pprint(headers)
        try:
            pprint.pprint(json.loads(body))
        except ValueError:
            pprint.pprint(body)


def main():
    request = CreateStacksRequest.CreateStacksRequest()
    body = {
        'Name': 'test-web-hook',
        'DisableRollback': False,
        'TimeoutMins': 120,
        'Webhook': WEB_HOOK,          #通过Webhook参数指定回调地址
        'Template': {
            'ROSTemplateFormatVersion': '2015-09-01',
            'Resources': {
                'WaitConditionHandle': {
                    'Type': 'ALIYUN::ROS::WaitConditionHandle'
                }
            },
            'Outputs': {
                'CurlCli': {
                    'Value': {
                        'Fn::GetAtt': ['WaitConditionHandle', 'CurlCli']
                    }
                }
            }
        }
    }
    RequestHelper.instance().run(request, body)


if __name__ == '__main__':
    main()

观察回调结果

{
    "Outputs": [
        {
            "Description": "No description given",
            "OutputKey": "CurlCli",
            "OutputValue": "curl -i -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'x-acs-region-id: cn-beijing' http://100.100.100.110/waitcondition?stackname=test-web-hook\\&stackid=80bd6b6c-e888-4573-ae3b-93d29144911d\\&resource=WaitConditionHandle\\&expire=1555424388\\&signature=e014516fa8028d8a8df9c9f4c9f7dc82a49421c1"
        }
    ],
    "StackId": "80bd6b6c-e888-4573-ae3b-93d29144911d",
    "StackName": "test-web-hook",
    "Status": "CREATE_COMPLETE"
}