def _get_extra_config(self, key, defaults=None):
        """Fetch an arbitrary extra chunk of config, laying in defaults.

        :param string key: name of the config section to fetch
        :param dict defaults: (optional) default values to merge under the
                                         found config
        """
        defaults = _util.normalize_keys(defaults or {})
        if not key:
            return defaults
        return _util.merge_clouds(
            defaults, _util.normalize_keys(self._extra_config.get(key, {})))
Esempio n. 2
0
def get_profile(profile_name):
    vendor_defaults = _get_vendor_defaults()
    if profile_name in vendor_defaults:
        return vendor_defaults[profile_name].copy()
    profile_url = urllib.parse.urlparse(profile_name)
    if not profile_url.netloc:
        # This isn't a url, and we already don't have it.
        return
    well_known_url = _WELL_KNOWN_PATH.format(
        scheme=profile_url.scheme,
        netloc=profile_url.netloc,
    )
    response = requests.get(well_known_url)
    if not response.ok:
        raise exceptions.ConfigException(
            "{profile_name} is a remote profile that could not be fetched:"
            " {status_code} {reason}".format(
                profile_name=profile_name,
                status_code=response.status_code,
                reason=response.reason))
        vendor_defaults[profile_name] = None
        return
    vendor_data = response.json()
    name = vendor_data['name']
    # Merge named and url cloud config, but make named config override the
    # config from the cloud so that we can supply local overrides if needed.
    profile = _util.merge_clouds(
        vendor_data['profile'],
        vendor_defaults.get(name, {}))
    # If there is (or was) a profile listed in a named config profile, it
    # might still be here. We just merged in content from a URL though, so
    # pop the key to prevent doing it again in the future.
    profile.pop('profile', None)
    # Save the data under both names so we don't reprocess this, no matter
    # how we're called.
    vendor_defaults[profile_name] = profile
    vendor_defaults[name] = profile
    return profile
Esempio n. 3
0
def get_profile(profile_name):
    vendor_defaults = _get_vendor_defaults()
    if profile_name in vendor_defaults:
        return vendor_defaults[profile_name].copy()
    profile_url = urllib.parse.urlparse(profile_name)
    if not profile_url.netloc:
        # This isn't a url, and we already don't have it.
        return
    well_known_url = _WELL_KNOWN_PATH.format(
        scheme=profile_url.scheme,
        netloc=profile_url.netloc,
    )
    response = requests.get(well_known_url)
    if not response.ok:
        raise exceptions.ConfigException(
            "{profile_name} is a remote profile that could not be fetched:"
            " {status_code} {reason}".format(
                profile_name=profile_name,
                status_code=response.status_code,
                reason=response.reason))
        vendor_defaults[profile_name] = None
        return
    vendor_data = response.json()
    name = vendor_data['name']
    # Merge named and url cloud config, but make named config override the
    # config from the cloud so that we can supply local overrides if needed.
    profile = _util.merge_clouds(
        vendor_data['profile'],
        vendor_defaults.get(name, {}))
    # If there is (or was) a profile listed in a named config profile, it
    # might still be here. We just merged in content from a URL though, so
    # pop the key to prevent doing it again in the future.
    profile.pop('profile', None)
    # Save the data under both names so we don't reprocess this, no matter
    # how we're called.
    vendor_defaults[profile_name] = profile
    vendor_defaults[name] = profile
    return profile
Esempio n. 4
0
    def __init__(self,
                 config_files=None,
                 vendor_files=None,
                 override_defaults=None,
                 force_ipv4=None,
                 envvar_prefix=None,
                 secure_files=None,
                 pw_func=None,
                 session_constructor=None,
                 app_name=None,
                 app_version=None,
                 load_yaml_config=True,
                 load_envvars=True):
        self.log = _log.setup_logging('openstack.config')
        self._session_constructor = session_constructor
        self._app_name = app_name
        self._app_version = app_version
        self._load_envvars = load_envvars

        if load_yaml_config:
            self._config_files = config_files or CONFIG_FILES
            self._secure_files = secure_files or SECURE_FILES
            self._vendor_files = vendor_files or VENDOR_FILES
        else:
            self._config_files = []
            self._secure_files = []
            self._vendor_files = []

        config_file_override = self._get_envvar('OS_CLIENT_CONFIG_FILE')
        if config_file_override:
            self._config_files.insert(0, config_file_override)

        secure_file_override = self._get_envvar('OS_CLIENT_SECURE_FILE')
        if secure_file_override:
            self._secure_files.insert(0, secure_file_override)

        self.defaults = self._defaults_module.get_defaults()
        if override_defaults:
            self.defaults.update(override_defaults)

        # First, use a config file if it exists where expected
        self.config_filename, self.cloud_config = self._load_config_file()
        _, secure_config = self._load_secure_file()
        if secure_config:
            self.cloud_config = _util.merge_clouds(self.cloud_config,
                                                   secure_config)

        if not self.cloud_config:
            self.cloud_config = {'clouds': {}}
        if 'clouds' not in self.cloud_config:
            self.cloud_config['clouds'] = {}

        # Save the other config
        self.extra_config = copy.deepcopy(self.cloud_config)
        self.extra_config.pop('clouds', None)

        # Grab ipv6 preference settings from env
        client_config = self.cloud_config.get('client', {})

        if force_ipv4 is not None:
            # If it's passed in to the constructor, honor it.
            self.force_ipv4 = force_ipv4
        else:
            # Get the backwards compat value
            prefer_ipv6 = get_boolean(
                self._get_envvar(
                    'OS_PREFER_IPV6',
                    client_config.get('prefer_ipv6',
                                      client_config.get('prefer-ipv6', True))))
            force_ipv4 = get_boolean(
                self._get_envvar(
                    'OS_FORCE_IPV4',
                    client_config.get('force_ipv4',
                                      client_config.get('broken-ipv6',
                                                        False))))

            self.force_ipv4 = force_ipv4
            if not prefer_ipv6:
                # this will only be false if someone set it explicitly
                # honor their wishes
                self.force_ipv4 = True

        # Next, process environment variables and add them to the mix
        self.envvar_key = self._get_envvar('OS_CLOUD_NAME', 'envvars')
        if self.envvar_key in self.cloud_config['clouds']:
            raise exceptions.ConfigException(
                '"{0}" defines a cloud named "{1}", but'
                ' OS_CLOUD_NAME is also set to "{1}". Please rename'
                ' either your environment based cloud, or one of your'
                ' file-based clouds.'.format(self.config_filename,
                                             self.envvar_key))

        self.default_cloud = self._get_envvar('OS_CLOUD')

        if load_envvars:
            envvars = self._get_os_environ(envvar_prefix=envvar_prefix)
            if envvars:
                self.cloud_config['clouds'][self.envvar_key] = envvars
                if not self.default_cloud:
                    self.default_cloud = self.envvar_key

        if not self.default_cloud and self.cloud_config['clouds']:
            if len(self.cloud_config['clouds'].keys()) == 1:
                # If there is only one cloud just use it. This matches envvars
                # behavior and allows for much less typing.
                # TODO(mordred) allow someone to mark a cloud as "default" in
                # clouds.yaml.
                # The next/iter thing is for python3 compat where dict.keys
                # returns an iterator but in python2 it's a list.
                self.default_cloud = next(
                    iter(self.cloud_config['clouds'].keys()))

        # Finally, fall through and make a cloud that starts with defaults
        # because we need somewhere to put arguments, and there are neither
        # config files or env vars
        if not self.cloud_config['clouds']:
            self.cloud_config = dict(clouds=dict(defaults=dict(self.defaults)))
            self.default_cloud = 'defaults'

        self._cache_expiration_time = 0
        self._cache_path = CACHE_PATH
        self._cache_class = 'dogpile.cache.null'
        self._cache_arguments = {}
        self._cache_expirations = {}
        if 'cache' in self.cloud_config:
            cache_settings = _util.normalize_keys(self.cloud_config['cache'])

            # expiration_time used to be 'max_age' but the dogpile setting
            # is expiration_time. Support max_age for backwards compat.
            self._cache_expiration_time = cache_settings.get(
                'expiration_time',
                cache_settings.get('max_age', self._cache_expiration_time))

            # If cache class is given, use that. If not, but if cache time
            # is given, default to memory. Otherwise, default to nothing.
            # to memory.
            if self._cache_expiration_time:
                self._cache_class = 'dogpile.cache.memory'
            self._cache_class = self.cloud_config['cache'].get(
                'class', self._cache_class)

            self._cache_path = os.path.expanduser(
                cache_settings.get('path', self._cache_path))
            self._cache_arguments = cache_settings.get('arguments',
                                                       self._cache_arguments)
            self._cache_expirations = cache_settings.get(
                'expiration', self._cache_expirations)

        # Flag location to hold the peeked value of an argparse timeout value
        self._argv_timeout = False

        # Save the password callback
        # password = self._pw_callback(prompt="Password: ")
        self._pw_callback = pw_func