ROS-CLI源码
参考文章:
源码下载:命令行工具源码地址
一、目录结构
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 作为配置文件 |
--json |
以json 格式输出查询信息,否则以阅读格式输出 |
--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))