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