Add pre-commit, apply ruff
Signed-off-by: Stephen Finucane <stephenfin@redhat.com> Change-Id: Iedc7653f27dbe9bb77b6d9bb03117a457e195e58
This commit is contained in:
32
.pre-commit-config.yaml
Normal file
32
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: mixed-line-ending
|
||||
args: ['--fix', 'lf']
|
||||
exclude: '.*\.(svg)$'
|
||||
- id: check-byte-order-marker
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-merge-conflict
|
||||
- id: debug-statements
|
||||
- id: check-yaml
|
||||
files: .*\.(yaml|yml)$
|
||||
exclude: '^zuul.d/.*$'
|
||||
- repo: https://github.com/PyCQA/doc8
|
||||
rev: v1.1.2
|
||||
hooks:
|
||||
- id: doc8
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.12
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: ['--fix', '--unsafe-fixes']
|
||||
- id: ruff-format
|
||||
- repo: https://opendev.org/openstack/hacking
|
||||
rev: 7.0.0
|
||||
hooks:
|
||||
- id: hacking
|
||||
additional_dependencies: []
|
||||
exclude: '^(doc|releasenotes|tools)/.*$'
|
||||
@@ -13,4 +13,4 @@ Pull requests submitted through GitHub will be ignored.
|
||||
|
||||
Bugs should be filed on Launchpad, not GitHub:
|
||||
|
||||
https://bugs.launchpad.net/os-client-config
|
||||
https://bugs.launchpad.net/os-client-config
|
||||
|
||||
20
doc/source/conf.py
Executable file → Normal file
20
doc/source/conf.py
Executable file → Normal file
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
@@ -43,8 +42,8 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'os-client-config'
|
||||
copyright = u'2015, various OpenStack developers'
|
||||
project = 'os-client-config'
|
||||
copyright = '2015, various OpenStack developers'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
@@ -66,17 +65,20 @@ pygments_style = 'native'
|
||||
html_theme = 'openstackdocs'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
htmlhelp_basename = f'{project}doc'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation', 'manual'),
|
||||
(
|
||||
'index',
|
||||
f'{project}.tex',
|
||||
f'{project} Documentation',
|
||||
'OpenStack Foundation',
|
||||
'manual',
|
||||
),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
# intersphinx_mapping = {'http://docs.python.org/': None}
|
||||
|
||||
@@ -26,15 +26,16 @@ _config = None
|
||||
|
||||
|
||||
def get_config(
|
||||
service_key=None, options=None,
|
||||
app_name=None, app_version=None,
|
||||
**kwargs):
|
||||
service_key=None, options=None, app_name=None, app_version=None, **kwargs
|
||||
):
|
||||
load_yaml_config = kwargs.pop('load_yaml_config', True)
|
||||
global _config
|
||||
if not _config:
|
||||
_config = OpenStackConfig(
|
||||
load_yaml_config=load_yaml_config,
|
||||
app_name=app_name, app_version=app_version)
|
||||
app_name=app_name,
|
||||
app_version=app_version,
|
||||
)
|
||||
if options:
|
||||
_config.register_argparse_arguments(options, sys.argv, service_key)
|
||||
parsed_options = options.parse_known_args(sys.argv)
|
||||
@@ -45,9 +46,13 @@ def get_config(
|
||||
|
||||
|
||||
def make_rest_client(
|
||||
service_key, options=None,
|
||||
app_name=None, app_version=None, version=None,
|
||||
**kwargs):
|
||||
service_key,
|
||||
options=None,
|
||||
app_name=None,
|
||||
app_version=None,
|
||||
version=None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Simple wrapper function. It has almost no features.
|
||||
|
||||
This will get you a raw requests Session Adapter that is mounted
|
||||
@@ -61,9 +66,12 @@ def make_rest_client(
|
||||
at OpenStack REST APIs with a properly configured keystone session.
|
||||
"""
|
||||
cloud = get_config(
|
||||
service_key=service_key, options=options,
|
||||
app_name=app_name, app_version=app_version,
|
||||
**kwargs)
|
||||
service_key=service_key,
|
||||
options=options,
|
||||
app_name=app_name,
|
||||
app_version=app_version,
|
||||
**kwargs,
|
||||
)
|
||||
return cloud.get_session_client(service_key, version=version)
|
||||
|
||||
|
||||
@@ -98,6 +106,7 @@ def make_sdk(options=None, **kwargs):
|
||||
:rtype: :class:`~openstack.connection.Connection`
|
||||
"""
|
||||
from openstack import connection
|
||||
|
||||
cloud = get_config(options=options, **kwargs)
|
||||
return connection.from_config(cloud_config=cloud, options=options)
|
||||
|
||||
@@ -110,5 +119,6 @@ def make_shade(options=None, **kwargs):
|
||||
:rtype: :class:`~shade.OpenStackCloud`
|
||||
"""
|
||||
import shade
|
||||
|
||||
cloud = get_config(options=options, **kwargs)
|
||||
return shade.OpenStackCloud(cloud_config=cloud, **kwargs)
|
||||
|
||||
@@ -26,39 +26,35 @@ def _get_client(service_key):
|
||||
class_mapping = constructors.get_constructor_mapping()
|
||||
if service_key not in class_mapping:
|
||||
raise exceptions.OpenStackConfigException(
|
||||
"Service {service_key} is unkown. Please pass in a client"
|
||||
" constructor or submit a patch to os-client-config".format(
|
||||
service_key=service_key))
|
||||
f"Service {service_key} is unkown. Please pass in a client"
|
||||
" constructor or submit a patch to os-client-config"
|
||||
)
|
||||
mod_name, ctr_name = class_mapping[service_key].rsplit('.', 1)
|
||||
lib_name = mod_name.split('.')[0]
|
||||
try:
|
||||
mod = importlib.import_module(mod_name)
|
||||
except ImportError:
|
||||
raise exceptions.OpenStackConfigException(
|
||||
"Client for '{service_key}' was requested, but"
|
||||
" {mod_name} was unable to be imported. Either import"
|
||||
f"Client for '{service_key}' was requested, but"
|
||||
f" {mod_name} was unable to be imported. Either import"
|
||||
" the module yourself and pass the constructor in as an argument,"
|
||||
" or perhaps you do not have python-{lib_name} installed.".format(
|
||||
service_key=service_key,
|
||||
mod_name=mod_name,
|
||||
lib_name=lib_name))
|
||||
f" or perhaps you do not have python-{lib_name} installed."
|
||||
)
|
||||
try:
|
||||
ctr = getattr(mod, ctr_name)
|
||||
except AttributeError:
|
||||
raise exceptions.OpenStackConfigException(
|
||||
"Client for '{service_key}' was requested, but although"
|
||||
" {mod_name} imported fine, the constructor at {fullname}"
|
||||
f"Client for '{service_key}' was requested, but although"
|
||||
f" {mod_name} imported fine, the constructor at {class_mapping[service_key]}"
|
||||
" as not found. Please check your installation, we have no"
|
||||
" clue what is wrong with your computer.".format(
|
||||
service_key=service_key,
|
||||
mod_name=mod_name,
|
||||
fullname=class_mapping[service_key]))
|
||||
" clue what is wrong with your computer."
|
||||
)
|
||||
return ctr
|
||||
|
||||
|
||||
class CloudConfig(cloud_region.CloudRegion):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CloudConfig, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.log = _log.setup_logging(__name__)
|
||||
|
||||
def __getattr__(self, key):
|
||||
@@ -74,8 +70,9 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
|
||||
def insert_user_agent(self):
|
||||
self._keystone_session.additional_user_agent.append(
|
||||
('os-client-config', os_client_config.__version__))
|
||||
super(CloudConfig, self).insert_user_agent()
|
||||
('os-client-config', os_client_config.__version__)
|
||||
)
|
||||
super().insert_user_agent()
|
||||
|
||||
@property
|
||||
def region(self):
|
||||
@@ -88,9 +85,16 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
return self.get_cache_expirations()
|
||||
|
||||
def get_legacy_client(
|
||||
self, service_key, client_class=None, interface_key=None,
|
||||
pass_version_arg=True, version=None, min_version=None,
|
||||
max_version=None, **kwargs):
|
||||
self,
|
||||
service_key,
|
||||
client_class=None,
|
||||
interface_key=None,
|
||||
pass_version_arg=True,
|
||||
version=None,
|
||||
min_version=None,
|
||||
max_version=None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Return a legacy OpenStack client object for the given config.
|
||||
|
||||
Most of the OpenStack python-*client libraries have the same
|
||||
@@ -136,7 +140,8 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
interface = self.get_interface(service_key)
|
||||
# trigger exception on lack of service
|
||||
endpoint = self.get_session_endpoint(
|
||||
service_key, min_version=min_version, max_version=max_version)
|
||||
service_key, min_version=min_version, max_version=max_version
|
||||
)
|
||||
endpoint_override = self.get_endpoint(service_key)
|
||||
|
||||
if service_key == 'object-store':
|
||||
@@ -145,14 +150,17 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
os_options=dict(
|
||||
service_type=self.get_service_type(service_key),
|
||||
object_storage_url=endpoint_override,
|
||||
region_name=self.region))
|
||||
region_name=self.region,
|
||||
),
|
||||
)
|
||||
else:
|
||||
constructor_kwargs = dict(
|
||||
session=self.get_session(),
|
||||
service_name=self.get_service_name(service_key),
|
||||
service_type=self.get_service_type(service_key),
|
||||
endpoint_override=endpoint_override,
|
||||
region_name=self.region)
|
||||
region_name=self.region,
|
||||
)
|
||||
|
||||
if service_key == 'image':
|
||||
# os-client-config does not depend on glanceclient, but if
|
||||
@@ -160,6 +168,7 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
# would need to do if they were requesting 'image' - then
|
||||
# they necessarily have glanceclient installed
|
||||
from glanceclient.common import utils as glance_utils
|
||||
|
||||
endpoint, detected_version = glance_utils.strip_version(endpoint)
|
||||
# If the user has passed in a version, that's explicit, use it
|
||||
if not version:
|
||||
@@ -176,6 +185,7 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
version = self.get_api_version(service_key)
|
||||
if not version and service_key == 'volume':
|
||||
from cinderclient import client as cinder_client
|
||||
|
||||
version = cinder_client.get_volume_api_from_url(endpoint)
|
||||
# Temporary workaround while we wait for python-openstackclient
|
||||
# to be able to handle 2.0 which is what neutronclient expects
|
||||
@@ -198,14 +208,16 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
constructor_kwargs['version'] = version
|
||||
if min_version and min_version > float(version):
|
||||
raise exceptions.OpenStackConfigVersionException(
|
||||
"Minimum version {min_version} requested but {version}"
|
||||
" found".format(min_version=min_version, version=version),
|
||||
version=version)
|
||||
f"Minimum version {min_version} requested but {version}"
|
||||
" found",
|
||||
version=version,
|
||||
)
|
||||
if max_version and max_version < float(version):
|
||||
raise exceptions.OpenStackConfigVersionException(
|
||||
"Maximum version {max_version} requested but {version}"
|
||||
" found".format(max_version=max_version, version=version),
|
||||
version=version)
|
||||
f"Maximum version {max_version} requested but {version}"
|
||||
" found",
|
||||
version=version,
|
||||
)
|
||||
if service_key == 'database':
|
||||
# TODO(mordred) Remove when https://review.openstack.org/314032
|
||||
# has landed and released. We're passing in a Session, but the
|
||||
@@ -217,8 +229,11 @@ class CloudConfig(cloud_region.CloudRegion):
|
||||
if not interface_key:
|
||||
if service_key in ('image', 'key-manager'):
|
||||
interface_key = 'interface'
|
||||
elif (service_key == 'identity'
|
||||
and version and version.startswith('3')):
|
||||
elif (
|
||||
service_key == 'identity'
|
||||
and version
|
||||
and version.startswith('3')
|
||||
):
|
||||
interface_key = 'interface'
|
||||
else:
|
||||
interface_key = 'endpoint_type'
|
||||
|
||||
@@ -23,7 +23,6 @@ from os_client_config import defaults
|
||||
|
||||
|
||||
class OpenStackConfig(loader.OpenStackConfig):
|
||||
|
||||
_cloud_region_class = cloud_config.CloudConfig
|
||||
_defaults_module = defaults
|
||||
|
||||
@@ -59,10 +58,10 @@ if __name__ == '__main__':
|
||||
if len(sys.argv) == 1:
|
||||
print_cloud = True
|
||||
elif len(sys.argv) == 3 and (
|
||||
sys.argv[1] == cloud.name and sys.argv[2] == cloud.region):
|
||||
sys.argv[1] == cloud.name and sys.argv[2] == cloud.region
|
||||
):
|
||||
print_cloud = True
|
||||
elif len(sys.argv) == 2 and (
|
||||
sys.argv[1] == cloud.name):
|
||||
elif len(sys.argv) == 2 and (sys.argv[1] == cloud.name):
|
||||
print_cloud = True
|
||||
|
||||
if print_cloud:
|
||||
|
||||
@@ -17,7 +17,8 @@ import os
|
||||
import threading
|
||||
|
||||
_json_path = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), 'constructors.json')
|
||||
os.path.dirname(os.path.realpath(__file__)), 'constructors.json'
|
||||
)
|
||||
_class_mapping = None
|
||||
_class_mapping_lock = threading.Lock()
|
||||
|
||||
@@ -30,7 +31,7 @@ def get_constructor_mapping():
|
||||
if _class_mapping is not None:
|
||||
return _class_mapping.copy()
|
||||
tmp_class_mapping = {}
|
||||
with open(_json_path, 'r') as json_file:
|
||||
with open(_json_path) as json_file:
|
||||
tmp_class_mapping.update(json.load(json_file))
|
||||
_class_mapping = tmp_class_mapping
|
||||
return tmp_class_mapping.copy()
|
||||
|
||||
@@ -17,7 +17,8 @@ import os
|
||||
from openstack.config import defaults
|
||||
|
||||
_json_path = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), 'defaults.json')
|
||||
os.path.dirname(os.path.realpath(__file__)), 'defaults.json'
|
||||
)
|
||||
|
||||
|
||||
def get_defaults():
|
||||
|
||||
@@ -21,5 +21,5 @@ class OpenStackConfigVersionException(OpenStackConfigException):
|
||||
"""A version was requested that is different than what was found."""
|
||||
|
||||
def __init__(self, version):
|
||||
super(OpenStackConfigVersionException, self).__init__()
|
||||
super().__init__()
|
||||
self.version = version
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
@@ -98,30 +96,37 @@ USER_CONF = {
|
||||
'domain_id': '6789',
|
||||
'project_domain_id': '123456789',
|
||||
},
|
||||
'networks': [{
|
||||
'name': 'a-public',
|
||||
'routes_externally': True,
|
||||
'nat_source': True,
|
||||
}, {
|
||||
'name': 'another-public',
|
||||
'routes_externally': True,
|
||||
'default_interface': True,
|
||||
}, {
|
||||
'name': 'a-private',
|
||||
'routes_externally': False,
|
||||
}, {
|
||||
'name': 'another-private',
|
||||
'routes_externally': False,
|
||||
'nat_destination': True,
|
||||
}, {
|
||||
'name': 'split-default',
|
||||
'routes_externally': True,
|
||||
'routes_ipv4_externally': False,
|
||||
}, {
|
||||
'name': 'split-no-default',
|
||||
'routes_ipv6_externally': False,
|
||||
'routes_ipv4_externally': True,
|
||||
}],
|
||||
'networks': [
|
||||
{
|
||||
'name': 'a-public',
|
||||
'routes_externally': True,
|
||||
'nat_source': True,
|
||||
},
|
||||
{
|
||||
'name': 'another-public',
|
||||
'routes_externally': True,
|
||||
'default_interface': True,
|
||||
},
|
||||
{
|
||||
'name': 'a-private',
|
||||
'routes_externally': False,
|
||||
},
|
||||
{
|
||||
'name': 'another-private',
|
||||
'routes_externally': False,
|
||||
'nat_destination': True,
|
||||
},
|
||||
{
|
||||
'name': 'split-default',
|
||||
'routes_externally': True,
|
||||
'routes_ipv4_externally': False,
|
||||
},
|
||||
{
|
||||
'name': 'split-no-default',
|
||||
'routes_ipv6_externally': False,
|
||||
'routes_ipv4_externally': True,
|
||||
},
|
||||
],
|
||||
'region_name': 'test-region',
|
||||
},
|
||||
'_test_cloud_regions': {
|
||||
@@ -136,14 +141,14 @@ USER_CONF = {
|
||||
'name': 'region1',
|
||||
'values': {
|
||||
'external_network': 'region1-network',
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
'name': 'region2',
|
||||
'values': {
|
||||
'external_network': 'my-network',
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
'_test_cloud_hyphenated': {
|
||||
@@ -202,7 +207,7 @@ class TestCase(base.BaseTestCase):
|
||||
"""Test case base class for all unit tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestCase, self).setUp()
|
||||
super().setUp()
|
||||
|
||||
self.useFixture(fixtures.NestedTempfile())
|
||||
conf = copy.deepcopy(USER_CONF)
|
||||
@@ -212,10 +217,12 @@ class TestCase(base.BaseTestCase):
|
||||
self.secure_yaml = _write_yaml(SECURE_CONF)
|
||||
self.vendor_yaml = _write_yaml(VENDOR_CONF)
|
||||
self.no_yaml = _write_yaml(NO_CONF)
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'os_client_config.__version__', '1.2.3'))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
'openstack.version.__version__', '3.4.5'))
|
||||
self.useFixture(
|
||||
fixtures.MonkeyPatch('os_client_config.__version__', '1.2.3')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.MonkeyPatch('openstack.version.__version__', '3.4.5')
|
||||
)
|
||||
|
||||
# Isolate the test runs from the environment
|
||||
# Do this as two loops because you can't modify the dict in a loop
|
||||
|
||||
@@ -34,15 +34,15 @@ fake_services_dict = {
|
||||
|
||||
|
||||
class TestCloudConfig(base.TestCase):
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_api_version')
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_object_store_password(
|
||||
self,
|
||||
mock_get_session_endpoint,
|
||||
mock_get_auth_args,
|
||||
mock_get_api_version):
|
||||
self,
|
||||
mock_get_session_endpoint,
|
||||
mock_get_auth_args,
|
||||
mock_get_api_version,
|
||||
):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_session_endpoint.return_value = 'http://swift.example.com'
|
||||
mock_get_api_version.return_value = '3'
|
||||
@@ -55,7 +55,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('object-store', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
session=mock.ANY,
|
||||
@@ -64,12 +65,14 @@ class TestCloudConfig(base.TestCase):
|
||||
'service_type': 'object-store',
|
||||
'object_storage_url': None,
|
||||
'endpoint_type': 'public',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_object_store_password_v2(
|
||||
self, mock_get_session_endpoint, mock_get_auth_args):
|
||||
self, mock_get_session_endpoint, mock_get_auth_args
|
||||
):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_session_endpoint.return_value = 'http://swift.example.com'
|
||||
mock_get_auth_args.return_value = dict(
|
||||
@@ -81,7 +84,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('object-store', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
session=mock.ANY,
|
||||
@@ -90,19 +94,22 @@ class TestCloudConfig(base.TestCase):
|
||||
'service_type': 'object-store',
|
||||
'object_storage_url': None,
|
||||
'endpoint_type': 'public',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_object_store(
|
||||
self, mock_get_session_endpoint, mock_get_auth_args):
|
||||
self, mock_get_session_endpoint, mock_get_auth_args
|
||||
):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_session_endpoint.return_value = 'http://example.com/v2'
|
||||
mock_get_auth_args.return_value = {}
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('object-store', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
session=mock.ANY,
|
||||
@@ -111,12 +118,14 @@ class TestCloudConfig(base.TestCase):
|
||||
'service_type': 'object-store',
|
||||
'object_storage_url': None,
|
||||
'endpoint_type': 'public',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_object_store_timeout(
|
||||
self, mock_get_session_endpoint, mock_get_auth_args):
|
||||
self, mock_get_session_endpoint, mock_get_auth_args
|
||||
):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_session_endpoint.return_value = 'http://example.com/v2'
|
||||
mock_get_auth_args.return_value = {}
|
||||
@@ -124,8 +133,11 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict.update(fake_services_dict)
|
||||
config_dict['api_timeout'] = 9
|
||||
cc = cloud_config.CloudConfig(
|
||||
name="test1", region_name="region-al", config=config_dict,
|
||||
auth_plugin=mock.Mock())
|
||||
name="test1",
|
||||
region_name="region-al",
|
||||
config=config_dict,
|
||||
auth_plugin=mock.Mock(),
|
||||
)
|
||||
cc.get_legacy_client('object-store', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
session=mock.ANY,
|
||||
@@ -134,18 +146,19 @@ class TestCloudConfig(base.TestCase):
|
||||
'service_type': 'object-store',
|
||||
'object_storage_url': None,
|
||||
'endpoint_type': 'public',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_auth_args')
|
||||
def test_legacy_client_object_store_endpoint(
|
||||
self, mock_get_auth_args):
|
||||
def test_legacy_client_object_store_endpoint(self, mock_get_auth_args):
|
||||
mock_client = mock.Mock()
|
||||
mock_get_auth_args.return_value = {}
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
config_dict['object_store_endpoint'] = 'http://example.com/swift'
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('object-store', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
session=mock.ANY,
|
||||
@@ -154,7 +167,8 @@ class TestCloudConfig(base.TestCase):
|
||||
'service_type': 'object-store',
|
||||
'object_storage_url': 'http://example.com/swift',
|
||||
'endpoint_type': 'public',
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_image(self, mock_get_session_endpoint):
|
||||
@@ -163,7 +177,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('image', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version=2.0,
|
||||
@@ -173,7 +188,7 @@ class TestCloudConfig(base.TestCase):
|
||||
interface='public',
|
||||
session=mock.ANY,
|
||||
# Not a typo - the config dict above overrides this
|
||||
service_type='mage'
|
||||
service_type='mage',
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
@@ -184,7 +199,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict.update(fake_services_dict)
|
||||
config_dict['image_endpoint_override'] = 'http://example.com/override'
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('image', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version=2.0,
|
||||
@@ -194,7 +210,7 @@ class TestCloudConfig(base.TestCase):
|
||||
interface='public',
|
||||
session=mock.ANY,
|
||||
# Not a typo - the config dict above overrides this
|
||||
service_type='mage'
|
||||
service_type='mage',
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
@@ -206,7 +222,8 @@ class TestCloudConfig(base.TestCase):
|
||||
# v2 endpoint was passed, 1 requested in config, endpoint wins
|
||||
config_dict['image_api_version'] = '1'
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('image', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version=2.0,
|
||||
@@ -216,7 +233,7 @@ class TestCloudConfig(base.TestCase):
|
||||
interface='public',
|
||||
session=mock.ANY,
|
||||
# Not a typo - the config dict above overrides this
|
||||
service_type='mage'
|
||||
service_type='mage',
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
@@ -228,7 +245,8 @@ class TestCloudConfig(base.TestCase):
|
||||
# Versionless endpoint, config wins
|
||||
config_dict['image_api_version'] = '1'
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('image', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version='1',
|
||||
@@ -238,7 +256,7 @@ class TestCloudConfig(base.TestCase):
|
||||
interface='public',
|
||||
session=mock.ANY,
|
||||
# Not a typo - the config dict above overrides this
|
||||
service_type='mage'
|
||||
service_type='mage',
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
@@ -250,7 +268,8 @@ class TestCloudConfig(base.TestCase):
|
||||
# Versionless endpoint, config wins
|
||||
config_dict['image_api_version'] = '6'
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('image', mock_client, version='beef')
|
||||
mock_client.assert_called_with(
|
||||
version='beef',
|
||||
@@ -260,7 +279,7 @@ class TestCloudConfig(base.TestCase):
|
||||
interface='public',
|
||||
session=mock.ANY,
|
||||
# Not a typo - the config dict above overrides this
|
||||
service_type='mage'
|
||||
service_type='mage',
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
@@ -270,7 +289,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('network', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
api_version='2.0',
|
||||
@@ -279,7 +299,8 @@ class TestCloudConfig(base.TestCase):
|
||||
region_name='region-al',
|
||||
service_type='network',
|
||||
session=mock.ANY,
|
||||
service_name=None)
|
||||
service_name=None,
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_compute(self, mock_get_session_endpoint):
|
||||
@@ -288,7 +309,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('compute', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version='2',
|
||||
@@ -297,7 +319,8 @@ class TestCloudConfig(base.TestCase):
|
||||
region_name='region-al',
|
||||
service_type='compute',
|
||||
session=mock.ANY,
|
||||
service_name=None)
|
||||
service_name=None,
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_identity(self, mock_get_session_endpoint):
|
||||
@@ -306,7 +329,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict = defaults.get_defaults()
|
||||
config_dict.update(fake_services_dict)
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('identity', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version='2.0',
|
||||
@@ -316,7 +340,8 @@ class TestCloudConfig(base.TestCase):
|
||||
region_name='region-al',
|
||||
service_type='identity',
|
||||
session=mock.ANY,
|
||||
service_name='locks')
|
||||
service_name='locks',
|
||||
)
|
||||
|
||||
@mock.patch.object(cloud_region.CloudRegion, 'get_session_endpoint')
|
||||
def test_legacy_client_identity_v3(self, mock_get_session_endpoint):
|
||||
@@ -326,7 +351,8 @@ class TestCloudConfig(base.TestCase):
|
||||
config_dict.update(fake_services_dict)
|
||||
config_dict['identity_api_version'] = '3'
|
||||
cc = cloud_config.CloudConfig(
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock())
|
||||
"test1", "region-al", config_dict, auth_plugin=mock.Mock()
|
||||
)
|
||||
cc.get_legacy_client('identity', mock_client)
|
||||
mock_client.assert_called_with(
|
||||
version='3',
|
||||
@@ -336,4 +362,5 @@ class TestCloudConfig(base.TestCase):
|
||||
region_name='region-al',
|
||||
service_type='identity',
|
||||
session=mock.ANY,
|
||||
service_name='locks')
|
||||
service_name='locks',
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,52 +22,66 @@ import fixtures
|
||||
|
||||
|
||||
class TestEnviron(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestEnviron, self).setUp()
|
||||
super().setUp()
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_AUTH_URL', 'https://example.com'))
|
||||
fixtures.EnvironmentVariable('OS_AUTH_URL', 'https://example.com')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_USERNAME', 'testuser'))
|
||||
fixtures.EnvironmentVariable('OS_USERNAME', 'testuser')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_PASSWORD', 'testpass'))
|
||||
fixtures.EnvironmentVariable('OS_PASSWORD', 'testpass')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'testproject'))
|
||||
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'testproject')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_PROJECT_ID', 'testnova'))
|
||||
fixtures.EnvironmentVariable('NOVA_PROJECT_ID', 'testnova')
|
||||
)
|
||||
|
||||
def test_get_one_cloud(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
self.assertIsInstance(c.get_one_cloud(), cloud_config.CloudConfig)
|
||||
|
||||
def test_no_fallthrough(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
self.assertRaises(
|
||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'openstack')
|
||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'openstack'
|
||||
)
|
||||
|
||||
def test_envvar_name_override(self):
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_CLOUD_NAME', 'override'))
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
fixtures.EnvironmentVariable('OS_CLOUD_NAME', 'override')
|
||||
)
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
cc = c.get_one_cloud('override')
|
||||
self._assert_cloud_details(cc)
|
||||
|
||||
def test_envvar_prefer_ipv6_override(self):
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_PREFER_IPV6', 'false'))
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
secure_files=[self.secure_yaml])
|
||||
fixtures.EnvironmentVariable('OS_PREFER_IPV6', 'false')
|
||||
)
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
secure_files=[self.secure_yaml],
|
||||
)
|
||||
cc = c.get_one_cloud('_test-cloud_')
|
||||
self.assertFalse(cc.prefer_ipv6)
|
||||
|
||||
def test_environ_exists(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
secure_files=[self.secure_yaml])
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
secure_files=[self.secure_yaml],
|
||||
)
|
||||
cc = c.get_one_cloud('envvars')
|
||||
self._assert_cloud_details(cc)
|
||||
self.assertNotIn('auth_url', cc.config)
|
||||
@@ -80,10 +94,12 @@ class TestEnviron(base.TestCase):
|
||||
self._assert_cloud_details(cc)
|
||||
|
||||
def test_environ_prefix(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
envvar_prefix='NOVA_',
|
||||
secure_files=[self.secure_yaml])
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
envvar_prefix='NOVA_',
|
||||
secure_files=[self.secure_yaml],
|
||||
)
|
||||
cc = c.get_one_cloud('envvars')
|
||||
self._assert_cloud_details(cc)
|
||||
self.assertNotIn('auth_url', cc.config)
|
||||
@@ -96,9 +112,11 @@ class TestEnviron(base.TestCase):
|
||||
self._assert_cloud_details(cc)
|
||||
|
||||
def test_get_one_cloud_with_config_files(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
secure_files=[self.secure_yaml])
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
secure_files=[self.secure_yaml],
|
||||
)
|
||||
self.assertIsInstance(c.cloud_config, dict)
|
||||
self.assertIn('cache', c.cloud_config)
|
||||
self.assertIsInstance(c.cloud_config['cache'], dict)
|
||||
@@ -112,40 +130,44 @@ class TestEnviron(base.TestCase):
|
||||
def test_config_file_override(self):
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable(
|
||||
'OS_CLIENT_CONFIG_FILE', self.cloud_yaml))
|
||||
c = config.OpenStackConfig(config_files=[],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
'OS_CLIENT_CONFIG_FILE', self.cloud_yaml
|
||||
)
|
||||
)
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
cc = c.get_one_cloud('_test-cloud_')
|
||||
self._assert_cloud_details(cc)
|
||||
|
||||
|
||||
class TestEnvvars(base.TestCase):
|
||||
|
||||
def test_no_envvars(self):
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
self.assertRaises(
|
||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars')
|
||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars'
|
||||
)
|
||||
|
||||
def test_test_envvars(self):
|
||||
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_STDERR_CAPTURE', 'True'))
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
fixtures.EnvironmentVariable('OS_STDERR_CAPTURE', 'True')
|
||||
)
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
self.assertRaises(
|
||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars')
|
||||
exceptions.OpenStackConfigException, c.get_one_cloud, 'envvars'
|
||||
)
|
||||
|
||||
def test_incomplete_envvars(self):
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
||||
config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
||||
config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
# This is broken due to an issue that's fixed in a subsequent patch
|
||||
# commenting it out in this patch to keep the patch size reasonable
|
||||
# self.assertRaises(
|
||||
@@ -153,33 +175,38 @@ class TestEnvvars(base.TestCase):
|
||||
# c.get_one_cloud, 'envvars')
|
||||
|
||||
def test_have_envvars(self):
|
||||
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
fixtures.EnvironmentVariable('OS_AUTH_URL', 'http://example.com')
|
||||
)
|
||||
self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_AUTH_URL', 'http://example.com'))
|
||||
fixtures.EnvironmentVariable('OS_PASSWORD', 'password')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_USERNAME', 'user'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_PASSWORD', 'password'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'project'))
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
fixtures.EnvironmentVariable('OS_PROJECT_NAME', 'project')
|
||||
)
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml], vendor_files=[self.vendor_yaml]
|
||||
)
|
||||
cc = c.get_one_cloud('envvars')
|
||||
self.assertEqual(cc.config['auth']['username'], 'user')
|
||||
|
||||
def test_old_envvars(self):
|
||||
self.useFixture(fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_USERNAME', 'nova'))
|
||||
fixtures.EnvironmentVariable('NOVA_AUTH_URL', 'http://example.com')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable(
|
||||
'NOVA_AUTH_URL', 'http://example.com'))
|
||||
fixtures.EnvironmentVariable('NOVA_PASSWORD', 'password')
|
||||
)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_PASSWORD', 'password'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('NOVA_PROJECT_NAME', 'project'))
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
envvar_prefix='NOVA_')
|
||||
fixtures.EnvironmentVariable('NOVA_PROJECT_NAME', 'project')
|
||||
)
|
||||
c = config.OpenStackConfig(
|
||||
config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml],
|
||||
envvar_prefix='NOVA_',
|
||||
)
|
||||
cc = c.get_one_cloud('envvars')
|
||||
self.assertEqual(cc.config['auth']['username'], 'nova')
|
||||
|
||||
@@ -16,7 +16,7 @@ from os_client_config.tests import base
|
||||
|
||||
|
||||
class TestImportVendors(base.TestCase):
|
||||
|
||||
def test_get_profile(self):
|
||||
import os_client_config # noqa
|
||||
|
||||
os_client_config.vendors.get_profile(profile_name="dummy")
|
||||
|
||||
@@ -19,17 +19,16 @@ from os_client_config.tests import base
|
||||
class TestInit(base.TestCase):
|
||||
def test_get_config_without_arg_parser(self):
|
||||
cloud_config = os_client_config.get_config(
|
||||
options=None, validate=False)
|
||||
options=None, validate=False
|
||||
)
|
||||
self.assertIsInstance(
|
||||
cloud_config,
|
||||
os_client_config.cloud_config.CloudConfig
|
||||
cloud_config, os_client_config.cloud_config.CloudConfig
|
||||
)
|
||||
|
||||
def test_get_config_with_arg_parser(self):
|
||||
cloud_config = os_client_config.get_config(
|
||||
options=argparse.ArgumentParser(),
|
||||
validate=False)
|
||||
self.assertIsInstance(
|
||||
cloud_config,
|
||||
os_client_config.cloud_config.CloudConfig
|
||||
options=argparse.ArgumentParser(), validate=False
|
||||
)
|
||||
self.assertIsInstance(
|
||||
cloud_config, os_client_config.cloud_config.CloudConfig
|
||||
)
|
||||
|
||||
14
pyproject.toml
Normal file
14
pyproject.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
target-version = "py310"
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "preserve"
|
||||
docstring-code-format = true
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E4", "E7", "E9", "F", "S", "U"]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"os_client_config/tests/*" = ["S"]
|
||||
"tools/*" = ["S"]
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Os-Client-Config Release Notes documentation build configuration file, created by
|
||||
# sphinx-quickstart on Thu Nov 5 11:50:32 2015.
|
||||
@@ -15,20 +14,17 @@
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- 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 = [
|
||||
'reno.sphinxext',
|
||||
'openstackdocstheme'
|
||||
]
|
||||
extensions = ['reno.sphinxext', 'openstackdocstheme']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -37,14 +33,14 @@ templates_path = ['_templates']
|
||||
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'
|
||||
|
||||
# General information about the project.
|
||||
project = u'os-client-config Release Notes'
|
||||
copyright = u'2015, os-client-config developers'
|
||||
project = 'os-client-config Release Notes'
|
||||
copyright = '2015, os-client-config developers'
|
||||
|
||||
# openstackdocstheme options
|
||||
openstackdocs_repo_name = 'openstack/os-client-config'
|
||||
@@ -60,13 +56,13 @@ release = ''
|
||||
|
||||
# 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.
|
||||
@@ -74,27 +70,27 @@ 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'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
# keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
@@ -106,23 +102,23 @@ 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,
|
||||
@@ -132,48 +128,48 @@ html_static_path = ['_static']
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
# html_extra_path = []
|
||||
|
||||
# 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 = 'OCCReleaseNotesdoc'
|
||||
@@ -182,43 +178,46 @@ htmlhelp_basename = 'OCCReleaseNotesdoc'
|
||||
# -- 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, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'OCCReleaseNotes.tex', u'os-client-config Release Notes Documentation',
|
||||
u'os-client-config developers', 'manual'),
|
||||
(
|
||||
'index',
|
||||
'OCCReleaseNotes.tex',
|
||||
'os-client-config Release Notes Documentation',
|
||||
'os-client-config developers',
|
||||
'manual',
|
||||
),
|
||||
]
|
||||
|
||||
# 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 ---------------------------------------
|
||||
@@ -226,12 +225,17 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'occreleasenotes', u'os-client-config Release Notes Documentation',
|
||||
[u'os-client-config developers'], 1)
|
||||
(
|
||||
'index',
|
||||
'occreleasenotes',
|
||||
'os-client-config Release Notes Documentation',
|
||||
['os-client-config developers'],
|
||||
1,
|
||||
)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
@@ -240,23 +244,28 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'OCCReleaseNotes', u'os-client-config Release Notes Documentation',
|
||||
u'os-client-config developers', 'OCCReleaseNotes',
|
||||
'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
(
|
||||
'index',
|
||||
'OCCReleaseNotes',
|
||||
'os-client-config Release Notes Documentation',
|
||||
'os-client-config developers',
|
||||
'OCCReleaseNotes',
|
||||
'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'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
# texinfo_no_detailmenu = False
|
||||
|
||||
# -- Options for Internationalization output ------------------------------
|
||||
locale_dirs = ['locale/']
|
||||
|
||||
4
setup.py
4
setup.py
@@ -15,6 +15,4 @@
|
||||
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr>=2.0.0'],
|
||||
pbr=True)
|
||||
setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True)
|
||||
|
||||
@@ -35,8 +35,9 @@ def print_version(version):
|
||||
if version['status'] in ('CURRENT', 'stable'):
|
||||
print(
|
||||
"\tVersion ID: {id} updated {updated}".format(
|
||||
id=version.get('id'),
|
||||
updated=version.get('updated')))
|
||||
id=version.get('id'), updated=version.get('updated')
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
verbose = '-v' in sys.argv
|
||||
@@ -55,7 +56,7 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
||||
if verbose:
|
||||
pprint.pprint(r)
|
||||
except Exception as e:
|
||||
print("Error with {cloud}: {e}".format(cloud=cloud.name, e=str(e)))
|
||||
print(f"Error with {cloud.name}: {str(e)}")
|
||||
continue
|
||||
if 'version' in r:
|
||||
print_version(r['version'])
|
||||
@@ -68,10 +69,11 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
||||
port = None
|
||||
stripped = path.rsplit('/', 2)[0]
|
||||
if port:
|
||||
stripped = '{stripped}:{port}'.format(stripped=stripped, port=port)
|
||||
stripped = f'{stripped}:{port}'
|
||||
endpoint = urllib.parse.urlunsplit(
|
||||
(url.scheme, url.netloc, stripped, url.params, url.query))
|
||||
print(" also {endpoint}".format(endpoint=endpoint))
|
||||
(url.scheme, url.netloc, stripped, url.params, url.query)
|
||||
)
|
||||
print(f" also {endpoint}")
|
||||
try:
|
||||
r = c.get(endpoint).json()
|
||||
if verbose:
|
||||
@@ -84,6 +86,6 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
||||
elif 'versions' in r:
|
||||
print_versions(r['versions'])
|
||||
else:
|
||||
print("\n\nUNKNOWN\n\n{r}".format(r=r))
|
||||
print(f"\n\nUNKNOWN\n\n{r}")
|
||||
else:
|
||||
print_versions(r['versions'])
|
||||
|
||||
@@ -28,29 +28,34 @@ for cloud in os_client_config.OpenStackConfig().get_all_clouds():
|
||||
print(endpoint)
|
||||
r = c.get(endpoint).json()
|
||||
except Exception:
|
||||
print("Error with %s" % cloud.name)
|
||||
print(f"Error with {cloud.name}")
|
||||
continue
|
||||
for version in r['versions']:
|
||||
if version['status'] == 'CURRENT':
|
||||
have_current = True
|
||||
print(
|
||||
"\tVersion ID: {id} updated {updated}".format(
|
||||
id=version.get('id'),
|
||||
updated=version.get('updated')))
|
||||
id=version.get('id'), updated=version.get('updated')
|
||||
)
|
||||
)
|
||||
print("\tVersion Max: {max}".format(max=version.get('version')))
|
||||
print(
|
||||
"\tVersion Max: {max}".format(max=version.get('version')))
|
||||
print(
|
||||
"\tVersion Min: {min}".format(min=version.get('min_version')))
|
||||
"\tVersion Min: {min}".format(min=version.get('min_version'))
|
||||
)
|
||||
if not have_current:
|
||||
for version in r['versions']:
|
||||
if version['status'] == 'SUPPORTED':
|
||||
have_current = True
|
||||
print(
|
||||
"\tVersion ID: {id} updated {updated}".format(
|
||||
id=version.get('id'),
|
||||
updated=version.get('updated')))
|
||||
id=version.get('id'), updated=version.get('updated')
|
||||
)
|
||||
)
|
||||
print(
|
||||
"\tVersion Max: {max}".format(max=version.get('version')))
|
||||
"\tVersion Max: {max}".format(max=version.get('version'))
|
||||
)
|
||||
print(
|
||||
"\tVersion Min: {min}".format(
|
||||
min=version.get('min_version')))
|
||||
min=version.get('min_version')
|
||||
)
|
||||
)
|
||||
|
||||
20
tox.ini
20
tox.ini
@@ -22,17 +22,13 @@ commands =
|
||||
stestr slowest
|
||||
|
||||
[testenv:pep8]
|
||||
usedevelop = false
|
||||
description =
|
||||
Run style checks.
|
||||
skip_install = true
|
||||
deps =
|
||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
||||
doc8
|
||||
hacking
|
||||
pygments
|
||||
readme
|
||||
pre-commit
|
||||
commands =
|
||||
doc8 doc/source
|
||||
flake8 os_client_config
|
||||
pre-commit run --all-files --show-diff-on-failure
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
@@ -54,7 +50,7 @@ deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/doc/requirements.txt
|
||||
commands =
|
||||
sphinx-build -W -d doc/build/doctrees -b html doc/source/ doc/build/html
|
||||
sphinx-build -W -d doc/build/doctrees -b html doc/source/ doc/build/html
|
||||
|
||||
[testenv:releasenotes]
|
||||
skip_install = true
|
||||
@@ -65,6 +61,12 @@ commands =
|
||||
sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
|
||||
|
||||
[flake8]
|
||||
# We only enable the hacking (H) checks
|
||||
select = H
|
||||
# H301 Black will put commas after imports that can't fit on one line
|
||||
# H404 Docstrings don't always start with a newline
|
||||
# H405 Multiline docstrings are okay
|
||||
ignore = H301,H403,H404,H405
|
||||
show-source = True
|
||||
builtins = _
|
||||
exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,releasenotes/source/conf.py
|
||||
|
||||
Reference in New Issue
Block a user