summaryrefslogtreecommitdiff
path: root/keystonemiddleware/_common/config.py
blob: 3e38eba176c6d141c8f745bc140d02efcafaf823 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# 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.

import pkg_resources

from oslo_config import cfg
from oslo_log import log as logging
import pbr

from keystonemiddleware import exceptions
from keystonemiddleware.i18n import _

CONF = cfg.CONF
_NOT_SET = object()
_LOG = logging.getLogger(__name__)


def _conf_values_type_convert(group_name, all_options, conf):
    """Convert conf values into correct type."""
    if not conf:
        return {}

    opts = {}
    opt_types = {}

    for group, options in all_options:
        # only accept paste overrides for the primary group
        if group != group_name:
            continue

        for o in options:
            type_dest = (getattr(o, 'type', str), o.dest)
            opt_types[o.dest] = type_dest
            # Also add the deprecated name with the same type and dest.
            for d_o in o.deprecated_opts:
                opt_types[d_o.name] = type_dest

        break

    for k, v in conf.items():
        dest = k
        try:
            if v is not None:
                type_, dest = opt_types[k]
                v = type_(v)
        except KeyError:  # nosec
            # This option is not known to auth_token. v is not converted.
            _LOG.warning(
                'The option "%s" in conf is not known to auth_token', k)
        except ValueError as e:
            raise exceptions.ConfigurationError(
                _('Unable to convert the value of %(key)s option into correct '
                  'type: %(ex)s') % {'key': k, 'ex': e})
        opts[dest] = v

    return opts


class Config(object):

    def __init__(self, name, group_name, all_options, conf):
        local_oslo_config = conf.pop('oslo_config_config', None)
        local_config_project = conf.pop('oslo_config_project', None)
        local_config_file = conf.pop('oslo_config_file', None)

        # NOTE(wanghong): If options are set in paste file, all the option
        # values passed into conf are string type. So, we should convert the
        # conf value into correct type.
        self.paste_overrides = _conf_values_type_convert(group_name,
                                                         all_options,
                                                         conf)

        # NOTE(sileht, cdent): If we don't want to use oslo.config global
        # object there are two options: set "oslo_config_project" in
        # paste.ini and the middleware will load the configuration with a
        # local oslo.config object or the caller which instantiates
        # AuthProtocol can pass in an existing oslo.config as the
        # value of the "oslo_config_config" key in conf. If both are
        # set "olso_config_config" is used.
        if local_config_project and not local_oslo_config:
            config_files = [local_config_file] if local_config_file else None

            local_oslo_config = cfg.ConfigOpts()
            local_oslo_config([],
                              project=local_config_project,
                              default_config_files=config_files,
                              validate_default_values=True)

        if local_oslo_config:
            for group, opts in all_options:
                local_oslo_config.register_opts(opts, group=group)

        self.name = name
        self.oslo_conf_obj = local_oslo_config or cfg.CONF
        self.group_name = group_name
        self._user_agent = None

    def get(self, name, group=_NOT_SET):
        # try config from paste-deploy first
        try:
            return self.paste_overrides[name]
        except KeyError:
            if group is _NOT_SET:
                group = self.group_name

            return self.oslo_conf_obj[group][name]

    @property
    def project(self):
        """Determine a project name from all available config sources.

        The sources are checked in the following order:

          1. The paste-deploy config for auth_token middleware
          2. The keystone_authtoken or base group in the project's config
          3. The oslo.config CONF.project property

        """
        try:
            return self.get('project', group=self.group_name)
        except cfg.NoSuchOptError:
            try:
                # CONF.project will exist only if the service uses
                # oslo.config. It will only be set when the project
                # calls CONF(...) and when not set oslo.config oddly
                # raises a NoSuchOptError exception.
                return self.oslo_conf_obj.project
            except cfg.NoSuchOptError:
                return None

    @property
    def user_agent(self):
        if not self._user_agent:
            project = self.project or ''

            if project:
                try:
                    version = pkg_resources.get_distribution(project).version
                except pkg_resources.DistributionNotFound:
                    version = "unknown"

                project = "%s/%s " % (project, version)

            self._user_agent = "%skeystonemiddleware.%s/%s" % (
                project,
                self.name,
                pbr.version.VersionInfo('keystonemiddleware').version_string())

        return self._user_agent