Source code for compliance.utils.credentials

# -*- mode:python; coding:utf-8 -*-
# Copyright (c) 2020 IBM Corp. All rights reserved.
#
# 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.
"""Compliance credentials configuration."""

import logging
import os
from collections import OrderedDict, namedtuple
from configparser import RawConfigParser

# used to differentiate a user passing None vs
# not passing a value for an optional argument
_sentinel = object()

logger = logging.getLogger('compliance.utils.credentials')


[docs]class Config(): """Handle credentials configuration.""" def __init__(self, cfg_file='~/.credentials'): """ Create an instance of a dictionary-like configuration object. :param cfg_file: The path to the RawConfigParser compatible config file """ self._cfg = RawConfigParser() self._cfg.read(os.path.expanduser(cfg_file)) self._cfg_file = cfg_file def __getitem__(self, section): """ Get the named tuple representing the configuration held at `section`. Build a named tuple representing the configuration at `section`. If a config file does not have an option for the section ignore it. Resulting in an AttributeError if accessed later in the code. :param section: the section to retrieve """ def _getattr_wrapper(t, attr): """ Replace the standard __getattr__ functionality. In the case when a section and/or attribute is not set in the config file, the error shown will be more helpful. """ try: return t.__getattribute__(attr) except AttributeError as exc: exc.args = ( ( f'Unable to locate attribute "{attr}" ' f'in section "{type(t).__name__}" ' f'at config file "{self._cfg_file}"' ), ) raise exc env_vars = [ k for k in os.environ.keys() if k.startswith(f'{section.upper()}_') ] env_keys = [ k.split(section.upper())[1].lstrip('_').lower() for k in env_vars ] env_values = [os.environ[e] for e in env_vars] if env_vars: logger.debug( f'Loading credentials from ENV vars: {", ".join(env_vars)}' ) params = [] if self._cfg.has_section(section): params = self._cfg.options(section) values = [self._cfg.get(section, x) for x in params] d = OrderedDict(zip(params, values)) if env_vars: d.update(zip(env_keys, env_values)) t = namedtuple(section, ' '.join(list(d.keys()))) t.__getattr__ = _getattr_wrapper return t(*list(d.values()))
[docs] def get(self, section, key=None, account=None, default=_sentinel): """ Retrieve sections and keys by account. ``section``: the section from which to retrieve keys. ``key``: the key in the section whose value you want to retrieve. if not specified, returns the whole section as a dictionary. ``account``: if provided, fetches the value for the specific account. assumes the account is prefixed to the key and separated by _. ``default``: if provided, returns this value if a value cannot be found; otherwise raises an exception. """ if key is None: return self[section] if account: key = '_'.join([account, key]) if default == _sentinel: return getattr(self[section], key) else: return getattr(self[section], key, default)