1# Copyright (c) 2012 Rackspace Hosting
2# All Rights Reserved.
3#
4#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5#    not use this file except in compliance with the License. You may obtain
6#    a copy of the License at
7#
8#         http://www.apache.org/licenses/LICENSE-2.0
9#
10#    Unless required by applicable law or agreed to in writing, software
11#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13#    License for the specific language governing permissions and limitations
14#    under the License.
15
16"""Configuration support for all drivers.
17
18This module allows support for setting configurations either from default
19or from a particular FLAGS group, to be able to set multiple configurations
20for a given set of values.
21
22For instance, two lvm configurations can be set by naming them in groups as
23
24 [lvm1]
25 volume_group=lvm-group-1
26 ...
27
28 [lvm2]
29 volume_group=lvm-group-2
30 ...
31
32And the configuration group name will be passed in so that all calls to
33configuration.volume_group within that instance will be mapped to the proper
34named group.
35
36This class also ensures the implementation's configuration is grafted into the
37option group. This is due to the way cfg works. All cfg options must be defined
38and registered in the group in which they are used.
39"""
40
41
42from oslo_config import cfg
43
44
45CONF = cfg.CONF
46SHARED_CONF_GROUP = 'backend_defaults'
47
48
49class DefaultGroupConfiguration(object):
50    """Get config options from only DEFAULT."""
51
52    def __init__(self):
53        # set the local conf so that __call__'s know what to use
54        self.local_conf = CONF
55
56    def _ensure_config_values(self, volume_opts):
57        CONF.register_opts(volume_opts, group=None)
58
59    def append_config_values(self, volume_opts):
60        self._ensure_config_values(volume_opts)
61
62    def safe_get(self, value):
63        try:
64            return self.__getattr__(value)
65        except cfg.NoSuchOptError:
66            return None
67
68    def __getattr__(self, value):
69        # Don't use self.local_conf to avoid reentrant call to __getattr__()
70        local_conf = object.__getattribute__(self, 'local_conf')
71        return getattr(local_conf, value)
72
73
74class BackendGroupConfiguration(object):
75
76    def __init__(self, volume_opts, config_group=None):
77        """Initialize configuration.
78
79        This takes care of grafting the implementation's config
80        values into the config group and shared defaults. We will try to
81        pull values from the specified 'config_group', but fall back to
82        defaults from the SHARED_CONF_GROUP.
83        """
84        self.config_group = config_group
85
86        # set the local conf so that __call__'s know what to use
87        self._ensure_config_values(volume_opts)
88        self.backend_conf = CONF._get(self.config_group)
89        self.shared_backend_conf = CONF._get(SHARED_CONF_GROUP)
90
91    def _safe_register(self, opt, group):
92        try:
93            CONF.register_opt(opt, group=group)
94        except cfg.DuplicateOptError:
95            pass  # If it's already registered ignore it
96
97    def _ensure_config_values(self, volume_opts):
98        """Register the options in the shared group.
99
100        When we go to get a config option we will try the backend specific
101        group first and fall back to the shared group. We override the default
102        from all the config options for the backend group so we can know if it
103        was set or not.
104        """
105        for opt in volume_opts:
106            self._safe_register(opt, SHARED_CONF_GROUP)
107            # Assuming they aren't the same groups, graft on the options into
108            # the backend group and override its default value.
109            if self.config_group != SHARED_CONF_GROUP:
110                self._safe_register(opt, self.config_group)
111                CONF.set_default(opt.name, None, group=self.config_group)
112
113    def append_config_values(self, volume_opts):
114        self._ensure_config_values(volume_opts)
115
116    def set_default(self, opt_name, default):
117        CONF.set_default(opt_name, default, group=SHARED_CONF_GROUP)
118
119    def get(self, key, default=None):
120        return getattr(self, key, default)
121
122    def safe_get(self, value):
123        try:
124            return self.__getattr__(value)
125        except cfg.NoSuchOptError:
126            return None
127
128    def __getattr__(self, opt_name):
129        # Don't use self.X to avoid reentrant call to __getattr__()
130        backend_conf = object.__getattribute__(self, 'backend_conf')
131        opt_value = getattr(backend_conf, opt_name)
132        if opt_value is None:
133            shared_conf = object.__getattribute__(self, 'shared_backend_conf')
134            opt_value = getattr(shared_conf, opt_name)
135        return opt_value
136
137
138class Configuration(object):
139
140    def __init__(self, volume_opts, config_group=None):
141        """Initialize configuration.
142
143        This shim will allow for compatibility with the DEFAULT
144        style of backend configuration which is used by some of the users
145        of this configuration helper, or by the volume drivers that have
146        all been forced over to the config_group style.
147        """
148        self.config_group = config_group
149        if config_group:
150            self.conf = BackendGroupConfiguration(volume_opts, config_group)
151        else:
152            self.conf = DefaultGroupConfiguration()
153
154    def append_config_values(self, volume_opts):
155        self.conf.append_config_values(volume_opts)
156
157    def safe_get(self, value):
158        return self.conf.safe_get(value)
159
160    def __getattr__(self, value):
161        # Don't use self.conf to avoid reentrant call to __getattr__()
162        conf = object.__getattribute__(self, 'conf')
163        return getattr(conf, value)
164