From b96c15c96fcbcf6af8f5c731406b2feaa3f74810 Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Tue, 10 Jul 2012 13:56:41 +0100 Subject: [PATCH] heat cli : Align resource-list-details usage with other commands Align resource-list-details usage with the other heat commands, and provide better usage info on failure Fixes #156 Change-Id: Id80b377151eca64e5f7dbfb436f5a5da5213c8b3 Signed-off-by: Steven Hardy --- bin/heat | 78 ++++++++++++++++++++++++++++++++++++++++++--------- bin/heat-boto | 63 ++++++++++++++++++++++++++++++++--------- 2 files changed, 114 insertions(+), 27 deletions(-) diff --git a/bin/heat b/bin/heat index 99ca84be..4aa5638c 100755 --- a/bin/heat +++ b/bin/heat @@ -50,6 +50,8 @@ else: if os.access(jeos_path, os.R_OK): break +scriptname = os.path.basename(sys.argv[0]) + gettext.install('heat', unicode=1) from heat import client as heat_client @@ -334,20 +336,74 @@ def stack_resources_list(options, arguments): print result +def _resources_list_details(options, lookup_key='StackName', + lookup_value=None, log_resid=None): + ''' + Helper function to reduce duplication in stack_resources_list_details + Looks up resource details based on StackName or PhysicalResourceId + ''' + c = get_client(options) + parameters = {} + + if lookup_key in ['StackName', 'PhysicalResourceId']: + parameters[lookup_key] = lookup_value + else: + logging.error("Unexpected key %s" % lookup_key) + return + + if log_resid: + parameters['LogicalResourceId'] = log_resid + + try: + result = c.describe_stack_resources(**parameters) + except: + logging.debug("Failed to lookup resource details with key %s:%s" % + (lookup_key, lookup_value)) + return + + return result + + @utils.catch_error('resource-list-details') def stack_resources_list_details(options, arguments): ''' - Display details of all resources in the specified stack. + Display details of resources in the specified stack. + + - If stack name is specified, all associated resources are returned + - If physical resource ID is specified, all associated resources of the + stack the resource belongs to are returned + - You must specify stack name *or* physical resource ID + - You may optionally specify a Logical resource ID to filter the result ''' - c = get_client(options) + usage = ('''Usage: +%s resource-list-details stack_name [logical_resource_id] +%s resource-list-details physical_resource_id [logical_resource_id]''' % + (scriptname, scriptname)) + + try: + name_or_pid = arguments.pop(0) + except IndexError: + logging.error("No valid stack_name or physical_resource_id") + print usage + return + logical_resource_id = arguments.pop(0) if arguments else None - parameters = { - 'StackName': options.stack_name, - 'PhysicalResourceId': options.physical_resource_id, - 'LogicalResourceId': logical_resource_id, - } - result = c.describe_stack_resources(**parameters) - print result + + # Try StackName first as it seems the most likely.. + lookup_keys = ['StackName', 'PhysicalResourceId'] + for key in lookup_keys: + logging.debug("Looking up resources for %s:%s" % (key, name_or_pid)) + result = _resources_list_details(options, lookup_key=key, + lookup_value=name_or_pid, + log_resid=logical_resource_id) + if result: + break + + if result: + print result + else: + logging.error("No valid stack_name or physical_resource_id") + print usage @utils.catch_error('list') @@ -450,10 +506,6 @@ def create_options(parser): parser.add_option('-P', '--parameters', metavar="parameters", default=None, help="Parameter values used to create the stack.") - parser.add_option('-n', '--stack-name', default=None, - help="Name of the queried stack") - parser.add_option('-c', '--physical-resource-id', default=None, - help="Physical ID of the queried resource") def credentials_from_env(): diff --git a/bin/heat-boto b/bin/heat-boto index 40a06ea1..91f15188 100755 --- a/bin/heat-boto +++ b/bin/heat-boto @@ -39,6 +39,8 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), if os.path.exists(os.path.join(possible_topdir, 'heat', '__init__.py')): sys.path.insert(0, possible_topdir) +scriptname = os.path.basename(sys.argv[0]) + gettext.install('heat', unicode=1) import boto @@ -406,18 +408,55 @@ def stack_resources_list(options, arguments): @utils.catch_error('resource-list-details') def stack_resources_list_details(options, arguments): ''' - Display details of all resources in the specified stack. + Display details of resources in the specified stack. + + - If stack name is specified, all associated resources are returned + - If physical resource ID is specified, all associated resources of the + stack the resource belongs to are returned + - You must specify stack name *or* physical resource ID + - You may optionally specify a Logical resource ID to filter the result ''' - c = get_client(options) - logical_resource_id = arguments.pop(0) if arguments else None - if not options.stack_name and not options.physical_resource_id: - logging.error( - "Must specify either stack-name physical-resource-id") + usage = ('''Usage: +%s resource-list-details stack_name [logical_resource_id] +%s resource-list-details physical_resource_id [logical_resource_id]''' % + (scriptname, scriptname)) + + try: + name_or_pid = arguments.pop(0) + except IndexError: + logging.error("Must pass a stack_name or physical_resource_id") + print usage return - result = c.describe_stack_resources(options.stack_name, - logical_resource_id, options.physical_resource_id) - for r in result: - print_stack_resource(r) + + logical_resource_id = arguments.pop(0) if arguments else None + + c = get_client(options) + + # Check if this is a StackName, if not assume it's a physical res ID + # Note this is slower (for the common case, which is probably StackName) + # than just doing a try/catch over the StackName case then retrying + # on failure with name_or_pid as the physical resource ID, however + # boto spews errors when raising an exception so we can't do that + list_stacks = c.list_stacks() + stack_names = [s.stack_name for s in list_stacks] + if name_or_pid in stack_names: + logging.debug("Looking up resources for StackName:%s" % name_or_pid) + result = c.describe_stack_resources(stack_name_or_id=name_or_pid, + logical_resource_id=logical_resource_id) + else: + logging.debug("Looking up resources for PhysicalResourceId:%s" % + name_or_pid) + result = c.describe_stack_resources(stack_name_or_id=None, + logical_resource_id=logical_resource_id, + physical_resource_id=name_or_pid) + + if result: + for r in result: + print_stack_resource(r) + else: + logging.error("Invalid stack_name, physical_resource_id " + + "or logical_resource_id") + print usage @utils.catch_error('list') @@ -525,10 +564,6 @@ def create_options(parser): parser.add_option('-P', '--parameters', metavar="parameters", default=None, help="Parameter values used to create the stack.") - parser.add_option('-n', '--stack-name', default=None, - help="Name of the queried stack") - parser.add_option('-c', '--physical-resource-id', default=None, - help="Physical ID of the queried resource") def credentials_from_env(): -- 2.45.2