def do_resource_signal(hc, args): '''Send a signal to a resource.''' fields = {'stack_id': args.id, 'resource_name': args.resource} data = args.data data_file = args.data_file if data and data_file: raise exc.CommandError('Can only specify one of data and data-file') if data_file: data_url = template_utils.normalise_file_path_to_url(data_file) data = request.urlopen(data_url).read() if data: if isinstance(data, six.binary_type): data = data.decode('utf-8') try: data = jsonutils.loads(data) except ValueError as ex: raise exc.CommandError('Data should be in JSON format: %s' % ex) if not isinstance(data, dict): raise exc.CommandError('Data should be a JSON dict') fields['data'] = data try: hc.resources.signal(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack or resource not found: %s %s' % (args.id, args.resource))
def get_template_contents(template_file=None, template_url=None, template_object=None, object_request=None, files=None, existing=False, fetch_child=True): is_object = False # Transform a bare file path to a file:// URL. if template_file: template_url = utils.normalise_file_path_to_url(template_file) if template_url: tpl = request.urlopen(template_url).read() elif template_object: is_object = True template_url = template_object tpl = object_request and object_request('GET', template_object) elif existing: return {}, None else: raise exc.CommandError( _('Need to specify exactly one of ' '[%(arg1)s, %(arg2)s or %(arg3)s]' ' or %(arg4)s') % { 'arg1': '--template-file', 'arg2': '--template-url', 'arg3': '--template-object', 'arg4': '--existing' }) if not tpl: raise exc.CommandError( _('Could not fetch template from %s') % template_url) try: if isinstance(tpl, six.binary_type): tpl = tpl.decode('utf-8') template = template_format.parse(tpl) except ValueError as e: raise exc.CommandError( _('Error parsing template %(url)s %(error)s') % { 'url': template_url, 'error': e }) if files is None: files = {} if fetch_child: tmpl_base_url = utils.base_url_for_url(template_url) resolve_template_get_files(template, files, tmpl_base_url, is_object, object_request) return files, template
def _get_keystone_auth(self, session, auth_url, **kwargs): """ Figure out whether to use v2 or v3 of the Keystone API, and return the auth object. This function is based, with minor changes, on the official OpenStack Heat client's shell implementation. Specifically, python-heatclient/heatclient/shell.py. """ v2_auth_url = None v3_auth_url = None try: ks_discover = discover.Discover(session=session, auth_url=auth_url) v2_auth_url = ks_discover.url_for('2.0') v3_auth_url = ks_discover.url_for('3.0') except ks_exc.ClientException: # If discovery is not supported, parse version out of the auth URL. url_parts = urlparse.urlparse(auth_url) (scheme, netloc, path, params, query, fragment) = url_parts path = path.lower() if path.startswith('/v3'): v3_auth_url = auth_url elif path.startswith('/v2'): v2_auth_url = auth_url else: raise heat_exc.CommandError( 'Unable to determine Keystone version.') auth = None if v3_auth_url and v2_auth_url: # Both v2 and v3 are supported. Use v3 only if domain information is # provided. user_domain_name = kwargs.get('user_domain_name', None) user_domain_id = kwargs.get('user_domain_id', None) project_domain_name = kwargs.get('project_domain_name', None) project_domain_id = kwargs.get('project_domain_id', None) if (user_domain_name or user_domain_id or project_domain_name or project_domain_id): auth = self._get_keystone_v3_auth(v3_auth_url, **kwargs) else: auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs) elif v3_auth_url: auth = self._get_keystone_v3_auth(v3_auth_url, **kwargs) elif v2_auth_url: auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs) else: raise heat_exc.CommandError( 'Unable to determine Keystone version.') return auth
def do_stack_adopt(hc, args): '''Adopt a stack.''' env_files, env = template_utils.process_environment_and_files( env_path=args.environment_file) if not args.adopt_file: raise exc.CommandError('Need to specify --adopt-file') adopt_url = template_utils.normalise_file_path_to_url(args.adopt_file) adopt_data = request.urlopen(adopt_url).read() if args.create_timeout: logger.warning('-c/--create-timeout is deprecated, ' 'please use -t/--timeout instead') fields = { 'stack_name': args.name, 'disable_rollback': not (args.enable_rollback), 'adopt_stack_data': adopt_data, 'parameters': utils.format_parameters(args.parameters), 'files': dict(list(env_files.items())), 'environment': env } timeout = args.timeout or args.create_timeout if timeout: fields['timeout_mins'] = timeout hc.stacks.create(**fields) do_stack_list(hc)
def do_event_list(hc, args): '''List events for a stack.''' fields = { 'stack_id': args.id, 'resource_name': args.resource, 'limit': args.limit, 'marker': args.marker, 'filters': utils.format_parameters(args.filters) } try: events = hc.events.list(**fields) except exc.HTTPNotFound as ex: # it could be the stack or resource that is not found # just use the message that the server sent us. raise exc.CommandError(str(ex)) else: fields = [ 'id', 'resource_status_reason', 'resource_status', 'event_time' ] if len(events) >= 1: if hasattr(events[0], 'resource_name'): fields.insert(0, 'resource_name') else: fields.insert(0, 'logical_resource_id') utils.print_list(events, fields, sortby_index=None)
def _discover_auth_versions(session, auth_url): # discover the API versions the server is supporting base on the # given URL v2_auth_url = None v3_auth_url = None try: ks_discover = discover.Discover(session=session, auth_url=auth_url) v2_auth_url = ks_discover.url_for('2.0') v3_auth_url = ks_discover.url_for('3.0') except ks_exc.ClientException: # Identity service may not support discover API version. # Lets trying to figure out the API version from the original URL. path = urlparse.urlparse(auth_url).path path = path.lower() if path.startswith('/v3'): v3_auth_url = auth_url elif path.startswith('/v2'): v2_auth_url = auth_url else: # not enough information to determine the auth version msg = ('Unable to determine the Keystone version ' 'to authenticate with using the given ' 'auth_url. Identity service may not support API ' 'version discovery. Please provide a versioned ' 'auth_url instead.') raise exc.CommandError(msg) return v2_auth_url, v3_auth_url
def _get_keystone_auth(session, auth_url, **kwargs): # discover the supported keystone versions using the given url (v2_auth_url, v3_auth_url) = _discover_auth_versions(session=session, auth_url=auth_url) # Determine which authentication plugin to use. First inspect the # auth_url to see the supported version. If both v3 and v2 are # supported, then use the highest version if possible. auth = None if v3_auth_url and v2_auth_url: user_domain_name = kwargs.get('user_domain_name', None) user_domain_id = kwargs.get('user_domain_id', None) project_domain_name = kwargs.get('project_domain_name', None) project_domain_id = kwargs.get('project_domain_id', None) # support both v2 and v3 auth. Use v3 if domain information is # provided. if (user_domain_name or user_domain_id or project_domain_name or project_domain_id): auth = _get_keystone_v3_auth(v3_auth_url, **kwargs) else: auth = _get_keystone_v2_auth(v2_auth_url, **kwargs) elif v3_auth_url: # support only v3 auth = _get_keystone_v3_auth(v3_auth_url, **kwargs) elif v2_auth_url: # support only v2 auth = _get_keystone_v2_auth(v2_auth_url, **kwargs) else: raise exc.CommandError('Unable to determine the Keystone version ' 'to authenticate with using the given ' 'auth_url.') return auth
def format_parameters(params, parse_semicolon=True): '''Reformat parameters into dict of format expected by the API.''' if not params: return {} if parse_semicolon: # expect multiple invocations of --parameters but fall back # to ; delimited if only one --parameters is specified if len(params) == 1: params = params[0].split(';') parameters = {} for p in params: try: (n, v) = p.split(('='), 1) except ValueError: msg = _('Malformed parameter(%s). Use the key=value format.') % p raise exc.CommandError(msg) if n not in parameters: parameters[n] = v else: if not isinstance(parameters[n], list): parameters[n] = [parameters[n]] parameters[n].append(v) return parameters
def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) client = self.app.client_manager.orchestration fields = { 'stack_id': parsed_args.stack, 'resource_name': parsed_args.resource, 'event_id': parsed_args.event } try: client.stacks.get(parsed_args.stack) client.resources.get(parsed_args.stack, parsed_args.resource) event = client.events.get(**fields) except exc.HTTPNotFound as ex: raise exc.CommandError(str(ex)) formatters = { 'links': heat_utils.link_formatter, 'resource_properties': heat_utils.json_formatter } columns = [] for key in event.to_dict(): columns.append(key) return columns, utils.get_item_properties(event, columns, formatters=formatters)
def find_resource(manager, name_or_id): """Helper for the _find_* methods.""" # first try to get entity as integer id try: if isinstance(name_or_id, int) or name_or_id.isdigit(): return manager.get(int(name_or_id)) except exc.NotFound: pass # now try to get entity as uuid try: uuid.UUID(str(name_or_id)) return manager.get(name_or_id) except (ValueError, exc.NotFound): pass # finally try to find entity by name try: return manager.find(name=name_or_id) except exc.NotFound: msg = _("No %(name)s with a name or ID of " "'%(name_or_id)s' exists.") % \ { 'name': manager.resource_class.__name__.lower(), 'name_or_id': name_or_id } raise exc.CommandError(msg)
def do_stack_cancel_update(hc, args): '''Cancel currently running update of the stack.''' fields = {'stack_id': args.id} try: hc.actions.cancel_update(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: do_stack_list(hc)
def do_action_check(hc, args): '''Check that stack resources are in expected states.''' fields = {'stack_id': args.id} try: hc.actions.check(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: do_stack_list(hc)
def do_action_resume(hc, args): '''Resume the stack.''' fields = {'stack_id': args.id} try: hc.actions.resume(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: do_stack_list(hc)
def do_stack_abandon(hc, args): '''Abandon the stack.''' fields = {'stack_id': args.id} try: stack = hc.stacks.abandon(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: print(jsonutils.dumps(stack, indent=2))
def do_resource_type_show(hc, args): '''Show the resource type.''' try: resource_type = hc.resource_types.get(args.resource_type) except exc.HTTPNotFound: raise exc.CommandError('Resource Type not found: %s' % args.resource_type) else: print(jsonutils.dumps(resource_type, indent=2))
def do_resource_metadata(hc, args): '''List resource metadata.''' fields = {'stack_id': args.id, 'resource_name': args.resource} try: metadata = hc.resources.metadata(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack or resource not found: %s %s' % (args.id, args.resource)) else: print(jsonutils.dumps(metadata, indent=2))
def do_help(self, args): """Display help about this program or one of its subcommands.""" if getattr(args, 'command', None): if args.command in self.subcommands: self.subcommands[args.command].print_help() else: raise exc.CommandError("'%s' is not a valid subcommand" % args.command) else: self.parser.print_help()
def do_output_show(hc, args): '''Show a specific stack output.''' try: stack = hc.stacks.get(stack_id=args.id) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: for output in stack.to_dict().get('outputs', []): if output['output_key'] == args.output: if 'output_error' in output: msg = "Error: %s" % output['output_error'] raise exc.CommandError(msg) else: value = output['output_value'] break else: return print(jsonutils.dumps(value, indent=2, ensure_ascii=False))
def _get_nested_ids(hc, stack_id): nested_ids = [] try: resources = hc.resources.list(stack_id=stack_id) except exc.HTTPNotFound: raise exc.CommandError(_('Stack not found: %s') % stack_id) for r in resources: nested_id = utils.resource_nested_identifier(r) if nested_id: nested_ids.append(nested_id) return nested_ids
def read_url_content(url): try: content = request.urlopen(url).read() except error.URLError: raise exc.CommandError('Could not fetch contents for %s' % url) if content: try: content.decode('utf-8') except ValueError: content = base64.encodestring(content) return content
def get_hook_type_via_status(hc, stack_id): # Figure out if the hook should be pre-create or pre-update based # on the stack status, also sanity assertions that we're in-progress. try: stack = hc.stacks.get(stack_id=stack_id) except exc.HTTPNotFound: raise exc.CommandError(_('Stack not found: %s') % stack_id) else: if 'IN_PROGRESS' not in stack.stack_status: raise exc.CommandError( _('Stack status %s not IN_PROGRESS') % stack.stack_status) if 'CREATE' in stack.stack_status: hook_type = 'pre-create' elif 'UPDATE' in stack.stack_status: hook_type = 'pre-update' else: raise exc.CommandError( _('Unexpected stack status %s, ' 'only create/update supported') % stack.stack_status) return hook_type
def do_resource_template(hc, args): '''Generate a template based on a resource.''' fields = {'resource_name': args.resource} try: template = hc.resources.generate_template(**fields) except exc.HTTPNotFound: raise exc.CommandError('Resource %s not found.' % args.resource) else: if args.format: print(utils.format_output(template, format=args.format)) else: print(utils.format_output(template))
def build_signal_id(hc, args): if args.signal_transport != 'TEMP_URL_SIGNAL': return if args.os_no_client_auth: raise exc.CommandError( _('Cannot use --os-no-client-auth, auth required to create ' 'a Swift TempURL.')) swift_client = create_swift_client(hc.http_client.auth, hc.http_client.session, args) return create_temp_url(swift_client, args.name, args.timeout)
def do_template_show(hc, args): '''Get the template for the specified stack.''' fields = {'stack_id': args.id} try: template = hc.stacks.template(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: if 'heat_template_version' in template: print(yaml.safe_dump(template, indent=2)) else: print(jsonutils.dumps(template, indent=2, ensure_ascii=False))
def get_template_contents(template_file=None, template_url=None, template_object=None, object_request=None, files=None): # Transform a bare file path to a file:// URL. if template_file: template_url = normalise_file_path_to_url(template_file) if template_url: tpl = request.urlopen(template_url).read() elif template_object: template_url = template_object tpl = object_request and object_request('GET', template_object) else: raise exc.CommandError('Need to specify exactly one of ' '--template-file, --template-url ' 'or --template-object') if not tpl: raise exc.CommandError('Could not fetch template from %s' % template_url) try: if isinstance(tpl, six.binary_type): tpl = tpl.decode('utf-8') template = template_format.parse(tpl) except ValueError as e: raise exc.CommandError('Error parsing template %s %s' % (template_url, e)) tmpl_base_url = base_url_for_url(template_url) if files is None: files = {} resolve_template_get_files(template, files, tmpl_base_url) resolve_template_type(template, files, tmpl_base_url) return files, template
def _get_stack_events(hc, stack_id, event_args): event_args['stack_id'] = stack_id try: events = hc.events.list(**event_args) except exc.HTTPNotFound as ex: # it could be the stack or resource that is not found # just use the message that the server sent us. raise exc.CommandError(str(ex)) else: # Show which stack the event comes from (for nested events) for e in events: e.stack_name = stack_id.split("/")[0] return events
def do_stack_abandon(hc, args): '''Abandon the stack. This will delete the record of the stack from Heat, but will not delete any of the underlying resources. Prints an adoptable JSON representation of the stack to stdout on success. ''' fields = {'stack_id': args.id} try: stack = hc.stacks.abandon(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: print(jsonutils.dumps(stack, indent=2))
def _get_stack_events(h_client, stack_id, event_args): ''' Get event for stack ''' event_args['stack_id'] = stack_id event_args['resource_name'] = None try: events = h_client.events.list(**event_args) except exc.HTTPNotFound as ex: raise exc.CommandError(str(ex)) else: for event in events: event.stack_name = stack_id.split('/')[0] return events
def do_stack_abandon(hc, args): '''Abandon the stack. This will delete the record of the stack from Heat, but will not delete any of the underlying resources. Prints an adoptable JSON representation of the stack to stdout or a file on success. ''' fields = {'stack_id': args.id} try: stack = hc.stacks.abandon(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack not found: %s' % args.id) else: result = jsonutils.dumps(stack, indent=2) if args.output_file is not None: try: with open(args.output_file, "w") as f: f.write(result) except IOError as err: print(result) raise exc.CommandError(str(err)) else: print(result)
def do_resource_show(hc, args): '''Describe the resource.''' fields = {'stack_id': args.id, 'resource_name': args.resource} try: resource = hc.resources.get(**fields) except exc.HTTPNotFound: raise exc.CommandError('Stack or resource not found: %s %s' % (args.id, args.resource)) else: formatters = { 'links': utils.link_formatter, 'required_by': utils.newline_list_formatter } utils.print_dict(resource.to_dict(), formatters=formatters)