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 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 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 return params
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: raise exc.CommandError('Unable to determine the Keystone version ' 'to authenticate with using the given ' 'auth_url.') return auth
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.saladier_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 # 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.saladier_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]") endpoint = args.saladier_url service_type = args.os_service_type or 'ci' 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.saladier_url: 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, } client = salclient.Client(api_version, endpoint, **kwargs) try: args.func(client, args) except exc.Unauthorized: raise exc.CommandError("Invalid OpenStack Identity credentials")