def common_params_for_list(args, fields, field_labels): params = {} if args.marker is not None: params['marker'] = args.marker if args.limit is not None: params['limit'] = args.limit if args.sort_key is not None: # Support using both heading and field name for sort_key fields_map = dict(zip(field_labels, fields)) fields_map.update(zip(fields, fields)) try: sort_key = fields_map[args.sort_key] except KeyError: raise exc.CommandError( _("%(sort_key)s is not a valid field for sorting, " "valid are %(valid)s") % { 'sort_key': args.sort_key, 'valid': list(fields_map) }) params['sort_key'] = sort_key if args.sort_dir is not None: if args.sort_dir not in ('asc', 'desc'): raise exc.CommandError( _("%s is not valid value for sort direction, " "valid are 'asc' and 'desc'") % args.sort_dir) params['sort_dir'] = args.sort_dir params['detail'] = args.detail return params
def main(self, argv): # Parse args once to find version parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) self._setup_debugging(options.debug) # build available subcommands based on version api_version = options.ironic_api_version subcommand_parser = self.get_subcommand_parser(api_version) self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: self.do_help(options) return 0 elif argv[0] == 'bash-completion': self._bash_completion() return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with help command right away. if args.func == self.do_help: self.do_help(args) return 0 if not (args.os_auth_token and args.ironic_url): if not args.os_username: raise exc.CommandError( _("You must provide a username via " "either --os-username or via " "env[OS_USERNAME]")) if not args.os_password: raise exc.CommandError( _("You must provide a password via " "either --os-password or via " "env[OS_PASSWORD]")) if not (args.os_tenant_id or args.os_tenant_name): raise exc.CommandError( _("You must provide a tenant_id via " "either --os-tenant-id or via " "env[OS_TENANT_ID]")) if not args.os_auth_url: raise exc.CommandError( _("You must provide an auth url via " "either --os-auth-url or via " "env[OS_AUTH_URL]")) client = iroclient.get_client(api_version, **(args.__dict__)) try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError(_("Invalid OpenStack Identity credentials"))
def _check_version(self, api_version): """Validate the supplied API (micro)version. :param api_version: API version as a string ("1", "1.x" or "latest") :returns: tuple (major version, version string) """ if api_version in ('1', 'latest'): return (1, LATEST_VERSION) else: try: versions = tuple(int(i) for i in api_version.split('.')) except ValueError: versions = () if not versions or len(versions) > 2: msg = _("The requested API version %(ver)s is an unexpected " "format. Acceptable formats are 'X', 'X.Y', or the " "literal string 'latest'.") % { 'ver': api_version } raise exc.CommandError(msg) if versions == (1, 0): os_ironic_api_version = None else: os_ironic_api_version = api_version api_major_version = versions[0] return (api_major_version, os_ironic_api_version)
def _discover_auth_versions(self, 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. # Let's try to figure out the API version from the original 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: # 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. %s') % auth_url raise exc.CommandError(msg) return (v2_auth_url, v3_auth_url)
def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) client = self.app.client_manager.baremetal params = {} if parsed_args.limit is not None and parsed_args.limit < 0: raise exc.CommandError( _('Expected non-negative --limit, got %s') % parsed_args.limit) params['limit'] = parsed_args.limit params['marker'] = parsed_args.marker for field in ('node', 'resource_class', 'state', 'owner'): value = getattr(parsed_args, field) if value is not None: params[field] = value if parsed_args.long: columns = res_fields.ALLOCATION_DETAILED_RESOURCE.fields labels = res_fields.ALLOCATION_DETAILED_RESOURCE.labels elif parsed_args.fields: fields = itertools.chain.from_iterable(parsed_args.fields) resource = res_fields.Resource(list(fields)) columns = resource.fields labels = resource.labels params['fields'] = columns else: columns = res_fields.ALLOCATION_RESOURCE.fields labels = res_fields.ALLOCATION_RESOURCE.labels self.log.debug("params(%s)", params) data = client.allocation.list(**params) data = oscutils.sort_items(data, parsed_args.sort) return (labels, (oscutils.get_item_properties(s, columns) for s in data))
def do_node_set_power_state(cc, args): """Power a node on or off or reboot.""" try: cc.node.set_power_state(args.node, args.power_state, args.soft, timeout=args.power_timeout) except ValueError as e: raise exc.CommandError(six.text_type(e))
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) client = self.app.client_manager.baremetal columns = res_fields.NODE_RESOURCE params = {} if parsed_args.limit is not None and parsed_args.limit < 0: raise exc.CommandError( _('Expected non-negative --limit, got %s') % parsed_args.limit) params['limit'] = parsed_args.limit params['marker'] = parsed_args.marker if parsed_args.associated: params['associated'] = parsed_args.associated if parsed_args.maintenance: params['maintenance'] = parsed_args.maintenance if parsed_args.long: columns = res_fields.NODE_DETAILED_RESOURCE params['detail'] = parsed_args.long self.log.debug("params(%s)" % params) data = client.node.list(**params) data = oscutils.sort_items(data, parsed_args.sort) return (columns.labels, (oscutils.get_item_properties( s, columns.fields, formatters={'Properties': oscutils.format_dict}, ) for s in data))
def bool_argument_value(arg_name, bool_str, strict=True, default=False): """Returns the Boolean represented by bool_str. Returns the Boolean value for the argument named arg_name. The value is represented by the string bool_str. If the string is an invalid Boolean string: if strict is True, a CommandError exception is raised; otherwise the default value is returned. :param arg_name: The name of the argument :param bool_str: The string representing a Boolean value :param strict: Used if the string is invalid. If True, raises an exception. If False, returns the default value. :param default: The default value to return if the string is invalid and not strict :returns: the Boolean value represented by bool_str or the default value if bool_str is invalid and strict is False :raises CommandError: if bool_str is an invalid Boolean string """ try: val = strutils.bool_from_string(bool_str, strict, default) except ValueError as e: raise exc.CommandError(_("argument %(arg)s: %(err)s.") % {'arg': arg_name, 'err': e}) return val
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) client = self.app.client_manager.baremetal columns = res_fields.CHASSIS_RESOURCE.fields labels = res_fields.CHASSIS_RESOURCE.labels params = {} if parsed_args.limit is not None and parsed_args.limit < 0: raise exc.CommandError( _('Expected non-negative --limit, got %s') % parsed_args.limit) params['limit'] = parsed_args.limit params['marker'] = parsed_args.marker if parsed_args.long: params['detail'] = parsed_args.long columns = res_fields.CHASSIS_DETAILED_RESOURCE.fields labels = res_fields.CHASSIS_DETAILED_RESOURCE.labels elif parsed_args.fields: params['detail'] = False fields = itertools.chain.from_iterable(parsed_args.fields) resource = res_fields.Resource(list(fields)) columns = resource.fields labels = resource.labels params['fields'] = columns self.log.debug("params(%s)" % params) data = client.chassis.list(**params) data = oscutils.sort_items(data, parsed_args.sort) return (labels, (oscutils.get_item_properties( s, columns, formatters={'Properties': oscutils.format_dict}, ) for s in data))
def _check_version(self, api_version): if api_version == 'latest': return LATEST_API_VERSION else: try: versions = tuple(int(i) for i in api_version.split('.')) except ValueError: versions = () if len(versions) == 1: # Default value of ironic_api_version is '1'. # If user not specify the value of api version, not passing # headers at all. os_ironic_api_version = None elif len(versions) == 2: os_ironic_api_version = api_version # In the case of '1.0' if versions[1] == 0: os_ironic_api_version = None else: msg = _("The requested API version %(ver)s is an unexpected " "format. Acceptable formats are 'X', 'X.Y', or the " "literal string '%(latest)s'." ) % {'ver': api_version, 'latest': 'latest'} raise exc.CommandError(msg) api_major_version = versions[0] return (api_major_version, os_ironic_api_version)
def common_params_for_list(args, fields, field_labels): """Generate 'params' dict that is common for every 'list' command. :param args: arguments from command line. :param fields: possible fields for sorting. :param field_labels: possible field labels for sorting. :returns: a dict with params to pass to the client method. """ params = {} if args.marker is not None: params['marker'] = args.marker if args.limit is not None: if args.limit < 0: raise exc.CommandError( _('Expected non-negative --limit, got %s') % args.limit) params['limit'] = args.limit if args.sort_key is not None: # Support using both heading and field name for sort_key fields_map = dict(zip(field_labels, fields)) fields_map.update(zip(fields, fields)) try: sort_key = fields_map[args.sort_key] except KeyError: raise exc.CommandError( _("%(sort_key)s is an invalid field for sorting, " "valid values for --sort-key are: %(valid)s") % { 'sort_key': args.sort_key, 'valid': list(fields_map) }) params['sort_key'] = sort_key if args.sort_dir is not None: if args.sort_dir not in ('asc', 'desc'): raise exc.CommandError( _("%s is an invalid value for sort direction, " "valid values for --sort-dir are: 'asc', 'desc'") % args.sort_dir) params['sort_dir'] = args.sort_dir params['detail'] = args.detail requested_fields = args.fields[0] if args.fields else None if requested_fields is not None: params['fields'] = requested_fields return params
def make_configdrive(path): """Make the config drive file. :param path: The directory containing the config drive files. :returns: A gzipped and base64 encoded configdrive string. """ # Make sure path it's readable if not os.access(path, os.R_OK): raise exc.CommandError(_('The directory "%s" is not readable') % path) with tempfile.NamedTemporaryFile() as tmpfile: with tempfile.NamedTemporaryFile() as tmpzipfile: publisher = 'ironicclient-configdrive 0.1' try: p = subprocess.Popen(['genisoimage', '-o', tmpfile.name, '-ldots', '-allow-lowercase', '-allow-multidot', '-l', '-publisher', publisher, '-quiet', '-J', '-r', '-V', 'config-2', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except OSError as e: raise exc.CommandError( _('Error generating the config drive. Make sure the ' '"genisoimage" tool is installed. Error: %s') % e) stdout, stderr = p.communicate() if p.returncode != 0: raise exc.CommandError( _('Error generating the config drive.' 'Stdout: "%(stdout)s". Stderr: %(stderr)s') % {'stdout': stdout, 'stderr': stderr}) # Compress file tmpfile.seek(0) g = gzip.GzipFile(fileobj=tmpzipfile, mode='wb') shutil.copyfileobj(tmpfile, g) g.close() tmpzipfile.seek(0) return base64.b64encode(tmpzipfile.read())
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 args_array_to_patch(op, attributes): patch = [] for attr in attributes: # Sanitize if not attr.startswith('/'): attr = '/' + attr if op in ['add', 'replace']: try: path, value = attr.split("=", 1) patch.append({'op': op, 'path': path, 'value': value}) except ValueError: raise exc.CommandError( _('Attributes must be a list of ' 'PATH=VALUE not "%s"') % attr) elif op == "remove": # For remove only the key is needed patch.append({'op': op, 'path': attr}) else: raise exc.CommandError(_('Unknown PATCH operation: %s') % op) return patch
def args_array_to_dict(kwargs, key_to_convert): values_to_convert = kwargs.get(key_to_convert) if values_to_convert: try: kwargs[key_to_convert] = dict( v.split("=", 1) for v in values_to_convert) except ValueError: raise exc.CommandError( _('%(key)s must be a list of KEY=VALUE not "%(values)s"') % { 'key': key_to_convert, 'values': values_to_convert }) return kwargs
def check_for_invalid_fields(fields, valid_fields): """Check for invalid fields. :param fields: A list of fields specified by the user. :param valid_fields: A list of valid fields. :raises CommandError: If invalid fields were specified by the user. """ if not fields: return invalid_fields = set(fields) - set(valid_fields) if invalid_fields: raise exc.CommandError( _('Invalid field(s) requested: %(invalid)s. Valid fields ' 'are: %(valid)s.') % {'invalid': ', '.join(invalid_fields), 'valid': ', '.join(valid_fields)})
def args_array_to_patch(op, attributes): patch = [] for attr in attributes: # Sanitize if not attr.startswith('/'): attr = '/' + attr if op in ['add', 'replace']: path, value = split_and_deserialize(attr) patch.append({'op': op, 'path': path, 'value': value}) elif op == "remove": # For remove only the key is needed patch.append({'op': op, 'path': attr}) else: raise exc.CommandError(_('Unknown PATCH operation: %s') % op) return patch
def take_action(self, parsed_args): self.log.debug("take_action(%s)", parsed_args) baremetal_client = self.app.client_manager.baremetal if parsed_args.boot_index is not None and parsed_args.boot_index < 0: raise exc.CommandError( _('Expected non-negative --boot-index, got %s') % parsed_args.boot_index) properties = [] if parsed_args.node_uuid: properties.extend( utils.args_array_to_patch( 'add', ["node_uuid=%s" % parsed_args.node_uuid])) if parsed_args.volume_type: properties.extend( utils.args_array_to_patch( 'add', ["volume_type=%s" % parsed_args.volume_type])) if parsed_args.boot_index: properties.extend( utils.args_array_to_patch( 'add', ["boot_index=%s" % parsed_args.boot_index])) if parsed_args.volume_id: properties.extend( utils.args_array_to_patch( 'add', ["volume_id=%s" % parsed_args.volume_id])) if parsed_args.properties: properties.extend( utils.args_array_to_patch( 'add', ["properties/" + x for x in parsed_args.properties])) if parsed_args.extra: properties.extend( utils.args_array_to_patch( 'add', ["extra/" + x for x in parsed_args.extra])) if properties: baremetal_client.volume_target.update(parsed_args.volume_target, properties) else: self.log.warning("Please specify what to set.")
def split_and_deserialize(string): """Split and try to JSON deserialize a string. Gets a string with the KEY=VALUE format, split it (using '=' as the separator) and try to JSON deserialize the VALUE. :returns: A tuple of (key, value). """ try: key, value = string.split("=", 1) except ValueError: raise exc.CommandError(_('Attributes must be a list of ' 'PATH=VALUE not "%s"') % string) try: value = json.loads(value) except ValueError: pass return (key, value)
def _get_keystone_auth(self, session, auth_url, **kwargs): # FIXME(dhu): this code should come from keystoneclient # discover the supported keystone versions using the given url (v2_auth_url, v3_auth_url) = self._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 = self._get_keystone_v3_auth(v3_auth_url, **kwargs) else: auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs) elif v3_auth_url: # support only v3 auth = self._get_keystone_v3_auth(v3_auth_url, **kwargs) elif v2_auth_url: # support only v2 auth = self._get_keystone_v2_auth(v2_auth_url, **kwargs) else: msg = _('Unable to determine the Keystone version ' 'to authenticate with using the given ' 'auth_url.') raise exc.CommandError(msg) return auth
def take_action(self, parsed_args): super(ProvisionStateWithWait, self).take_action(parsed_args) self.log.debug("take_action(%s)", parsed_args) if (parsed_args.wait_timeout is None): return baremetal_client = self.app.client_manager.baremetal wait_args = v1_utils.PROVISION_ACTIONS.get( parsed_args.provision_state) if wait_args is None: # This should never happen in reality, but checking just in case raise exc.CommandError( _("'--wait is not supported for provision state '%s'") % parsed_args.provision_state) print(_('Waiting for provision state %(state)s on node %(node)s') % {'state': wait_args['expected_state'], 'node': parsed_args.node}) baremetal_client.node.wait_for_provision_state( parsed_args.node, timeout=parsed_args.wait_timeout, **wait_args)
def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) baremetal_client = self.app.client_manager.baremetal if parsed_args.boot_index < 0: raise exc.CommandError( _('Expected non-negative --boot-index, got %s') % parsed_args.boot_index) field_list = [ 'extra', 'volume_type', 'properties', 'boot_index', 'node_uuid', 'volume_id', 'uuid' ] fields = dict((k, v) for (k, v) in vars(parsed_args).items() if k in field_list and v is not None) fields = utils.args_array_to_dict(fields, 'properties') fields = utils.args_array_to_dict(fields, 'extra') volume_target = baremetal_client.volume_target.create(**fields) data = dict([(f, getattr(volume_target, f, '')) for f in res_fields.VOLUME_TARGET_DETAILED_RESOURCE.fields ]) return self.dict2columns(data)
def main(self, argv): # TODO(rloo): delete the ironic CLI in the S* cycle. print( 'The "ironic" CLI is deprecated and will be removed in the ' 'S* release. Please use the "openstack baremetal" CLI instead.', file=sys.stderr) # Parse args once to find version parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) self._setup_debugging(options.debug) # build available subcommands based on version (api_major_version, os_ironic_api_version) = (self._check_version( options.ironic_api_version)) subcommand_parser = self.get_subcommand_parser(api_major_version) self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with these commands right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion() return 0 # Assume password auth if it does not seem like none, admin_token or # token auth if not args.endpoint and not (args.token and args.auth_url): if not args.username: raise exc.CommandError( _("You must provide a username via " "either --os-username or via " "env[OS_USERNAME]")) if not args.password: # No password, If we've got a tty, try prompting for it if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty(): # Check for Ctl-D try: args.password = getpass.getpass('OpenStack Password: '******'t have a tty or the # user Ctl-D when prompted. if not args.password: raise exc.CommandError( _("You must provide a password via " "either --os-password, " "env[OS_PASSWORD], " "or prompted response")) if not (args.tenant_id or args.tenant_name or args.project_id or args.project_name): raise exc.CommandError( _("You must provide a project name or" " project id via --os-project-name, --os-project-id," " env[OS_PROJECT_ID] or env[OS_PROJECT_NAME].")) if not args.auth_url: raise exc.CommandError( _("You must provide an auth url via " "either --os-auth-url or via " "env[OS_AUTH_URL]")) if args.max_retries < 0: raise exc.CommandError( _("You must provide value >= 0 for " "--max-retries")) if args.retry_interval < 1: raise exc.CommandError( _("You must provide value >= 1 for " "--retry-interval")) client_args = ('token', 'endpoint', 'username', 'password', 'auth_url', 'project_id', 'project_name', 'tenant_id', 'tenant_name', 'region_name', 'user_domain_id', 'user_domain_name', 'project_domain_id', 'project_domain_name', 'service_type', 'interface', 'max_retries', 'retry_interval', 'timeout', 'insecure') kwargs = {} for key in client_args: value = getattr(args, key) # NOTE(vdrok): check for both None and ''. If the default value # for option is set using cliutils.env function, default empty # value is ''. If the default is not set explicitly, it is None. if value not in (None, ''): kwargs[key] = value # NOTE(vdrok): this is to workaround the fact that these options are # named differently in keystoneauth, depending on whether they are # provided through CLI or loaded from conf options, here we unify them. for cli_ssl_opt, conf_ssl_opt in [('os_cacert', 'cafile'), ('os_cert', 'certfile'), ('os_key', 'keyfile')]: value = getattr(args, cli_ssl_opt) if value not in (None, ''): kwargs[conf_ssl_opt] = value kwargs['os_ironic_api_version'] = os_ironic_api_version client = ironicclient.client.get_client(api_major_version, **kwargs) if options.ironic_api_version in ('1', 'latest'): # Allow negotiating a lower version, if the latest version # supported by the client is higher than the latest version # supported by the server. client.http_client.api_version_select_state = 'default' try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError(_("Invalid OpenStack Identity credentials")) except exc.CommandError as e: subcommand_parser = self.subcommands[args.subparser_name] subcommand_parser.error(e)
def main(self, argv): # Parse args once to find version parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) self._setup_debugging(options.debug) # build available subcommands based on version (api_major_version, os_ironic_api_version) = (self._check_version( options.ironic_api_version)) subcommand_parser = self.get_subcommand_parser(api_major_version) self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with these commands right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion() return 0 if not (args.os_auth_token and (args.ironic_url or args.os_auth_url)): if not args.os_username: raise exc.CommandError( _("You must provide a username via " "either --os-username or via " "env[OS_USERNAME]")) if not args.os_password: # No password, If we've got a tty, try prompting for it if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty(): # Check for Ctl-D try: args.os_password = getpass.getpass( 'OpenStack Password: '******'t have a tty or the # user Ctl-D when prompted. if not args.os_password: raise exc.CommandError( _("You must provide a password via " "either --os-password, " "env[OS_PASSWORD], " "or prompted response")) if not (args.os_tenant_id or args.os_tenant_name or args.os_project_id or args.os_project_name): raise exc.CommandError( _("You must provide a project name or" " project id via --os-project-name, --os-project-id," " env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]. You may" " use os-project and os-tenant interchangeably.")) if not args.os_auth_url: raise exc.CommandError( _("You must provide an auth url via " "either --os-auth-url or via " "env[OS_AUTH_URL]")) if args.max_retries < 0: raise exc.CommandError( _("You must provide value >= 0 for " "--max-retries")) if args.retry_interval < 1: raise exc.CommandError( _("You must provide value >= 1 for " "--retry-interval")) client_args = ('os_auth_token', 'ironic_url', 'os_username', 'os_password', 'os_auth_url', 'os_project_id', 'os_project_name', 'os_tenant_id', 'os_tenant_name', 'os_region_name', 'os_user_domain_id', 'os_user_domain_name', 'os_project_domain_id', 'os_project_domain_name', 'os_service_type', 'os_endpoint_type', 'os_cacert', 'os_cert', 'os_key', 'max_retries', 'retry_interval', 'timeout', 'insecure') kwargs = {} for key in client_args: kwargs[key] = getattr(args, key) kwargs['os_ironic_api_version'] = os_ironic_api_version client = iroclient.get_client(api_major_version, **kwargs) try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError(_("Invalid OpenStack Identity credentials")) except exc.CommandError as e: subcommand_parser = self.subcommands[args.subparser_name] subcommand_parser.error(e)
def check_empty_arg(arg, arg_descriptor): if not arg.strip(): raise exc.CommandError(_('%(arg)s cannot be empty or only have blank' ' spaces') % {'arg': arg_descriptor})
def main(self, argv): # Parse args once to find version parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) self._setup_debugging(options.debug) # build available subcommands based on version (api_major_version, os_ironic_api_version) = ( self._check_version(options.ironic_api_version)) subcommand_parser = self.get_subcommand_parser(api_major_version) self.parser = subcommand_parser # Handle top-level --help/-h before attempting to parse # a command off the command line if options.help or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected args = subcommand_parser.parse_args(argv) # Short-circuit and deal with these commands right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion() return 0 if not (args.os_auth_token and (args.ironic_url or args.os_endpoint)): if not args.os_username: raise exc.CommandError(_("You must provide a username via " "either --os-username or via " "env[OS_USERNAME]")) if not args.os_password: # No password, If we've got a tty, try prompting for it if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty(): # Check for Ctl-D try: args.os_password = getpass.getpass( 'OpenStack Password: '******'t have a tty or the # user Ctl-D when prompted. if not args.os_password: raise exc.CommandError(_("You must provide a password via " "either --os-password, " "env[OS_PASSWORD], " "or prompted response")) if not (args.os_tenant_id or args.os_tenant_name or args.os_project_id or args.os_project_name): raise exc.CommandError( _("You must provide a project name or" " project id via --os-project-name, --os-project-id," " env[OS_PROJECT_ID] or env[OS_PROJECT_NAME]. You may" " use os-project and os-tenant interchangeably.")) if not args.os_auth_url: raise exc.CommandError(_("You must provide an auth url via " "either --os-auth-url or via " "env[OS_AUTH_URL]")) endpoint = args.ironic_url or args.os_endpoint service_type = args.os_service_type or 'baremetal' project_id = args.os_project_id or args.os_tenant_id project_name = args.os_project_name or args.os_tenant_name if (args.os_auth_token and (args.ironic_url or args.os_endpoint)): kwargs = { 'token': args.os_auth_token, 'insecure': args.insecure, 'timeout': args.timeout, 'ca_file': args.os_cacert, 'cert_file': args.os_cert, 'key_file': args.os_key, 'auth_ref': None, } elif (args.os_username and args.os_password and args.os_auth_url and (project_id or project_name)): keystone_session = kssession.Session.load_from_cli_options(args) kwargs = { 'username': args.os_username, 'user_domain_id': args.os_user_domain_id, 'user_domain_name': args.os_user_domain_name, 'password': args.os_password, 'auth_token': args.os_auth_token, 'project_id': project_id, 'project_name': project_name, 'project_domain_id': args.os_project_domain_id, 'project_domain_name': args.os_project_domain_name, } keystone_auth = self._get_keystone_auth(keystone_session, args.os_auth_url, **kwargs) if not endpoint: svc_type = args.os_service_type region_name = args.os_region_name endpoint = keystone_auth.get_endpoint(keystone_session, service_type=svc_type, region_name=region_name) endpoint_type = args.os_endpoint_type or 'publicURL' kwargs = { 'auth_url': args.os_auth_url, 'session': keystone_session, 'auth': keystone_auth, 'service_type': service_type, 'endpoint_type': endpoint_type, 'region_name': args.os_region_name, 'username': args.os_username, 'password': args.os_password, } kwargs['os_ironic_api_version'] = os_ironic_api_version client = iroclient.Client(api_major_version, endpoint, **kwargs) try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError(_("Invalid OpenStack Identity credentials"))