Change oslo.config with a global dictionary

Change-Id: I7bca2e01e74645273b708c4c8ca305c5d4da8478
This commit is contained in:
Alexandru Coman 2017-03-23 16:00:59 +02:00
parent 349a9035d7
commit 614454027a
No known key found for this signature in database
GPG Key ID: A7B6A9021F704507
15 changed files with 66 additions and 270 deletions

View File

@ -1,4 +0,0 @@
To generate the sample hnv.conf file, run the following command from the top
level of the python-hnv directory:
oslo-config-generator --config-file etc/python-hnv/hnv-config-generator.conf

View File

@ -1,5 +0,0 @@
[DEFAULT]
output_file = etc/python-hnv/hnv.conf
wrap_width = 80
namespace = hnv.conf
namespace = oslo.log

View File

@ -15,3 +15,14 @@ import pbr.version
__version__ = pbr.version.VersionInfo( __version__ = pbr.version.VersionInfo(
'hnv').version_string() 'hnv').version_string()
CONFIG = {
"url": None,
"username": None,
"password": None,
"https_allow_insecure": False,
"https_ca_bundle": None,
"retry_count": 5,
"retry_interval": 1,
"http_request_timeout": None,
}

View File

@ -24,15 +24,14 @@ from hnv.common import constant
from hnv.common import exception from hnv.common import exception
from hnv.common import model from hnv.common import model
from hnv.common import utils from hnv.common import utils
from hnv import config as hnv_config from hnv import CONFIG
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
CONFIG = hnv_config.CONFIG
class _BaseHNVModel(model.Model): class _BaseHNVModel(model.Model):
_endpoint = CONFIG.HNV.url _endpoint = CONFIG["url"]
resource_ref = model.Field(name="resource_ref", key="resourceRef", resource_ref = model.Field(name="resource_ref", key="resourceRef",
is_property=False) is_property=False)
@ -138,11 +137,13 @@ class _BaseHNVModel(model.Model):
@staticmethod @staticmethod
def _get_client(): def _get_client():
"""Create a new client for the HNV REST API.""" """Create a new client for the HNV REST API."""
return utils.get_client(url=CONFIG.HNV.url, return utils.get_client(
username=CONFIG.HNV.username, url=CONFIG["url"],
password=CONFIG.HNV.password, username=CONFIG["username"],
allow_insecure=CONFIG.HNV.https_allow_insecure, password=CONFIG["password"],
ca_bundle=CONFIG.HNV.https_ca_bundle) allow_insecure=CONFIG["https_allow_insecure"],
ca_bundle=CONFIG["https_ca_bundle"]
)
@classmethod @classmethod
def _get_all(cls, parent_id=None, grandparent_id=None): def _get_all(cls, parent_id=None, grandparent_id=None):
@ -237,10 +238,10 @@ class _BaseHNVModel(model.Model):
LOG.debug("The resource was successfully removed.") LOG.debug("The resource was successfully removed.")
break break
elapsed_time += CONFIG.HNV.retry_interval elapsed_time += CONFIG["retry_interval"]
if timeout and elapsed_time > timeout: if timeout and elapsed_time > timeout:
raise exception.TimeOut("The request timed out.") raise exception.TimeOut("The request timed out.")
time.sleep(CONFIG.HNV.retry_interval) time.sleep(CONFIG["retry_interval"])
def refresh(self): def refresh(self):
"""Get the latest representation of the current model.""" """Get the latest representation of the current model."""
@ -289,10 +290,10 @@ class _BaseHNVModel(model.Model):
self.refresh() # Update the representation of the current model self.refresh() # Update the representation of the current model
if self.is_ready(): if self.is_ready():
break break
elapsed_time += CONFIG.HNV.retry_interval elapsed_time += CONFIG["retry_interval"]
if timeout and elapsed_time > timeout: if timeout and elapsed_time > timeout:
raise exception.TimeOut("The request timed out.") raise exception.TimeOut("The request timed out.")
time.sleep(CONFIG.HNV.retry_interval) time.sleep(CONFIG["retry_interval"])
else: else:
self._reset_model(response) self._reset_model(response)
@ -2808,9 +2809,6 @@ class BGPPeersStatistics(model.Model):
@classmethod @classmethod
def process_raw_data(cls, raw_data): def process_raw_data(cls, raw_data):
"""Create a new model using raw API response.""" """Create a new model using raw API response."""
# pylint: disable=redefined-variable-type
raw_content = raw_data.get("updateMessageStats", None) raw_content = raw_data.get("updateMessageStats", None)
if raw_content is not None: if raw_content is not None:
statistics = UpdateMessageStatistics.from_raw_data(raw_content) statistics = UpdateMessageStatistics.from_raw_data(raw_content)
@ -3188,3 +3186,26 @@ class LoadBalancerMux(_BaseHNVModel):
properties["virtualServer"] = resource properties["virtualServer"] = resource
return super(LoadBalancerMux, cls).process_raw_data(raw_data) return super(LoadBalancerMux, cls).process_raw_data(raw_data)
def setup(**config):
"""Update the global configurations for the HNV client.
:param url: The base URL where the agent looks for Network
Controller API.
:param username: The username required for connecting to the
Network Controller API.
:param password: The password required for connecting to the
Network Controller API.
:param https_allow_insecure: Whether to disable the validation
of HTTPS certificates.
:param https_ca_bundle: The path to a CA_BUNDLE file or directory
with certificates of trusted CAs.
:param retry_count: Max. number of attempts for fetching content in
case of transient errors.
:param retry_interval: Interval between attempts in case of transient
errors, expressed in seconds.
:param http_request_timeout: Number of seconds until network requests
stop waiting for a response.
"""
CONFIG.update(config)

View File

@ -25,10 +25,9 @@ import six
from hnv.common import constant from hnv.common import constant
from hnv.common import exception from hnv.common import exception
from hnv import config as hnv_config from hnv import CONFIG
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
CONFIG = hnv_config.CONFIG
class _HNVClient(object): class _HNVClient(object):
@ -124,7 +123,7 @@ class _HNVClient(object):
response = self._session.request( response = self._session.request(
method=method, url=url, headers=headers, method=method, url=url, headers=headers,
data=json.dumps(body) if body else None, data=json.dumps(body) if body else None,
timeout=CONFIG.HNV.http_request_timeout timeout=CONFIG["http_request_timeout"]
) )
break break
except (requests.ConnectionError, except (requests.ConnectionError,
@ -132,12 +131,12 @@ class _HNVClient(object):
attemts += 1 attemts += 1
self._http_session = None self._http_session = None
LOG.debug("Request failed: %s", exc) LOG.debug("Request failed: %s", exc)
if attemts > CONFIG.HNV.retry_count: if attemts > CONFIG["retry_count"]:
if isinstance(exc, requests.exceptions.SSLError): if isinstance(exc, requests.exceptions.SSLError):
raise exception.CertificateVerifyFailed( raise exception.CertificateVerifyFailed(
"HTTPS certificate validation failed.") "HTTPS certificate validation failed.")
raise raise
time.sleep(CONFIG.HNV.retry_interval) time.sleep(CONFIG["retry_interval"])
try: try:
response.raise_for_status() response.raise_for_status()

View File

@ -1,24 +0,0 @@
# Copyright 2017 Cloudbase Solutions Srl
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Config options available for HNV client project."""
from oslo_config import cfg
from hnv.config import factory as options_factory
CONFIG = cfg.CONF
for option_class in options_factory.get_options():
option_class(CONFIG).register()

View File

@ -1,44 +0,0 @@
# Copyright 2017 Cloudbase Solutions Srl
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Contact class for all the collections of config options."""
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class Options(object):
"""Contact class for all the collections of config options."""
def __init__(self, config, group="DEFAULT"):
self._config = config
self._group_name = group
@property
def group_name(self):
"""The group name for the current options."""
return self._group_name
@abc.abstractmethod
def register(self):
"""Register the current options to the global ConfigOpts object."""
pass
@abc.abstractmethod
def list(self):
"""Return a list which contains all the available options."""
pass

View File

@ -1,78 +0,0 @@
# Copyright 2017 Cloudbase Solutions Srl
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Config options available for HVN."""
from oslo_config import cfg
from hnv.config import base as config_base
class HVNOptions(config_base.Options):
"""Config options available for HVN."""
def __init__(self, config):
super(HVNOptions, self).__init__(config, group="HNV")
self._options = [
cfg.StrOpt(
"url", default="http://127.0.0.1/",
help=("The base URL where the agent looks for "
"Network Controller API.")),
cfg.StrOpt(
"username",
help=("The username required for connecting to the Netowork "
"Controller API.")),
cfg.StrOpt(
"password",
help=("The password required for connecting to the Netowork "
"Controller API."),
secret=True),
cfg.BoolOpt(
"https_allow_insecure", default=False,
help=("Whether to disable the validation of "
"HTTPS certificates.")),
cfg.StrOpt(
"https_ca_bundle", default=None,
help=("The path to a CA_BUNDLE file or directory with "
"certificates of trusted CAs.")),
cfg.IntOpt(
"retry_count", default=5,
help="Max. number of attempts for fetching metadata in "
"case of transient errors"),
cfg.FloatOpt(
"retry_interval", default=1,
help=("Interval between attempts in case of transient errors, "
"expressed in seconds")),
cfg.IntOpt(
"http_request_timeout", default=None,
help=("Number of seconds until network requests stop waiting "
"for a response")),
cfg.StrOpt(
"logical_network", default=None,
help=("Logical network to use as a medium for tenant network "
"traffic.")),
]
def register(self):
"""Register the current options to the global ConfigOpts object."""
group = cfg.OptGroup(
self.group_name,
title="HNV (Hyper-V Network Virtualization) Options")
self._config.register_group(group)
self._config.register_opts(self._options, group=group)
def list(self):
"""Return a list which contains all the available options."""
return self._options

View File

@ -1,31 +0,0 @@
# Copyright 2017 Cloudbase Solutions Srl
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Factory for all the available config options."""
_OPT_PATHS = (
'hnv.config.client.HVNOptions',
)
def _load_class(class_path):
"""Load the module and return the required class."""
parts = class_path.rsplit('.', 1)
module = __import__(parts[0], fromlist=parts[1])
return getattr(module, parts[1])
def get_options():
"""Return a list of all the available `Options` subclasses."""
return [_load_class(class_path) for class_path in _OPT_PATHS]

View File

@ -1,34 +0,0 @@
# Copyright 2017 Cloudbase Solutions Srl
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
This is the single point of entry to generate the sample configuration
file for Cloudbase-Init.
"""
import collections
from hnv.config import base as config_base
from hnv.config import factory as config_factory
def get_options():
"""Collect all the options info from the other modules."""
options = collections.defaultdict(list)
for opt_class in config_factory.get_options():
if not issubclass(opt_class, config_base.Options):
continue
config_options = opt_class(None)
options[config_options.group_name].extend(config_options.list())
return [(key, value) for key, value in options.items()]

View File

@ -25,11 +25,9 @@ import requests
from hnv.common import constant from hnv.common import constant
from hnv.common import exception from hnv.common import exception
from hnv.common import utils as hnv_utils from hnv.common import utils as hnv_utils
from hnv import config as hnv_config from hnv import CONFIG
from hnv.tests import utils as test_utils from hnv.tests import utils as test_utils
CONFIG = hnv_config.CONFIG
class TestHNVClient(unittest.TestCase): class TestHNVClient(unittest.TestCase):
@ -142,7 +140,7 @@ class TestHNVClient(unittest.TestCase):
session_request.assert_called_once_with( session_request.assert_called_once_with(
method=method, url=mock.sentinel.url, headers=headers, method=method, url=mock.sentinel.url, headers=headers,
data=mock.sentinel.content if body else None, data=mock.sentinel.content if body else None,
timeout=CONFIG.HNV.http_request_timeout timeout=CONFIG["http_request_timeout"]
) )
elif len(response) > 1: elif len(response) > 1:
# Note(alexcoman): The first response is an exception # Note(alexcoman): The first response is an exception
@ -170,7 +168,7 @@ class TestHNVClient(unittest.TestCase):
def test_http_request_with_connection_error(self): def test_http_request_with_connection_error(self):
response = [requests.ConnectionError(), mock.MagicMock()] response = [requests.ConnectionError(), mock.MagicMock()]
with test_utils.ConfigPatcher('retry_count', 1, "HNV"): with test_utils.ConfigPatcher('retry_count', 1):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
@ -179,7 +177,7 @@ class TestHNVClient(unittest.TestCase):
def test_http_request_connection_error(self): def test_http_request_connection_error(self):
response = [requests.ConnectionError(), requests.ConnectionError()] response = [requests.ConnectionError(), requests.ConnectionError()]
with test_utils.ConfigPatcher('retry_count', 1, "HNV"): with test_utils.ConfigPatcher('retry_count', 1):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,
@ -189,7 +187,7 @@ class TestHNVClient(unittest.TestCase):
def test_http_request_ssl_error(self): def test_http_request_ssl_error(self):
response = [requests.exceptions.SSLError(), response = [requests.exceptions.SSLError(),
requests.exceptions.SSLError()] requests.exceptions.SSLError()]
with test_utils.ConfigPatcher('retry_count', 1, "HNV"): with test_utils.ConfigPatcher('retry_count', 1):
self._test_http_request(method=constant.GET, self._test_http_request(method=constant.GET,
body=mock.sentinel.body, body=mock.sentinel.body,
response=response, response=response,

View File

@ -23,12 +23,10 @@ except ImportError:
from hnv import client from hnv import client
from hnv.common import exception from hnv.common import exception
from hnv import config as hnv_config from hnv import CONFIG
from hnv.tests.fake import fake_response from hnv.tests.fake import fake_response
from hnv.tests import utils as test_utils from hnv.tests import utils as test_utils
CONFIG = hnv_config.CONFIG
class TestBaseHNVModel(unittest.TestCase): class TestBaseHNVModel(unittest.TestCase):
@ -94,7 +92,7 @@ class TestBaseHNVModel(unittest.TestCase):
side_effect.append(True if not timeout else False) side_effect.append(True if not timeout else False)
is_ready.side_effect = side_effect is_ready.side_effect = side_effect
request_timeout = CONFIG.HNV.retry_interval * loop_count request_timeout = CONFIG["retry_interval"] * loop_count
request_wait = True if loop_count > 0 else False request_wait = True if loop_count > 0 else False
if timeout: if timeout:
@ -146,7 +144,7 @@ class TestBaseHNVModel(unittest.TestCase):
side_effect.append(True) side_effect.append(True)
mock_is_ready.side_effect = side_effect mock_is_ready.side_effect = side_effect
request_timeout = CONFIG.HNV.retry_interval * loop_count request_timeout = CONFIG["retry_interval"] * loop_count
request_wait = True if loop_count > 0 else False request_wait = True if loop_count > 0 else False
model = client._BaseHNVModel(resource_id="hnv-client", model = client._BaseHNVModel(resource_id="hnv-client",

View File

@ -21,10 +21,7 @@ import logging as base_logging
from oslo_log import log as oslo_logging from oslo_log import log as oslo_logging
from hnv import config as hnv_conf from hnv import CONFIG as hnv_config
CONFIG = hnv_conf.CONFIG
class SnatchHandler(base_logging.Handler): class SnatchHandler(base_logging.Handler):
@ -83,15 +80,11 @@ class ConfigPatcher(object):
This class can be used both as a context manager and as a decorator. This class can be used both as a context manager and as a decorator.
""" """
def __init__(self, key, value, group=None, conf=CONFIG): def __init__(self, key, value):
if group:
self._original_value = conf.get(group).get(key)
else:
self._original_value = conf.get(key)
self._key = key self._key = key
self._value = value self._value = value
self._group = group self._original_value = None
self._config = conf self._config = hnv_config
def __call__(self, func, *args, **kwargs): def __call__(self, func, *args, **kwargs):
def _wrapped_f(*args, **kwargs): def _wrapped_f(*args, **kwargs):
@ -102,10 +95,9 @@ class ConfigPatcher(object):
return _wrapped_f return _wrapped_f
def __enter__(self): def __enter__(self):
self._config.set_override(self._key, self._value, self._original_value = self._config[self._key]
group=self._group) self._config[self._key] = self._value
return self return self
def __exit__(self, exc_type, exc_val, exc_tb): def __exit__(self, exc_type, exc_val, exc_tb):
self._config.set_override(self._key, self._original_value, self._config[self._key] = self._original_value
group=self._group)

View File

@ -5,7 +5,6 @@
pbr>=1.8 # Apache-2.0 pbr>=1.8 # Apache-2.0
six>=1.7.0 six>=1.7.0
oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0 oslo.i18n>=2.1.0 # Apache-2.0
oslo.log>=3.11.0 # Apache-2.0 oslo.log>=3.11.0 # Apache-2.0
requests requests

View File

@ -29,8 +29,6 @@ setup-hooks =
pbr.hooks.setup_hook pbr.hooks.setup_hook
[entry_points] [entry_points]
oslo.config.opts =
hnv.conf = hnv.config.options:get_options
[build_sphinx] [build_sphinx]
source-dir = doc/source source-dir = doc/source