当前位置: 首页 > 工具软件 > stacks-cli > 使用案例 >

ROS-CLI命令行源码及使用方法整理

薛欣德
2023-12-01

ROS-CLI源码

参考文章:

通过命令行工具使用阿里云资源编排服务

阿里云ROS帮助文档——命令行工具使用示例

源码下载:命令行工具源码地址

一、目录结构

aliyun-ros-cli-master
    --bin                执行文件        
        --ros            
    --resources
        --ros_completion
    --ros
        --apps            功能及配置相关
            --__init__.py
            --config.py
            --NewConfigParser.py
            --utils.py
        --others        其他操作命令
            --__init__.py
            --list_events_command.py
            --list_regions_command.py
            --userdata_command.py
        --resources        操作资源命令
            --__init__.py
            --describe_resource_command.py
            --list_resources_command.py
            --resource_type_command.py
            --resource_type_detail_command.py
            --resource_type_template_command.py
        --stacks        资源栈操作命令
            --__init__.py
            --abandon_stack_command.py
            --create_stack_command.py
            --delete_stack_command.py
            --describe_stack_command.py
            --list_stacks_command.py
            --preview_stack_command.py
            --update_stack_command.py
        --templates        模板操作命令
            --__init__.py
            --get_template_command.py
            --validate_template_command.py
        --__init__.py

二、命令

概览

ros 本身支持如下参数:

命令功能
-h --help 查看帮助信息
--config [CONFIG_FILE]使用指定配置文件,如果没有指定,默认使用当前目录下的 ros/ros.conf 作为配置文件
--jsonjson格式输出查询信息,否则以阅读格式输出
--region-id [REGION_ID]指定区域信息,否则使用配置文件中的区域信息

json 格式的输出按照配置文件中的 JSON_INDENT 设置缩进。

ros 支持如下一级命令:

命令功能
set-userdata设置默认配置
create-stack创建堆栈
delete-stack删除堆栈
update-stack更新堆栈
preview-stack预览堆栈
abandon-stack废弃堆栈(开发中)
list-stacks列出满足条件的堆栈
describe-stack列出指定堆栈的详细信息
list-resource列出指定堆栈的资源信息
describe-resource列出指定资源的详细信息
resource-type列出所有资源类型
resource-type-detail列出指定资源类型的详细信息
resource-type-template列出指定资源类型的模板信息
get-template列出指定堆栈的模板信息
validate-template验证模板信息
list-regions列出所有区域
list-events列出满足条件的事件信息

1、资源栈相关

Abandon Stack

使用 ros abandon-stack 命令废弃堆栈,包含如下参数:

命令功能备注
--region-id指定堆栈所在区域必须给出
--stack-name [STACK_NAME]指定堆栈的名称必须给出
--stack-id [STACK_ID]指定堆栈的ID必须给出
Create Stack

使用 ros create-stack 命令创建堆栈,包含如下参数:

命令功能备注
--region-id指定堆栈所在区域 region-id 将按如下优先级取用:当前命令指定值 > ros 命令指定值 > 配置文件指定值
--stack-name [STACK_NAME]指定创建堆栈的名称必须给出
--template-url [TEMPLATE_URL]指定创建堆栈的模板文件必须给出,模板文件内容为 json 格式的模板
--parameters [PARAMETERS]给出模板需要的参数与模板中的参数匹配,否则会被服务器拒绝。格式为连续的字符串,形如key1=value1,key2=value2
--disable-rollback [DISABLE_ROLLBACK]指定回滚策略默认 true 禁止回滚,
--timeout-in-minutes [TIMEOUT_IN_MINUTES]指定超时时间默认 60 (分钟)

创建成功后,返回堆栈名称和ID,否则返回错误信息。

Preview Stack

使用 ros preview-stack 命令创建堆栈,包含如下参数:

命令功能备注
--region-id指定堆栈所在区域 region-id 将按如下优先级取用:当前命令指定值 > ros 命令指定值 > 配置文件指定值
--stack-name [STACK_NAME]指定预览堆栈的名称必须给出
--template-url [TEMPLATE_URL]指定预览堆栈的模板文件必须给出,模板文件内容为 json 格式的模板
--parameters [PARAMETERS]给出模板需要的参数与模板中的参数匹配,否则会被服务器拒绝。格式为连续的字符串,形如key1=value1,key2=value2
--disable-rollback [DISABLE_ROLLBACK]指定回滚策略默认 true 禁止回滚,
--timeout-in-minutes [TIMEOUT_IN_MINUTES]指定超时时间默认 60 (分钟)
Update Stack

使用 ros update-stack 命令更新堆栈,包含如下参数:

命令功能备注
--region-id指定堆栈所在区域必须给出
--stack-name [STACK_NAME]指定更新堆栈的名称必须给出
--stack-id [STACK_ID]指定更新堆栈的ID必须给出
--template-url [TEMPLATE_URL]指定更新堆栈的模板文件必须给出,模板文件内容为 json 格式的模板
--parameters [PARAMETERS]给出模板需要的参数与模板中的参数匹配,否则会被服务器拒绝。格式为连续的字符串,形如key1=value1,key2=value2
--disable-rollback [DISABLE_ROLLBACK]指定回滚策略默认 true 禁止回滚,
--timeout-in-minutes [TIMEOUT_IN_MINUTES]指定超时时间默认 60 (分钟)

更新成功后,返回堆栈名称和ID,否则返回错误信息。

Delete Stack

使用 ros delete-stack 命令删除堆栈,包含如下参数:

命令功能备注
--region-id指定堆栈所在区域必须给出
--stack-name [STACK_NAME]指定堆栈的名称必须给出
--stack-id [STACK_ID]指定堆栈的ID必须给出

删除成功后,提示成功,无返回值,否则返回错误信息。

List Stacks

使用 ros list-stacks 命令查看堆栈列表,包含如下参数:

命令功能备注
--region-id指定堆栈所在区域
--stack-name [STACK_NAME]指定堆栈的名称
--stack-id [STACK_ID]指定堆栈的ID
--status {CREATE_COMPLETE, CREATE_FAILED, CREATE_IN_PROGRESS, DELETE_COMPLETE, DELETE_FAILED, DELETE_IN_PROGRESS, ROLLBACK_COMPLETE, ROLLBACK_FAILED, ROLLBACK_IN_PROGRESS}指定堆栈的状态必须使用指定值
--page-number [PAGE_NUMBER]输入查看的页码查询结果将分页返回,从1开始,默认为1
--page-size [PAGE_SIZE]指定每页显示数量默认为10,不超过100

输出当前的翻页情况及结果列表

Describe Stack

使用 ros describe-stack 命令获取堆栈详细信息,包含如下参数:

命令功能备注
--stack-name [STACK_NAME]指定堆栈的名称必须给出
--stack-id [STACK_ID]指定堆栈的ID必须给出

成功后输出堆栈信息,否则输出错误信息。

2、资源相关

List Resources

使用 ros list-resources 命令获取堆栈资源信息,包含如下参数:

命令功能备注
--stack-name [STACK_NAME]指定堆栈的名称必须给出
--stack-id [STACK_ID]指定堆栈的ID必须给出

成功后输出堆栈资源信息,否则输出错误信息。

Describe Resource

使用 ros describe-resource 命令获取堆栈资源信息,包含如下参数:

命令功能备注
--stack-name [STACK_NAME]指定堆栈的名称必须给出
--stack-id [STACK_ID]指定堆栈的ID必须给出
--resource-name [RESOUCE_NAME]指定的资源名称必须给出

成功后输出堆栈资源信息,否则输出错误信息。

Resource Type

使用 ros resoucre-type 命令获取资源种类信息,包含如下参数:

命令功能备注
--status {UNKNOWN, SUPPORTED, DEPRECATED, UNSUPPORTED, HIDDEN}资源状态默认使用SUPPORTED

成功后输出资源种类信息。如果没有符合要求的,无输出。

Resource Type Detail

使用 ros resource-type-detail 命令获取资源种类信息,包含如下参数:

命令功能备注
--name [NAME]指定资源类型的名称必须给出

成功后返回资源详细信息,否则输出错误信息。

Resource Type template

使用 ros resource-type-template命令获取资源种类模板,包含如下参数:

命令功能备注
--name [NAME]指定资源类型的名称必须给出

成功后返回资源模板信息,否则输出错误信息。

3、模板相关

Get Template

使用 ros get-template 命令获取指定堆栈的模板,包含如下参数:

命令功能备注
--stack-name [STACK_NAME]指定堆栈的名称必须给出
--stack-id [STACK_ID]指定堆栈的ID必须给出

获取成功后,输出模板,否则输出错误信息。

Validate Template

使用 ros validate-template 命令验证指定堆栈的模板,包含如下参数:

命令功能备注
--template-url [TEMPLATE_URL]指定模板地址必须给出

获取成功后,输出模板,否则输出错误信息。

4、其他

List Regions

列出所有的区域,无需参数。

List Events

使用 ros list-events 命令查看事件列表,包含如下参数:

命令功能备注
--stack-name [STACK_NAME]指定堆栈的名称
--stack-id [STACK_ID]指定堆栈的ID
--resource-status {'COMPLETE', 'FAILED', 'IN_PROGRESS'}指定资源的状态必须使用指定值
--resource-name指定筛选资源
--resource-type指定筛选资源类型
--page-number [PAGE_NUMBER]输入查看的页码查询结果将分页返回,从1开始,默认为1
--page-size [PAGE_SIZE]指定每页显示数量默认为10,不超过100

输出当前的翻页情况及结果列表

Set userdata

使用 set-userdata 命令设置默认的用户配置。

命令功能备注
--key-id [KEY_ID]默认的 ALIYUN Access Key ID
--key-secret [KEY_SECRET]默认的 ALIYUN Access Key Secret
--region-id [REGION_ID]默认的 region-id
--json-indent [JSON_INDENT]JSON输出时的缩进

三、源码

1、bin\

ros
#!/usr/bin/env python
# coding=utf-8

import argparse

import os
import sys

POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir))
if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'ros', '__init__.py')):
    sys.path.insert(0, POSSIBLE_TOPDIR)

from ros.stacks import create_stack_command
from ros.stacks import delete_stack_command
from ros.stacks import update_stack_command
from ros.stacks import preview_stack_command
from ros.stacks import abandon_stack_command
from ros.stacks import describe_stack_command
from ros.stacks import list_stacks_command
from ros.resources import list_resources_command
from ros.resources import describe_resource_command
from ros.resources import resource_type_command
from ros.resources import resource_type_detail_command
from ros.resources import resource_type_template_command
from ros.templates import validate_template_command
from ros.templates import get_template_command
from ros.others import list_regions_command
from ros.others import list_events_command
from ros.others import userdata_command
from ros.apps import config


if __name__ == '__main__':
      # 设置程序名(文件名)
    parser = argparse.ArgumentParser(prog='ros')
    # 添加子命令
    subparsers = parser.add_subparsers(title='commands', metavar='', help=None)
    # 添加可选参数: 配置文件、是否json格式输出、Region ID
    parser.add_argument('--config', metavar='CONFIG_FILE', help='Location of config file', default=None)
    parser.add_argument('--json', action='store_true', help="Print results as JSON format", default=False)
    parser.add_argument('--region-id', help="Region ID, if not set, use config file's field", default=None)

    # 设置各种相关命令
    userdata_command.setup(subparsers)

    create_stack_command.setup(subparsers)
    delete_stack_command.setup(subparsers)
    update_stack_command.setup(subparsers)
    preview_stack_command.setup(subparsers)
    abandon_stack_command.setup(subparsers)
    list_stacks_command.setup(subparsers)
    describe_stack_command.setup(subparsers)

    list_resources_command.setup(subparsers)
    describe_resource_command.setup(subparsers)
    resource_type_command.setup(subparsers)
    resource_type_detail_command.setup(subparsers)
    resource_type_template_command.setup(subparsers)
    
    get_template_command.setup(subparsers)
    validate_template_command.setup(subparsers)

    list_regions_command.setup(subparsers)
    list_events_command.setup(subparsers)
    
    # 参数输入
    args = parser.parse_args()
    config.set_client(args.config, args.region_id, POSSIBLE_TOPDIR)
    if(args.json):
        config.JSON_FORM = True

    args.func(args)

2、rosapps\

utils.py
import ConfigParser

# 处理配置文件的类,继承自python内置ConfigParser类    
class NewConfigParser(ConfigParser.ConfigParser):
    '''
    Make options keep upper case
    '''
    def __init__(self,defaults=None):
        ConfigParser.ConfigParser.__init__(self, defaults=None)

    def optionxform(self, optionstr):
        return optionstr
config.py 处理用户配置
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException

import NewConfigParser
import os
import sys
import re

reload(sys)
sys.setdefaultencoding('utf-8')

# 初始化配置
ACCESS_KEY_ID = None
ACCESS_KEY_SECRET = None
REGION_ID = None
client = None
JSON_FORM = False
JSON_INDENT = 2
ROS_DEBUG = False


# 输出当前配置
def current_conf():
    """
    Print current client configuration
    :return: None
    """
    global ACCESS_KEY_ID
    global ACCESS_KEY_SECRET
    global REGION_ID

    print(
        "[DEBUG] Current Config:\nACCESS_KEY_ID: %s\nACCESS_KEY_SECRET: %s\nREGION_ID: %s\n" %
        (ACCESS_KEY_ID, ACCESS_KEY_SECRET, REGION_ID))


def set_client(cfg_file, region_id, top_dir=None):
    """
    Configure client
    :param cfg_file: specify the configuration file
    :param region_id: specify region id
    :param top_dir: working path
    :return: None
    """
    global ACCESS_KEY_ID
    global ACCESS_KEY_SECRET
    global REGION_ID
    global client
    global JSON_INDENT
    global ROS_DEBUG

    # 指定默认配置文件
    if top_dir is None:
        default_file = 'ros/ros.conf'
    else:
        default_file = os.path.normpath(top_dir + '/ros/ros.conf')

    # 如果未提供配置文件 则使用默认文件
    cf = NewConfigParser.NewConfigParser()
    if cfg_file is None:
        if ROS_DEBUG:
            print("Use default config file: %s\n" % default_file)
        cfg_file = default_file

    if os.path.isfile(cfg_file):
        pass
    else:
        if os.path.isdir(top_dir + '/ros'):
            pass
        else:
            os.mkdir(top_dir + '/ros')
            
        print('Please set Aliyun access info first.')

        # 输入access-key-id
        access_key_id = raw_input('Enter your access key id:')
        while check_access_info(access_key_id) is False:
            access_key_id = raw_input('Enter your access key id, only characters and numbers:')
        # 输入access-key-secret
        access_key_secret = raw_input('Enter your access key secret, without quote:')
        while check_access_info(access_key_secret) is False:
            access_key_secret = raw_input('Enter your access key secret, only characters and numbers:')
        # 输入region-id
        default_region_id = raw_input('Enter default region id, without quote:')

        # 添加配置项ACCESS
        cf.add_section('ACCESS')
        cf.set('ACCESS', 'ACCESS_KEY_ID', access_key_id)
        cf.set('ACCESS', 'ACCESS_KEY_SECRET', access_key_secret)
        cf.set('ACCESS', 'REGION_ID', default_region_id)
        
        # 添加配置项other:是否json格式输出、是否debug模式
        cf.add_section('OTHER')
        cf.set('OTHER', 'JSON_INDENT', 2)
        cf.set('OTHER', 'DEBUG', False)
        
        # 写出配置文件
        with open(cfg_file, 'w') as configfile:
            cf.write(configfile)

    # 读取配置
    try:
        cf.read(cfg_file)
    except BaseException:
        print("""Config file (%s) error, please write it like:

        [ACCESS]
        ACCESS_KEY_ID = YOUR_KEY_ID
        ACCESS_KEY_SECRET = YOUR_KEY_SECRET
        REGION_ID = cn-beijing

        [OTHER]
        JSON_INDENT = 2
        DEBUG = False
        """ % cfg_file)
        sys.exit(1)

    ACCESS_KEY_ID = cf.get("ACCESS", "ACCESS_KEY_ID")
    ACCESS_KEY_SECRET = cf.get("ACCESS", "ACCESS_KEY_SECRET")
    if region_id is None:
        REGION_ID = cf.get("ACCESS", "REGION_ID")
    else:
        REGION_ID = region_id

    JSON_INDENT = int(cf.get("OTHER", "JSON_INDENT"))
    ROS_DEBUG = bool(cf.get("OTHER", "DEBUG") == 'True')

       # 创建连接
    client = AcsClient(
        ACCESS_KEY_ID,
        ACCESS_KEY_SECRET,
        REGION_ID
    )

    if ROS_DEBUG:
        current_conf()


# 验证输入的access信息
def check_access_info(info):
    """
    Check if access info only has characters and numbers
    """
    match = re.search('^[A-Za-z0-9]+$', info)

    if match:
        return True
    else:
        return False
utils.py
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception import error_code, error_msg
import ros.apps.config as connect
import sys
import json
import urllib2

reload(sys)
sys.setdefaultencoding('utf-8')

# 输出错误
def print_error(data):
    """
    Output error response from aliyun server
    :param data: response body in json
    :return: None
    """

    for (k, v) in data.items():
        print('%-20s:  %s' % (k, v))

# 从指定地址读取template
def read_template(template_url):
    """
    Get template content, support local file and online url
    :param template_url: the url of the template
    :return: template content
    """
    if template_url.startswith('http'):
        try:
            response = urllib2.urlopen(template_url)
            return response.read()
        except Exception as e:
            print('Something wrong:\n%s' % str(e))
            sys.exit(1)
    else:
        try:
            with open(template_url, 'r') as file_object:
                file_context = file_object.read()
            return file_context
        except Exception as e:
            print('Something wrong:\n%s' % str(e))
            sys.exit(1)


def alignment(s, space, align='left'):
    """
    In python 2.x, make Chinese characters keep align
    :param str: input str
    :param space: width of the str
    :param align: left\right\center
    :return: aligned str
    """
    length = len(s.encode('gb2312'))
    space = space - length if space >= length else 0
    if align == 'left':
        s = s + ' ' * space
    elif align == 'right':
        s = ' ' * space + s
    elif align == 'center':
        s = ' ' * (space // 2) + s + ' ' * (space - space // 2)
    return s


# 发送请求
def send_req(req):
    """
    Send ros request
    :param req: request
    :return: None
    """
    req.set_accept_format("JSON")

    if connect.ROS_DEBUG:
        print('[DEBUG] Send request:\n %s\n' % req)

    try:
        status, headers, body = get_raw_resp(req)
    except Exception, e:
        print('Something wrong:\n%s' % str(e))
        sys.exit(1)

    return status, headers, body

#处理响应内容
def deal_resp(status, headers, body, print_response):
    """
    Output response
    :param status: status code
    :param headers: response header
    :param body: response body
    :param print_response: print function
    :return: None
    """

    if connect.ROS_DEBUG:
        print('[DEBUG] Response status:\n %s\n' % status)
        print('[DEBUG] Response headers:\n %s\n' % headers)
        print('[DEBUG] Response body:\n %s\n' % body)

    try:
        data = json.loads(body)
        if 200 <= status < 300:
            print("[Succeed]")
            print_response(data)
        else:
            print("[Failed]")
            print_error(data)
    except Exception, e:
        print("[Error]")
        print('Something wrong:\n%s' % str(e))
        sys.exit(1)


# 获取原生响应
def get_raw_resp(request):
    """
    Get RAW response of aliyunsdk
    :param client: aliyunsdk client
    :param request: request to send
    :return: None
    """

    client = connect.client

    endpoint = client._resolve_endpoint(request)
    http_response = client._make_http_response(endpoint, request)
    if client._url_test_flag:
        raise ClientException("URLTestFlagIsSet", http_response.get_url())

    # Do the actual network thing
    try:
        status, headers, body = http_response.get_response_object()
        return status, headers, body
    except IOError as e:
        raise ClientException(
            error_code.SDK_SERVER_UNREACHABLE,
            error_msg.get_msg('SDK_SERVER_UNREACHABLE') + ': ' + str(e))
    except AttributeError:
        raise ClientException(
            error_code.SDK_INVALID_REQUEST,
            error_msg.get_msg('SDK_INVALID_REQUEST'))


def recursively_print(data, flag=True, indent=0):
    """
    Print dict\list recursively
    :param data: data to print
    :param flag: whether need to use indentation
    :param indent: passed father level's indent
    :return: None
    """
    if isinstance(data, list):
        for item in data:
            print('')
            recursively_print(item, False, indent + 1)

    elif isinstance(data, dict):
        for (k, v) in data.items():
            if indent == 0:
                print '\n\n===================================================\n',
            elif indent == 1:
                print '\n\n    -----------------------------------------------\n',
            print('')
            recursively_print(k, False, indent)
            print':  ',
            recursively_print(v, True, indent + 1)

    else:
        data_out = str(data)
        pre = ''
        if not flag:
            pre = '    '
        for i in range(0, indent):
            data_out = pre + data_out
        print data_out,


if __name__ == '__main__':
    resp = read_template('http://ros-template.cn-hangzhou.oss.aliyun-inc.com/ecs_vpc_instance.json')
    print(resp)

3、rosstack\

abandon_stack_command.py 废弃资源栈
from aliyunsdkros.request.v20150901 import AbandonStackRequest

import ros.apps.config as connect
import ros.apps.utils as utils
import json
import sys

reload(sys)
sys.setdefaultencoding('utf-8')


def setup(subparsers):
    # 设置命令
    parser = subparsers.add_parser('abandon-stack', help='Abandon the specified stack')
    # 设置可选参数: regionID、stackName、stackID
    parser.add_argument('--region-id', help='The region that is associated with the stack', required=True)
    parser.add_argument('--stack-name', help='The name that is associated with the stack', required=True)
    parser.add_argument('--stack-id', help='The id that is associated with the stack', required=True)
    # 指定abandon_stack为默认调用函数
    parser.set_defaults(func=abandon_stack)


def abandon_stack(args):
    # 根据参数创建请求
    req = prepare_request(args)
    # 获取返回结果:状态码、响应头、body
    status, headers, body = utils.send_req(req)
    # 处理返回结果(status, headers, body,回调函数)
    utils.deal_resp(status, headers, body, print_response)


def prepare_request(args):
    # 创建废弃资源栈的请求
    req = AbandonStackRequest.AbandonStackRequest()
    
    # 设置headers:regionID
    req.set_headers({'x-acs-region-id': args.region_id})
    # 设置资源栈name
    req.set_StackName(args.stack_name)
    # 设置资源栈ID
    req.set_StackId(args.stack_id)
    
    # 返回请求
    return req

def print_response(data):
    #if connect.JSON_FORM:
    jsonDumpsIndentStr = json.dumps(data, indent=connect.JSON_INDENT, ensure_ascii=False, sort_keys=True)
    print(jsonDumpsIndentStr)
create_stack_command.py 创建资源栈

from aliyunsdkros.request.v20150901 import CreateStacksRequest

import ros.apps.config as connect
import ros.apps.utils as utils
import json
import sys

reload(sys)
sys.setdefaultencoding('utf-8')


def setup(subparsers):
    # create a parser for the 'create-stack' command
    parser = subparsers.add_parser('create-stack', help='Creates a stack as specified in the template')
    # 添加可选参数regionID
    parser.add_argument('--region-id', help='The region that is associated with the stack')
    # 添加可选参数stack-name
    parser.add_argument('--stack-name', help='The name that is associated with the stack', required=True)
    # 添加可选参数stack-name
    parser.add_argument('--template-url', help='Location of file containing the template body', required=True)
    # 创建资源栈需要输入的参数列表 语法:key=value,key=value
    parser.add_argument('--parameters', help='A list of Parameter structures that specify input parameters for the stack. Synatax: key=value,key=value')
    # 创建失败是否回滚
    parser.add_argument('--disable-rollback', help='Set to true to disable rollback of the stack if stack creation failed', default=True, type=bool)
    # 超时时间 -单位minutes int 默认60min
    parser.add_argument('--timeout-in-minutes', help='The amount of time that can pass before the stack status becomes CREATE_FAILED', default=60, type=int)

    parser.set_defaults(func=create_stack)

 
def create_stack(args):
    req = prepare_request(args)
    status, headers, body = utils.send_req(req)
    utils.deal_resp(status, headers, body, print_response)


def prepare_request(args):
    req = CreateStacksRequest.CreateStacksRequest()
    
    # 如果没有指定regionID,则使用默认配置的regionID
    if args.region_id is not None:
        req.set_headers({'x-acs-region-id': args.region_id})
    else:
        req.set_headers({'x-acs-region-id': connect.REGION_ID})

    content = {}
    content['Name'] = args.stack_name
    
    # 通过templateURL获取Template,支持http和本地文件
    file_context = utils.read_template(args.template_url)
    content['Template'] = file_context

    content['DisableRollback'] = args.disable_rollback
    content['TimeoutMins'] = args.timeout_in_minutes

    # 处理parameters为dict
    ps = {}
    if args.parameters is not None:
        s = args.parameters.split(',')
        for item in s:
            pair = item.split('=')
            ps[pair[0]] = pair[1]

    content['Parameters'] = ps

    jsonDumpsIndentStr = json.dumps(content, indent=connect.JSON_INDENT, ensure_ascii=False, sort_keys=True)
    # print(jsonDumpsIndentStr)
    req.set_content(jsonDumpsIndentStr)

    return req


def print_response(data):
    # 根据配置 是否以json格式输出结果
    if connect.JSON_FORM:
        jsonDumpsIndentStr = json.dumps(data, indent=connect.JSON_INDENT, ensure_ascii=False, sort_keys=True)
        print(jsonDumpsIndentStr)
    else:
        for (k, v) in data.items():
            print('%-20s:  %s' % (k, v))
其他命令文件类似,均省略
 类似资料: