Blacken code

Another library down.

Change-Id: Id29f29331ba994a1f09376763702fcca82ec6f1c
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane 2023-08-30 19:27:40 +01:00
parent 6304b384bb
commit ab7cdb4c25
37 changed files with 1294 additions and 901 deletions

View File

@ -31,12 +31,19 @@ def run_apidoc(app):
return
run_already = True
package_dir = path.abspath(path.join(app.srcdir, '..', '..',
'osc_lib'))
package_dir = path.abspath(path.join(app.srcdir, '..', '..', 'osc_lib'))
source_dir = path.join(app.srcdir, 'api')
apidoc.main(['apidoc', package_dir, '-f',
'-H', 'osc-lib Modules',
'-o', source_dir])
apidoc.main(
[
'apidoc',
package_dir,
'-f',
'-H',
'osc-lib Modules',
'-o',
source_dir,
]
)
def setup(app):

View File

@ -17,21 +17,24 @@ import sys
# NOTE(blk-u): Path for our Sphinx extension, remove when
# https://launchpad.net/bugs/1260495 is fixed.
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
sys.path.insert(
0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
)
# -- General configuration ----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.todo',
'openstackdocstheme',
'sphinxcontrib.apidoc',
]
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.todo',
'openstackdocstheme',
'sphinxcontrib.apidoc',
]
# openstackdocstheme options
openstackdocs_repo_name = 'openstack/osc-lib'
@ -39,13 +42,13 @@ openstackdocs_auto_name = False
openstackdocs_use_storyboard = True
# Add any paths that contain templates here, relative to this directory.
#templates_path = ['_templates']
# templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@ -55,13 +58,13 @@ project = 'OpenStackClient CLI Base'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@ -69,18 +72,18 @@ exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'native'
@ -93,76 +96,76 @@ modindex_common_prefix = ['osc_lib.']
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#html_theme_path = ["."]
#html_theme = '_theme'
# html_theme_path = ["."]
# html_theme = '_theme'
html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# html_theme_options = {}
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']
# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenStackCommandLineClientdoc'
@ -171,54 +174,55 @@ htmlhelp_basename = 'OpenStackCommandLineClientdoc'
# -- Options for LaTeX output -------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual])
# .
latex_documents = [
('index', 'OpenStackCommandLineClient.tex',
'OpenStack Command Line Client Documentation',
'OpenStack'),
(
'index',
'OpenStackCommandLineClient.tex',
'OpenStack Command Line Client Documentation',
'OpenStack',
),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# latex_domain_indices = True
# -- Options for manual page output -------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
#man_pages = []
# man_pages = []
# If true, show URL addresses after external links.
#man_show_urls = False
# man_show_urls = False
# -- Options for Texinfo output -----------------------------------------------
@ -227,21 +231,25 @@ latex_documents = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'OpenStackCommandLineClient',
'OpenStack Command Line Client Documentation',
'OpenStack', 'OpenStackCommandLineClient',
'One line description of project.',
'Miscellaneous'),
(
'index',
'OpenStackCommandLineClient',
'OpenStack Command Line Client Documentation',
'OpenStack',
'OpenStackCommandLineClient',
'One line description of project.',
'Miscellaneous',
),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# texinfo_show_urls = 'footnote'
# -- Options for sphinxcontrib.apidoc ----------------------------------------

View File

@ -42,11 +42,7 @@ class BaseAPI(object):
HEADER_NAME = "OpenStack-API-Version"
def __init__(
self,
session=None,
service_type=None,
endpoint=None,
**kwargs
self, session=None, service_type=None, endpoint=None, **kwargs
):
"""Base object that contains some common API objects and methods
@ -140,13 +136,7 @@ class BaseAPI(object):
# The basic action methods all take a Session and return dict/lists
def create(
self,
url,
session=None,
method=None,
**params
):
def create(self, url, session=None, method=None, **params):
"""Create a new resource
:param string url:
@ -166,12 +156,7 @@ class BaseAPI(object):
except json.JSONDecodeError:
return ret
def delete(
self,
url,
session=None,
**params
):
def delete(self, url, session=None, **params):
"""Delete a resource
:param string url:
@ -292,9 +277,7 @@ class BaseAPI(object):
if len(data) > 1:
msg = _("Multiple %(resource)s exist with %(attr)s='%(value)s'")
raise exceptions.CommandError(
msg % {'resource': resource,
'attr': attr,
'value': value}
msg % {'resource': resource, 'attr': attr, 'value': value}
)
# Search by id
@ -304,17 +287,10 @@ class BaseAPI(object):
return data[0]
msg = _("No %(resource)s with a %(attr)s or ID of '%(value)s' found")
raise exceptions.CommandError(
msg % {'resource': resource,
'attr': attr,
'value': value}
msg % {'resource': resource, 'attr': attr, 'value': value}
)
def find_bulk(
self,
path,
headers=None,
**kwargs
):
def find_bulk(self, path, headers=None, **kwargs):
"""Bulk load and filter locally
:param string path:
@ -342,11 +318,7 @@ class BaseAPI(object):
return ret
def find_one(
self,
path,
**kwargs
):
def find_one(self, path, **kwargs):
"""Find a resource by name or ID
:param string path:
@ -390,7 +362,8 @@ class BaseAPI(object):
try:
ret = self._request(
'GET', "/%s/%s" % (path, value),
'GET',
"/%s/%s" % (path, value),
headers=headers,
).json()
if isinstance(ret, dict):
@ -404,11 +377,7 @@ class BaseAPI(object):
if attr:
kwargs = {attr: value}
try:
ret = self.find_one(
path,
headers=headers,
**kwargs
)
ret = self.find_one(path, headers=headers, **kwargs)
except (
exceptions.NotFound,
ksa_exceptions.NotFound,

View File

@ -53,7 +53,8 @@ def get_options_list():
os_name = o.name.lower().replace('_', '-')
os_env_name = 'OS_' + os_name.upper().replace('-', '_')
OPTIONS_LIST.setdefault(
os_name, {'env': os_env_name, 'help': ''},
os_name,
{'env': os_env_name, 'help': ''},
)
# TODO(mhu) simplistic approach, would be better to only add
# help texts if they vary from one auth plugin to another
@ -67,19 +68,23 @@ def get_options_list():
def check_valid_authorization_options(options, auth_plugin_name):
"""Validate authorization options, and provide helpful error messages."""
if (options.auth.get('project_id') and not
options.auth.get('domain_id') and not
options.auth.get('domain_name') and not
options.auth.get('project_name') and not
options.auth.get('tenant_id') and not
options.auth.get('tenant_name')):
raise exc.CommandError(_(
'Missing parameter(s): '
'Set either a project or a domain scope, but not both. Set a '
'project scope with --os-project-name, OS_PROJECT_NAME, or '
'auth.project_name. Alternatively, set a domain scope with '
'--os-domain-name, OS_DOMAIN_NAME or auth.domain_name.'
))
if (
options.auth.get('project_id')
and not options.auth.get('domain_id')
and not options.auth.get('domain_name')
and not options.auth.get('project_name')
and not options.auth.get('tenant_id')
and not options.auth.get('tenant_name')
):
raise exc.CommandError(
_(
'Missing parameter(s): '
'Set either a project or a domain scope, but not both. Set a '
'project scope with --os-project-name, OS_PROJECT_NAME, or '
'auth.project_name. Alternatively, set a domain scope with '
'--os-domain-name, OS_DOMAIN_NAME or auth.domain_name.'
)
)
def check_valid_authentication_options(options, auth_plugin_name):
@ -102,31 +107,34 @@ def check_valid_authentication_options(options, auth_plugin_name):
# when no auth params are passed in, user advised to use os-cloud
if not options.auth and auth_plugin_name != 'none':
msgs.append(_(
'Set a cloud-name with --os-cloud or OS_CLOUD'
))
msgs.append(_('Set a cloud-name with --os-cloud or OS_CLOUD'))
else:
if ('password' in plugin_opts and not
(options.auth.get('username') or options.auth.get('user_id'))):
msgs.append(_(
'Set a username with --os-username, OS_USERNAME,'
' or auth.username'
' or set a user-id with --os-user-id, OS_USER_ID,'
' or auth.user_id'
))
if 'password' in plugin_opts and not (
options.auth.get('username') or options.auth.get('user_id')
):
msgs.append(
_(
'Set a username with --os-username, OS_USERNAME,'
' or auth.username'
' or set a user-id with --os-user-id, OS_USER_ID,'
' or auth.user_id'
)
)
if 'auth_url' in plugin_opts and not options.auth.get('auth_url'):
msgs.append(_(
'Set an authentication URL, with --os-auth-url,'
' OS_AUTH_URL or auth.auth_url'
))
msgs.append(
_(
'Set an authentication URL, with --os-auth-url,'
' OS_AUTH_URL or auth.auth_url'
)
)
if 'url' in plugin_opts and not options.auth.get('url'):
msgs.append(_(
'Set a service URL, with --os-url, OS_URL or auth.url'
))
msgs.append(
_('Set a service URL, with --os-url, OS_URL or auth.url')
)
if 'token' in plugin_opts and not options.auth.get('token'):
msgs.append(_(
'Set a token with --os-token, OS_TOKEN or auth.token'
))
msgs.append(
_('Set a token with --os-token, OS_TOKEN or auth.token')
)
if msgs:
raise exc.CommandError(
@ -147,20 +155,21 @@ def build_auth_plugins_option_parser(parser):
metavar='<auth-type>',
dest='auth_type',
default=utils.env('OS_AUTH_TYPE'),
help=_('Select an authentication type. Available types: %s.'
' Default: selected based on --os-username/--os-token'
' (Env: OS_AUTH_TYPE)') % ', '.join(available_plugins),
choices=available_plugins
help=_(
'Select an authentication type. Available types: %s.'
' Default: selected based on --os-username/--os-token'
' (Env: OS_AUTH_TYPE)'
)
% ', '.join(available_plugins),
choices=available_plugins,
)
# Maintain compatibility with old tenant env vars
envs = {
'OS_PROJECT_NAME': utils.env(
'OS_PROJECT_NAME',
default=utils.env('OS_TENANT_NAME')
'OS_PROJECT_NAME', default=utils.env('OS_TENANT_NAME')
),
'OS_PROJECT_ID': utils.env(
'OS_PROJECT_ID',
default=utils.env('OS_TENANT_ID')
'OS_PROJECT_ID', default=utils.env('OS_TENANT_ID')
),
}
for o in get_options_list():
@ -174,7 +183,8 @@ def build_auth_plugins_option_parser(parser):
OPTIONS_LIST[o]['env'],
utils.env(OPTIONS_LIST[o]['env']),
),
help=_('%(help)s\n(Env: %(env)s)') % {
help=_('%(help)s\n(Env: %(env)s)')
% {
'help': OPTIONS_LIST[o]['help'],
'env': OPTIONS_LIST[o]['env'],
},
@ -196,10 +206,14 @@ def build_auth_plugins_option_parser(parser):
return parser
def get_keystone2keystone_auth(local_auth, service_provider,
project_id=None, project_name=None,
project_domain_id=None,
project_domain_name=None):
def get_keystone2keystone_auth(
local_auth,
service_provider,
project_id=None,
project_name=None,
project_domain_id=None,
project_domain_name=None,
):
"""Return Keystone 2 Keystone authentication for service provider.
:param local_auth: authentication to use with the local Keystone
@ -210,9 +224,11 @@ def get_keystone2keystone_auth(local_auth, service_provider,
:param project_domain_name: name of domain to in the service provider
:return: Keystone2Keystone auth object for service provider
"""
return k2k.Keystone2Keystone(local_auth,
service_provider,
project_id=project_id,
project_name=project_name,
project_domain_id=project_domain_id,
project_domain_name=project_domain_name)
return k2k.Keystone2Keystone(
local_auth,
service_provider,
project_id=project_id,
project_name=project_name,
project_domain_id=project_domain_id,
project_domain_name=project_domain_name,
)

View File

@ -60,8 +60,11 @@ def simple_filter(
if attr in d:
# Searching data fields
search_value = d[attr]
elif (property_field and property_field in d and
isinstance(d[property_field], dict)):
elif (
property_field
and property_field in d
and isinstance(d[property_field], dict)
):
# Searching a properties field - do this separately because
# we don't want to fail over to checking the fields if a
# property name is given.

View File

@ -26,7 +26,6 @@ LOG = logging.getLogger(__name__)
# Sublcass OpenStackConfig in order to munge config values
# before auth plugins are loaded
class OSC_Config(config.OpenStackConfig):
def _auth_select_default_plugin(self, config):
"""Select a default plugin based on supplied arguments
@ -66,7 +65,7 @@ class OSC_Config(config.OpenStackConfig):
Migrated from auth.build_auth_params()
"""
if ('auth_type' in config and config['auth_type'].startswith("v2")):
if 'auth_type' in config and config['auth_type'].startswith("v2"):
if 'project_id' in config['auth']:
config['auth']['tenant_id'] = config['auth']['project_id']
if 'project_name' in config['auth']:
@ -82,8 +81,9 @@ class OSC_Config(config.OpenStackConfig):
# NOTE(hieulq): If USER_DOMAIN_NAME, USER_DOMAIN_ID, PROJECT_DOMAIN_ID
# or PROJECT_DOMAIN_NAME is present and API_VERSION is 2.0, then
# ignore all domain related configs.
if (str(config.get('identity_api_version', '')).startswith('2') and
config.get('auth_type').endswith('password')):
if str(config.get('identity_api_version', '')).startswith(
'2'
) and config.get('auth_type').endswith('password'):
domain_props = [
'project_domain_id',
'project_domain_name',
@ -95,12 +95,14 @@ class OSC_Config(config.OpenStackConfig):
if config.get('cloud'):
LOG.warning(
"Ignoring domain related config %s for %s"
"because identity API version is 2.0" % (
prop, config['cloud']))
"because identity API version is 2.0"
% (prop, config['cloud'])
)
else:
LOG.warning(
"Ignoring domain related config %s because"
" identity API version is 2.0" % prop)
" identity API version is 2.0" % prop
)
return config
def _auth_default_domain(self, config):
@ -115,17 +117,18 @@ class OSC_Config(config.OpenStackConfig):
# TODO(mordred): This is a usability improvement that's broadly useful
# We should port it back up into os-client-config.
default_domain = config.get('default_domain', None)
if (identity_version == '3' and
not auth_type.startswith('v2') and
default_domain):
if (
identity_version == '3'
and not auth_type.startswith('v2')
and default_domain
):
# NOTE(stevemar): If PROJECT_DOMAIN_ID or PROJECT_DOMAIN_NAME is
# present, then do not change the behaviour. Otherwise, set the
# PROJECT_DOMAIN_ID to 'OS_DEFAULT_DOMAIN' for better usability.
if (
auth_type in ("password", "v3password", "v3totp") and
not config['auth'].get('project_domain_id') and
not config['auth'].get('project_domain_name')
auth_type in ("password", "v3password", "v3totp")
and not config['auth'].get('project_domain_id')
and not config['auth'].get('project_domain_name')
):
config['auth']['project_domain_id'] = default_domain
@ -136,9 +139,9 @@ class OSC_Config(config.OpenStackConfig):
# TODO(dtroyer): Move this to os-client-config after the plugin has
# been loaded so we can check directly if the options are accepted.
if (
auth_type in ("password", "v3password", "v3totp") and
not config['auth'].get('user_domain_id') and
not config['auth'].get('user_domain_name')
auth_type in ("password", "v3password", "v3totp")
and not config['auth'].get('user_domain_id')
and not config['auth'].get('user_domain_name')
):
config['auth']['user_domain_id'] = default_domain
return config
@ -156,8 +159,9 @@ class OSC_Config(config.OpenStackConfig):
config = self._auth_default_domain(config)
if LOG.isEnabledFor(logging.DEBUG):
LOG.debug("auth_config_hook(): %s",
strutils.mask_password(str(config)))
LOG.debug(
"auth_config_hook(): %s", strutils.mask_password(str(config))
)
return config
def _validate_auth(self, config, loader, fixed_argparse=None):
@ -176,7 +180,8 @@ class OSC_Config(config.OpenStackConfig):
winning_value = self._find_winning_auth_value(p_opt, config)
if not winning_value:
winning_value = self._find_winning_auth_value(
p_opt, config['auth'])
p_opt, config['auth']
)
# if the plugin tells us that this value is required
# then error if it's doesn't exist now
@ -184,7 +189,8 @@ class OSC_Config(config.OpenStackConfig):
msgs.append(
'Missing value {auth_key}'
' required for auth plugin {plugin}'.format(
auth_key=p_opt.name, plugin=config.get('auth_type'),
auth_key=p_opt.name,
plugin=config.get('auth_type'),
)
)
@ -198,17 +204,18 @@ class OSC_Config(config.OpenStackConfig):
# Prefer the plugin configuration dest value if the value's key
# is marked as depreciated.
if p_opt.dest is None:
config['auth'][p_opt.name.replace('-', '_')] = (
winning_value)
config['auth'][
p_opt.name.replace('-', '_')
] = winning_value
else:
config['auth'][p_opt.dest] = winning_value
# See if this needs a prompting
if (
'prompt' in vars(p_opt) and
p_opt.prompt is not None and
p_opt.dest not in config['auth'] and
self._pw_callback is not None
'prompt' in vars(p_opt)
and p_opt.prompt is not None
and p_opt.dest not in config['auth']
and self._pw_callback is not None
):
# Defer these until we know all required opts are present
prompt_options.append(p_opt)

View File

@ -25,14 +25,16 @@ def add_project_owner_option_to_parser(parser):
parser.add_argument(
'--project',
metavar='<project>',
help=_("Owner's project (name or ID)")
help=_("Owner's project (name or ID)"),
)
parser.add_argument(
'--project-domain',
metavar='<project-domain>',
help=_('Domain the project belongs to (name or ID). '
'This can be used in case collisions between project names '
'exist.'),
help=_(
'Domain the project belongs to (name or ID). '
'This can be used in case collisions between project names '
'exist.'
),
)
@ -55,14 +57,15 @@ def find_project(sdk_connection, name_or_id, domain_name_or_id=None):
"""
try:
if domain_name_or_id:
domain = sdk_connection.identity.find_domain(domain_name_or_id,
ignore_missing=False)
domain = sdk_connection.identity.find_domain(
domain_name_or_id, ignore_missing=False
)
domain_id = domain.id
else:
domain_id = None
return sdk_connection.identity.find_project(name_or_id,
ignore_missing=False,
domain_id=domain_id)
return sdk_connection.identity.find_project(
name_or_id, ignore_missing=False, domain_id=domain_id
)
# NOTE: OpenStack SDK raises HttpException for 403 response code.
# There is no specific exception class at now, so we need to catch
# HttpException and check the status code.

View File

@ -84,8 +84,15 @@ class MultiKeyValueAction(argparse.Action):
And comma(',') and equal('=') may not be used in the key or value.
"""
def __init__(self, option_strings, dest, nargs=None,
required_keys=None, optional_keys=None, **kwargs):
def __init__(
self,
option_strings,
dest,
nargs=None,
required_keys=None,
optional_keys=None,
**kwargs
):
"""Initialize the action object, and parse customized options
Required keys and optional keys can be specified when initializing
@ -99,8 +106,9 @@ class MultiKeyValueAction(argparse.Action):
msg = _("Parameter 'nargs' is not allowed, but got %s")
raise ValueError(msg % nargs)
super(MultiKeyValueAction, self).__init__(option_strings,
dest, **kwargs)
super(MultiKeyValueAction, self).__init__(
option_strings, dest, **kwargs
)
# required_keys: A list of keys that is required. None by default.
if required_keys and not isinstance(required_keys, list):
@ -128,10 +136,13 @@ class MultiKeyValueAction(argparse.Action):
"Invalid keys %(invalid_keys)s specified.\n"
"Valid keys are: %(valid_keys)s"
)
raise argparse.ArgumentTypeError(msg % {
'invalid_keys': ', '.join(invalid_keys),
'valid_keys': ', '.join(valid_keys),
})
raise argparse.ArgumentTypeError(
msg
% {
'invalid_keys': ', '.join(invalid_keys),
'valid_keys': ', '.join(valid_keys),
}
)
if self.required_keys:
missing_keys = [k for k in self.required_keys if k not in keys]
@ -140,10 +151,13 @@ class MultiKeyValueAction(argparse.Action):
"Missing required keys %(missing_keys)s.\n"
"Required keys are: %(required_keys)s"
)
raise argparse.ArgumentTypeError(msg % {
'missing_keys': ', '.join(missing_keys),
'required_keys': ', '.join(self.required_keys),
})
raise argparse.ArgumentTypeError(
msg
% {
'missing_keys': ', '.join(missing_keys),
'required_keys': ', '.join(self.required_keys),
}
)
def __call__(self, parser, namespace, values, metavar=None):
# Make sure we have an empty list rather than None
@ -245,10 +259,14 @@ class RangeAction(argparse.Action):
setattr(namespace, self.dest, (int(range[0]), int(range[1])))
else:
msg = _("Invalid range, %(min)s is not less than %(max)s")
raise argparse.ArgumentError(self, msg % {
'min': range[0],
'max': range[1],
})
raise argparse.ArgumentError(
self,
msg
% {
'min': range[0],
'max': range[1],
},
)
else:
# Too many values
msg = _("Invalid range, too many values")

View File

@ -18,7 +18,7 @@
import copy
import logging
from openstack.config import loader as config # noqa
from openstack.config import loader as config # noqa
from openstack import connection
from oslo_utils import strutils
@ -145,13 +145,16 @@ class ClientManager(object):
# Horrible hack alert...must handle prompt for null password if
# password auth is requested.
if (self.auth_plugin_name.endswith('password') and
not self._cli_options.auth.get('password')):
if self.auth_plugin_name.endswith(
'password'
) and not self._cli_options.auth.get('password'):
self._cli_options.auth['password'] = self._pw_callback()
LOG.info('Using auth plugin: %s', self.auth_plugin_name)
LOG.debug('Using parameters %s',
strutils.mask_password(self._cli_options.auth))
LOG.debug(
'Using parameters %s',
strutils.mask_password(self._cli_options.auth),
)
self.auth = self._cli_options.get_auth()
if self._cli_options.service_provider:
@ -161,7 +164,7 @@ class ClientManager(object):
self._cli_options.remote_project_id,
self._cli_options.remote_project_name,
self._cli_options.remote_project_domain_id,
self._cli_options.remote_project_domain_name
self._cli_options.remote_project_domain_name,
)
self.session = self._cli_options.get_session()
@ -193,8 +196,10 @@ class ClientManager(object):
@property
def auth_ref(self):
"""Dereference will trigger an auth if it hasn't already"""
if (not self._auth_required or
self._cli_options.config['auth_type'] == 'none'):
if (
not self._auth_required
or self._cli_options.config['auth_type'] == 'none'
):
# Forcibly skip auth if we know we do not need it
return None
if not self._auth_ref:
@ -230,8 +235,9 @@ class ClientManager(object):
LOG.debug("No service catalog")
return service_available
def get_endpoint_for_service_type(self, service_type, region_name=None,
interface='public'):
def get_endpoint_for_service_type(
self, service_type, region_name=None, interface='public'
):
"""Return the endpoint URL for the service type."""
# Overrides take priority unconditionally
override = self._override_for(service_type)

View File

@ -24,25 +24,26 @@ from osc_lib.i18n import _
class CommandMeta(abc.ABCMeta):
def __new__(mcs, name, bases, cls_dict):
if 'log' not in cls_dict:
cls_dict['log'] = logging.getLogger(
cls_dict['__module__'] + '.' + name)
cls_dict['__module__'] + '.' + name
)
return super(CommandMeta, mcs).__new__(mcs, name, bases, cls_dict)
class Command(command.Command, metaclass=CommandMeta):
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
return super(Command, self).run(parsed_args)
def validate_os_beta_command_enabled(self):
if not self.app.options.os_beta_command:
msg = _('Caution: This is a beta command and subject to '
'change. Use global option --os-beta-command '
'to enable this command.')
msg = _(
'Caution: This is a beta command and subject to '
'change. Use global option --os-beta-command '
'to enable this command.'
)
raise exceptions.CommandError(msg)
def deprecated_option_warning(self, old_option, new_option):

View File

@ -18,4 +18,5 @@ import cliff.commandmanager
class CommandManager(cliff.commandmanager.CommandManager):
"""Noop subclass for transition purposes."""
pass

View File

@ -26,6 +26,7 @@ class AuthorizationFailure(Exception):
class PluginAttributeError(Exception):
"""A plugin threw an AttributeError while being lazily loaded."""
# This *must not* inherit from AttributeError;
# that would defeat the whole purpose.
pass
@ -33,21 +34,25 @@ class PluginAttributeError(Exception):
class NoTokenLookupException(Exception):
"""This does not support looking up endpoints from an existing token."""
pass
class EndpointNotFound(Exception):
"""Could not find Service or Region in Service Catalog."""
pass
class UnsupportedVersion(Exception):
"""The user is trying to use an unsupported version of the API"""
pass
class InvalidValue(Exception):
"""An argument value is not valid: wrong type, out of range, etc"""
message = "Supplied value is not valid"
@ -68,36 +73,42 @@ class ClientException(Exception):
class BadRequest(ClientException):
"""HTTP 400 - Bad request: you sent some malformed data."""
http_status = 400
message = "Bad request"
class Unauthorized(ClientException):
"""HTTP 401 - Unauthorized: bad credentials."""
http_status = 401
message = "Unauthorized"
class Forbidden(ClientException):
"""HTTP 403 - Forbidden: not authorized to access to this resource."""
http_status = 403
message = "Forbidden"
class NotFound(ClientException):
"""HTTP 404 - Not found"""
http_status = 404
message = "Not found"
class Conflict(ClientException):
"""HTTP 409 - Conflict"""
http_status = 409
message = "Conflict"
class OverLimit(ClientException):
"""HTTP 413 - Over limit: reached the API limits for this time period."""
http_status = 413
message = "Over limit"
@ -105,6 +116,7 @@ class OverLimit(ClientException):
# NotImplemented is a python keyword.
class HTTPNotImplemented(ClientException):
"""HTTP 501 - Not Implemented: server does not support this operation."""
http_status = 501
message = "Not Implemented"
@ -115,11 +127,14 @@ class HTTPNotImplemented(ClientException):
# for c in ClientException.__subclasses__())
#
# Instead, we have to hardcode it:
_code_map = dict((c.http_status, c) for c in [
BadRequest,
Unauthorized,
Forbidden,
NotFound,
OverLimit,
HTTPNotImplemented
])
_code_map = dict(
(c.http_status, c)
for c in [
BadRequest,
Unauthorized,
Forbidden,
NotFound,
OverLimit,
HTTPNotImplemented,
]
)

View File

@ -81,8 +81,10 @@ def set_warning_filter(log_level):
class _FileFormatter(logging.Formatter):
"""Customize the logging format for logging handler"""
_LOG_MESSAGE_BEGIN = (
'%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s ')
'%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s '
)
_LOG_MESSAGE_CONTEXT = '[%(cloud)s %(username)s %(project)s] '
_LOG_MESSAGE_END = '%(message)s'
_LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
@ -102,16 +104,17 @@ class _FileFormatter(logging.Formatter):
'username': config.auth.get('username', ''),
}
if context:
self.fmt = (self._LOG_MESSAGE_BEGIN +
(self._LOG_MESSAGE_CONTEXT % context) +
self._LOG_MESSAGE_END)
self.fmt = (
self._LOG_MESSAGE_BEGIN
+ (self._LOG_MESSAGE_CONTEXT % context)
+ self._LOG_MESSAGE_END
)
else:
self.fmt = self._LOG_MESSAGE_BEGIN + self._LOG_MESSAGE_END
logging.Formatter.__init__(self, self.fmt, self._LOG_DATE_FORMAT)
class LogConfigurator(object):
_CONSOLE_MESSAGE_FORMAT = '%(message)s'
def __init__(self, options):
@ -183,7 +186,7 @@ class LogConfigurator(object):
for k in logconfig.keys():
level = log_level_from_string(logconfig[k])
logging.getLogger(k).setLevel(level)
if (highest_level < level):
if highest_level < level:
highest_level = level
self.console_logger.setLevel(highest_level)
if self.file_logger:

View File

@ -63,29 +63,32 @@ def prompt_for_password(prompt=None):
pass
# No password because we did't have a tty or nothing was entered
if not pw:
raise exc.CommandError(_("No password entered, or found via"
" --os-password or OS_PASSWORD"),)
raise exc.CommandError(
_(
"No password entered, or found via"
" --os-password or OS_PASSWORD"
),
)
return pw
class OpenStackShell(app.App):
CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(name)s %(message)s'
log = logging.getLogger(__name__)
timing_data = []
def __init__(
self,
description=None,
version=None,
command_manager=None,
stdin=None,
stdout=None,
stderr=None,
interactive_app_factory=None,
deferred_help=False,
self,
description=None,
version=None,
command_manager=None,
stdin=None,
stdout=None,
stderr=None,
interactive_app_factory=None,
deferred_help=False,
):
# Patch command.Command to add a default auth_required = True
command.Command.auth_required = True
@ -163,10 +166,14 @@ class OpenStackShell(app.App):
# bigger than most big default one (CRITICAL) or something like
# that (PROFILE = 60 for instance), but not sure we need it here.
self.log.warning("Trace ID: %s" % trace_id)
self.log.warning("Short trace ID "
"for OpenTracing-based drivers: %s" % short_id)
self.log.warning("Display trace data with command:\n"
"osprofiler trace show --html %s " % trace_id)
self.log.warning(
"Short trace ID "
"for OpenTracing-based drivers: %s" % short_id
)
self.log.warning(
"Display trace data with command:\n"
"osprofiler trace show --html %s " % trace_id
)
def run_subcommand(self, argv):
self.init_profile()
@ -186,8 +193,8 @@ class OpenStackShell(app.App):
def build_option_parser(self, description, version):
parser = super(OpenStackShell, self).build_option_parser(
description,
version)
description, version
)
# service token auth argument
parser.add_argument(
@ -243,11 +250,11 @@ class OpenStackShell(app.App):
'--os-default-domain',
metavar='<auth-domain>',
dest='default_domain',
default=utils.env(
'OS_DEFAULT_DOMAIN',
default=DEFAULT_DOMAIN),
help=_('Default domain ID, default=%s. '
'(Env: OS_DEFAULT_DOMAIN)') % DEFAULT_DOMAIN,
default=utils.env('OS_DEFAULT_DOMAIN', default=DEFAULT_DOMAIN),
help=_(
'Default domain ID, default=%s. ' '(Env: OS_DEFAULT_DOMAIN)'
)
% DEFAULT_DOMAIN,
)
parser.add_argument(
'--os-interface',
@ -258,18 +265,23 @@ class OpenStackShell(app.App):
# config key 'interface' will be ignored. Use OSC_Config's ctor
# option 'override_defaults' below instead.
default=utils.env('OS_INTERFACE'),
help=_('Select an interface type.'
' Valid interface types: [admin, public, internal].'
' default=%s, (Env: OS_INTERFACE)') % DEFAULT_INTERFACE,
help=_(
'Select an interface type.'
' Valid interface types: [admin, public, internal].'
' default=%s, (Env: OS_INTERFACE)'
)
% DEFAULT_INTERFACE,
)
parser.add_argument(
'--os-service-provider',
metavar='<service_provider>',
dest='service_provider',
default=utils.env('OS_SERVICE_PROVIDER'),
help=_('Authenticate with and perform the command on a service'
' provider using Keystone-to-keystone federation. Must'
' also specify the remote project option.')
help=_(
'Authenticate with and perform the command on a service'
' provider using Keystone-to-keystone federation. Must'
' also specify the remote project option.'
),
)
remote_project_group = parser.add_mutually_exclusive_group()
remote_project_group.add_argument(
@ -277,16 +289,20 @@ class OpenStackShell(app.App):
metavar='<remote_project_name>',
dest='remote_project_name',
default=utils.env('OS_REMOTE_PROJECT_NAME'),
help=_('Project name when authenticating to a service provider'
' if using Keystone-to-Keystone federation.')
help=_(
'Project name when authenticating to a service provider'
' if using Keystone-to-Keystone federation.'
),
)
remote_project_group.add_argument(
'--os-remote-project-id',
metavar='<remote_project_id>',
dest='remote_project_id',
default=utils.env('OS_REMOTE_PROJECT_ID'),
help=_('Project ID when authenticating to a service provider'
' if using Keystone-to-Keystone federation.')
help=_(
'Project ID when authenticating to a service provider'
' if using Keystone-to-Keystone federation.'
),
)
remote_project_domain_group = parser.add_mutually_exclusive_group()
remote_project_domain_group.add_argument(
@ -294,18 +310,22 @@ class OpenStackShell(app.App):
metavar='<remote_project_domain_name>',
dest='remote_project_domain_name',
default=utils.env('OS_REMOTE_PROJECT_DOMAIN_NAME'),
help=_('Domain name of the project when authenticating to a'
' service provider if using Keystone-to-Keystone'
' federation.')
help=_(
'Domain name of the project when authenticating to a'
' service provider if using Keystone-to-Keystone'
' federation.'
),
)
remote_project_domain_group.add_argument(
'--os-remote-project-domain-id',
metavar='<remote_project_domain_id>',
dest='remote_project_domain_id',
default=utils.env('OS_REMOTE_PROJECT_DOMAIN_ID'),
help=_('Domain ID of the project when authenticating to a'
' service provider if using Keystone-to-Keystone'
' federation.')
help=_(
'Domain ID of the project when authenticating to a'
' service provider if using Keystone-to-Keystone'
' federation.'
),
)
parser.add_argument(
'--timing',
@ -345,6 +365,7 @@ class OpenStackShell(app.App):
* ClientManager
"""