oslo.config/oslo_config/sources/_uri.py
Raildo Mascena e8c93ea5ba User guide documentation for backend drivers for oslo.config
New documentation sections explaning how to use the backend
drivers for oslo.config, also include explanation on how to
use the remote_file driver.

Change-Id: I45fc2155f6fe2d8bee058dac880afba8bb9bfd53
Blueprint: oslo-config-drivers
2018-07-05 14:44:15 +00:00

171 lines
5.7 KiB
Python

# 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.
r"""
Remote File
-----------
The **remote_file** backend driver is the first driver implemented by
oslo.config. It extends the previous limit of only accessing local files
to a new scenario where it is possible to access configuration data over
the network. The **remote_file** driver is based on the **requests** module
and is capable of accessing remote files through **HTTP** or **HTTPS**.
To definition of a remote_file configuration data source can be as minimal as::
[DEFAULT]
config_source = external_config_group
[external_config_group]
driver = remote_file
uri = http://mydomain.com/path/to/config/data.conf
Or as complete as::
[DEFAULT]
config_source = external_config_group
[external_config_group]
driver = remote_file
uri = https://mydomain.com/path/to/config/data.conf
ca_path = /path/to/server/ca.pem
client_key = /path/to/my/key.pem
client_cert = /path/to/my/cert.pem
On the following sessions, you can find more information about this driver's
classes and its options.
The Driver Class
================
.. autoclass:: URIConfigurationSourceDriver
The Configuration Source Class
==============================
.. autoclass:: URIConfigurationSource
"""
import requests
import tempfile
from oslo_config import cfg
from oslo_config import sources
class URIConfigurationSourceDriver(sources.ConfigurationSourceDriver):
"""A backend driver for remote files served through http[s].
Required options:
- uri: URI containing the file location.
Non-required options:
- ca_path: The path to a CA_BUNDLE file or directory with
certificates of trusted CAs.
- client_cert: Client side certificate, as a single file path
containing either the certificate only or the
private key and the certificate.
- client_key: Client side private key, in case client_cert is
specified but does not includes the private key.
"""
_uri_driver_opts = [
cfg.URIOpt(
'uri',
schemes=['http', 'https'],
required=True,
sample_default='https://example.com/my-configuration.ini',
help=('Required option with the URI of the '
'extra configuration file\'s location.'),
),
cfg.StrOpt(
'ca_path',
sample_default='/etc/ca-certificates',
help=('The path to a CA_BUNDLE file or directory '
'with certificates of trusted CAs.'),
),
cfg.StrOpt(
'client_cert',
sample_default='/etc/ca-certificates/service-client-keystore',
help=('Client side certificate, as a single file path '
'containing either the certificate only or the '
'private key and the certificate.'),
),
cfg.StrOpt(
'client_key',
help=('Client side private key, in case client_cert is '
'specified but does not includes the private key.'),
),
]
def list_options_for_discovery(self):
return self._uri_driver_opts
def open_source_from_opt_group(self, conf, group_name):
conf.register_opts(self._uri_driver_opts, group_name)
return URIConfigurationSource(
conf[group_name].uri,
conf[group_name].ca_path,
conf[group_name].client_cert,
conf[group_name].client_key)
class URIConfigurationSource(sources.ConfigurationSource):
"""A configuration source for remote files served through http[s].
:param uri: The Uniform Resource Identifier of the configuration to be
retrieved.
:param ca_path: The path to a CA_BUNDLE file or directory with
certificates of trusted CAs.
:param client_cert: Client side certificate, as a single file path
containing either the certificate only or the
private key and the certificate.
:param client_key: Client side private key, in case client_cert is
specified but does not includes the private key.
"""
def __init__(self, uri, ca_path=None, client_cert=None, client_key=None):
self._uri = uri
self._namespace = cfg._Namespace(cfg.ConfigOpts())
data = self._fetch_uri(uri, ca_path, client_cert, client_key)
with tempfile.NamedTemporaryFile() as tmpfile:
tmpfile.write(data.encode("utf-8"))
tmpfile.flush()
cfg.ConfigParser._parse_file(tmpfile.name, self._namespace)
def _fetch_uri(self, uri, ca_path, client_cert, client_key):
verify = ca_path if ca_path else True
cert = (client_cert, client_key) if client_cert and client_key else \
client_cert
with requests.get(uri, verify=verify, cert=cert) as response:
response.raise_for_status() # raises only in case of HTTPError
return response.text
def get(self, group_name, option_name, opt):
try:
return self._namespace._get_value(
[(group_name, option_name)],
multi=opt.multi)
except KeyError:
return (sources._NoValue, None)