senlin/senlin/engine/environment.py

229 lines
7.5 KiB
Python

# 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 glob
import os.path
from stevedore import extension
from oslo_config import cfg
from oslo_log import log as logging
from senlin.common import exception
from senlin.common.i18n import _
from senlin.engine import parser
from senlin.engine import registry
LOG = logging.getLogger(__name__)
_environment = None
def global_env():
global _environment
if _environment is None:
initialize()
return _environment
class Environment(object):
"""An object that contains all profiles, policies and customizations."""
SECTIONS = (
PARAMETERS, CUSTOM_PROFILES, CUSTOM_POLICIES,
) = (
'parameters', 'custom_profiles', 'custom_policies',
)
def __init__(self, env=None, is_global=False):
"""Create an Environment from a dict.
:param env: the json environment
:param is_global: boolean indicating if this is a user created one.
"""
self.params = {}
if is_global:
self.profile_registry = registry.Registry('profiles')
self.policy_registry = registry.Registry('policies')
self.driver_registry = registry.Registry('drivers')
self.endpoint_registry = registry.Registry('endpoints')
else:
self.profile_registry = registry.Registry(
'profiles', global_env().profile_registry)
self.policy_registry = registry.Registry(
'policies', global_env().policy_registry)
self.driver_registry = registry.Registry(
'drivers', global_env().driver_registry)
self.endpoint_registry = registry.Registry(
'endpoints', global_env().endpoint_registry)
if env is not None:
# Merge user specified keys with current environment
self.params = env.get(self.PARAMETERS, {})
custom_profiles = env.get(self.CUSTOM_PROFILES, {})
custom_policies = env.get(self.CUSTOM_POLICIES, {})
self.profile_registry.load(custom_profiles)
self.policy_registry.load(custom_policies)
def parse(self, env_str):
"""Parse a string format environment file into a dictionary."""
if env_str is None:
return {}
env = parser.simple_parse(env_str)
# Check unknown sections
for sect in env:
if sect not in self.SECTIONS:
msg = _('environment has unknown section "%s"') % sect
raise ValueError(msg)
# Fill in default values for missing sections
for sect in self.SECTIONS:
if sect not in env:
env[sect] = {}
return env
def load(self, env_dict):
"""Load environment from the given dictionary."""
self.params.update(env_dict.get(self.PARAMETERS, {}))
self.profile_registry.load(env_dict.get(self.CUSTOM_PROFILES, {}))
self.policy_registry.load(env_dict.get(self.CUSTOM_POLICIES, {}))
def _check_plugin_name(self, plugin_type, name):
if name is None or name == "":
msg = _('%s type name not specified') % plugin_type
raise exception.InvalidPlugin(message=msg)
elif not isinstance(name, str):
msg = _('%s type name is not a string') % plugin_type
raise exception.InvalidPlugin(message=msg)
def register_profile(self, name, plugin):
self._check_plugin_name('Profile', name)
self.profile_registry.register_plugin(name, plugin)
def get_profile(self, name):
self._check_plugin_name('Profile', name)
plugin = self.profile_registry.get_plugin(name)
if plugin is None:
raise exception.ResourceNotFound(type='profile_type', id=name)
return plugin
def get_profile_types(self):
return self.profile_registry.get_types()
def register_policy(self, name, plugin):
self._check_plugin_name('Policy', name)
self.policy_registry.register_plugin(name, plugin)
def get_policy(self, name):
self._check_plugin_name('Policy', name)
plugin = self.policy_registry.get_plugin(name)
if plugin is None:
raise exception.ResourceNotFound(type='policy_type', id=name)
return plugin
def get_policy_types(self):
return self.policy_registry.get_types()
def register_driver(self, name, plugin):
self._check_plugin_name('Driver', name)
self.driver_registry.register_plugin(name, plugin)
def get_driver(self, name):
self._check_plugin_name('Driver', name)
plugin = self.driver_registry.get_plugin(name)
if plugin is None:
msg = _('Driver plugin %(name)s is not found.') % {'name': name}
raise exception.InvalidPlugin(message=msg)
return plugin
def get_driver_types(self):
return self.driver_registry.get_types()
def register_endpoint(self, name, plugin):
self._check_plugin_name('Endpoint', name)
plugin = self.endpoint_registry.register_plugin(name, plugin)
def get_endpoint(self, name):
self._check_plugin_name('Endpoint', name)
plugin = self.endpoint_registry.get_plugin(name)
if plugin is None:
msg = _('Endpoint plugin %(name)s is not found.') % {'name': name}
raise exception.InvalidPlugin(message=msg)
return plugin
def read_global_environment(self):
"""Read and parse global environment files."""
cfg.CONF.import_opt('environment_dir', 'senlin.conf')
env_dir = cfg.CONF.environment_dir
try:
files = glob.glob(os.path.join(env_dir, '*'))
except OSError as ex:
LOG.error('Failed to read %s', env_dir)
LOG.exception(ex)
return
for fname in files:
try:
with open(fname) as f:
LOG.info('Loading environment from %s', fname)
self.load(self.parse(f.read()))
except ValueError as vex:
LOG.error('Failed to parse %s', fname)
LOG.exception(str(vex))
except IOError as ioex:
LOG.error('Failed to read %s', fname)
LOG.exception(str(ioex))
def _get_mapping(namespace):
mgr = extension.ExtensionManager(
namespace=namespace,
invoke_on_load=False)
return [[name, mgr[name].plugin] for name in mgr.names()]
def initialize():
global _environment
if _environment is not None:
return
env = Environment(is_global=True)
# Register global plugins when initialized
entries = _get_mapping('senlin.profiles')
for name, plugin in entries:
env.register_profile(name, plugin)
entries = _get_mapping('senlin.policies')
for name, plugin in entries:
env.register_policy(name, plugin)
entries = _get_mapping('senlin.drivers')
for name, plugin in entries:
env.register_driver(name, plugin)
entries = _get_mapping('senlin.endpoints')
for name, plugin in entries:
env.register_endpoint(name, plugin)
env.read_global_environment()
_environment = env