anvil/devstack/distro.py
Doug Hellmann 679f33b242 Make all of the packager method signatures consistent by moving the loops for pre_install and post_install into the component method where the packager is invoked.
Have the component get a packager for each package and use that, falling back to a default provided by the distro. This will allow us to override the packaging rules for specific packages by providing a class reference in the distro file.
2012-03-23 16:46:15 -04:00

149 lines
5.5 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
# Copyright (C) 2012 New Dream Network, LLC (DreamHost) All Rights Reserved.
#
# 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 platform
import re
import shlex
import yaml
from devstack import decorators
from devstack import importer
from devstack import log as logging
from devstack import settings
from devstack import shell as sh
LOG = logging.getLogger('devstack.distro')
class Distro(object):
@classmethod
def load_all(cls, path=settings.STACK_DISTRO_DIR):
"""Returns a list of the known distros."""
results = []
input_files = glob.glob(sh.joinpths(path, '*.yaml'))
if not input_files:
raise RuntimeError(
'Did not find any distro definition files in %s' %
path)
for fn in input_files:
cls_kvs = None
filename = sh.abspth(fn)
LOG.audit("Attempting to load distro definition from [%s]" % (filename))
try:
with open(filename, 'r') as f:
cls_kvs = yaml.load(f)
except (IOError, yaml.YAMLError) as err:
LOG.warning('Could not load distro definition from %s: %s',
filename, err)
if cls_kvs is not None:
try:
results.append(cls(**cls_kvs))
except Exception as err:
LOG.warning('Could not initialize instance %s using parameter map %s: %s',
cls, cls_kvs, err)
return results
@classmethod
def get_current(cls):
"""Returns a Distro instance configured for the current system."""
plt = platform.platform()
distname = platform.linux_distribution()[0]
if not distname:
raise RuntimeError('Unsupported platform %s' % plt)
LOG.debug('Looking for distro data for %s (%s)', plt, distname)
for p in cls.load_all():
if p.supports_distro(plt):
LOG.info('Using distro "%s" for platform "%s"', p.name, plt)
return p
else:
raise RuntimeError(
'No platform configuration data for %s (%s)' %
(plt, distname))
@decorators.log_debug
def __init__(self, name, distro_pattern, packager_name, commands, components):
self.name = name
self._distro_pattern = re.compile(distro_pattern, re.IGNORECASE)
self._packager_name = packager_name
self._commands = commands
self._components = components
def get_command_config(self, key, *more_keys, **kargs):
""" Gets a end object for a given set of keys """
root = self._commands
acutal_keys = [key] + list(more_keys)
run_over_keys = acutal_keys[0:-1]
end_key = acutal_keys[-1]
quiet = kargs.get('quiet', False)
LOG.debug("Running over keys (%s)" % (", ".join(run_over_keys)))
LOG.debug("End key is (%s)" % (end_key))
for k in run_over_keys:
if quiet:
root = root.get(k)
if root is None:
return None
else:
root = root[k]
end_value = None
if not quiet:
end_value = root[end_key]
else:
end_value = root.get(end_key)
LOG.debug("Retrieved end command config: %s", end_value)
return end_value
def get_command(self, key, *more_keys, **kargs):
"""Retrieves a string for running a command from the setup
and splits it to return a list.
"""
val = self.get_command_config(key, *more_keys, **kargs)
ret_val = shlex.split(val) if val else []
LOG.debug("Parsed configured command: %s", ret_val)
return ret_val
def known_component(self, name):
return name in self._components
def supports_distro(self, distro_name):
"""Does this distro support the named Linux distro?
:param distro_name: Return value from platform.linux_distribution().
"""
return bool(self._distro_pattern.search(distro_name))
def get_default_package_manager(self):
"""Return a package manager that will work for this distro."""
return importer.import_entry_point(self._packager_name)(self)
def extract_component(self, name, action):
"""Return the class + component info to use for doing the action w/the component."""
try:
# Use a copy instead of the original
component_info = dict(self._components[name])
entry_point = component_info['action_classes'][action]
cls = importer.import_entry_point(entry_point)
# Remove action class info
if 'action_classes' in component_info:
del component_info['action_classes']
return (cls, component_info)
except KeyError:
raise RuntimeError('No class configured to %s %s on %s' %
(action, name, self.name))