anvil/devstack/progs/actions.py
2012-02-28 10:44:50 -08:00

272 lines
10 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! Inc. 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..
from devstack import env_rc
from devstack import exceptions as excp
from devstack import log as logging
from devstack import settings
from devstack import shell as sh
from devstack import utils
from devstack.progs import common
LOG = logging.getLogger("devstack.progs.actions")
# For actions in this list we will reverse the component order
_REVERSE_ACTIONS = [settings.UNINSTALL, settings.STOP]
# For these actions we will attempt to make an rc file if it does not exist
_RC_FILE_MAKE_ACTIONS = [settings.INSTALL, settings.START]
# The order of which uninstalls happen + message of what is happening (before and after)
UNINSTALL_ORDERING = [
(
"Unconfiguring {name}.",
(lambda instance: (instance.unconfigure())),
None,
),
(
"Pre-uninstalling {name}.",
(lambda instance: (instance.pre_uninstall())),
None,
),
(
"Uninstalling {name}.",
(lambda instance: (instance.uninstall())),
None,
),
(
"Post-uninstalling {name}.",
(lambda instance: (instance.post_uninstall())),
None,
),
]
# The order of which starts happen + message of what is happening (before and after)
STARTS_ORDERING = [
(
"Configuring runner for {name}.",
(lambda instance: (instance.configure())),
None,
),
(
"Pre-starting {name}.",
(lambda instance: (instance.pre_start())),
None,
),
(
"Starting {name}.",
(lambda instance: (instance.start())),
"Started {result} applications.",
),
(
"Post-starting {name}.",
(lambda instance:(instance.post_start())),
None,
),
]
# The order of which stops happen + message of what is happening (before and after)
STOPS_ORDERING = [
(
"Stopping {name}.",
(lambda instance:(instance.stop())),
"Stopped {result} items.",
),
]
# The order of which install happen + message of what is happening (before and after)
INSTALL_ORDERING = [
(
"Downloading {name}.",
(lambda instance: (instance.download())),
"Performed {result} downloads.",
),
(
"Configuring {name}.",
(lambda instance: (instance.configure())),
"Configured {result} items.",
),
(
"Pre-installing {name}.",
(lambda instance: (instance.pre_install())),
None,
),
(
"Installing {name}.",
(lambda instance: (instance.install())),
"Finished install of {name} - check {result} for traces of what happened.",
),
(
"Post-installing {name}.",
(lambda instance: (instance.post_install())),
None,
),
]
# Map of action name to action order
ACTION_MP = {
settings.START: STARTS_ORDERING,
settings.STOP: STOPS_ORDERING,
settings.INSTALL: INSTALL_ORDERING,
settings.UNINSTALL: UNINSTALL_ORDERING,
}
# These actions must have there prerequisite action accomplished (if determined by the boolean lambda to be needed)
PREQ_ACTIONS = {
settings.START: ((lambda instance: (not instance.is_installed())), settings.INSTALL),
settings.UNINSTALL: ((lambda instance: (instance.is_started())), settings.STOP),
}
class ActionRunner(object):
def __init__(self, distro, action, directory, config, pkg_manager, **kargs):
self.distro = distro
self.action = action
self.directory = directory
self.cfg = config
self.pkg_manager = pkg_manager
self.kargs = kargs
self.components = kargs.pop("components")
self.force = kargs.get('force', False)
self.ignore_deps = kargs.get('ignore_deps', False)
self.ref_components = kargs.get("ref_components")
self.rc_file = sh.abspth(settings.OSRC_FN)
self.gen_rc = action in _RC_FILE_MAKE_ACTIONS
def _get_components(self):
components = self.components
if not components:
components = common.get_default_components(self.distro)
LOG.info("Activating default components [%s]" % (", ".join(sorted(components.keys()))))
else:
LOG.info("Activating components [%s]" % (", ".join(sorted(components.keys()))))
return components
def _order_components(self, components):
adjusted_components = dict(components)
if self.ignore_deps:
return (adjusted_components, list(components.keys()))
all_components = common.get_components_deps(self.action, components, self.distro, self.directory)
component_diff = set(all_components.keys()).difference(components.keys())
if component_diff:
LOG.info("Having to activate dependent components: [%s]" % (", ".join(sorted(component_diff))))
for new_component in component_diff:
adjusted_components[new_component] = list()
return (adjusted_components, utils.get_components_order(all_components))
def _inject_references(self, components):
ref_components = utils.parse_components(self.ref_components)
adjusted_components = dict(components)
for c in ref_components.keys():
if c not in components:
adjusted_components[c] = ref_components.get(c)
return adjusted_components
def _instanciate_components(self, components):
all_instances = dict()
for component in components.keys():
cls = common.get_action_cls(self.action, component, self.distro)
instance = cls(instances=all_instances,
distro=self.distro,
packager=self.pkg_manager,
config=self.cfg,
root=self.directory,
opts=components.get(component, list()))
all_instances[component] = instance
return all_instances
def _run_preqs(self, components, component_order):
if not (self.action in PREQ_ACTIONS):
return
(check_functor, preq_action) = PREQ_ACTIONS[self.action]
instances = self._instanciate_components(components)
preq_components = dict()
for c in component_order:
instance = instances[c]
if check_functor(instance):
preq_components[c] = components[c]
if preq_components:
LOG.info("Having to activate prerequisite action [%s] for %s components." % (preq_action, len(preq_components)))
preq_runner = ActionRunner(self.distro, preq_action,
self.directory, self.cfg, self.pkg_manager,
components=preq_components, **self.kargs)
preq_runner.rc_file = self.rc_file
preq_runner.run()
def _pre_run(self, instances, component_order):
loaded_rc_file = False
if self.rc_file:
try:
if sh.isfile(self.rc_file):
LOG.info("Attempting to load rc file at [%s] which has your environment settings." % (self.rc_file))
am_loaded = env_rc.RcLoader().load(self.rc_file)
LOG.info("Loaded [%s] settings from rc file [%s]" % (am_loaded, self.rc_file))
loaded_rc_file = True
except IOError:
LOG.warn('Error reading rc file located at [%s]. Skipping loading it.' % (self.rc_file))
LOG.info("Verifying that the components are ready to rock-n-roll.")
for component in component_order:
inst = instances[component]
inst.verify()
LOG.info("Warming up your component configurations (ie so you won't be prompted later)")
for component in component_order:
inst = instances[component]
inst.warm_configs()
if self.gen_rc and not loaded_rc_file and self.rc_file:
LOG.info("Generating a file at [%s] that will contain your environment settings." % (self.rc_file))
creator = env_rc.RcGenerator(self.cfg)
contents = creator.generate()
sh.write_file(self.rc_file, contents)
if self.rc_file:
self.rc_file = None
def _run_instances(self, instances, component_order):
component_order = self._apply_reverse(component_order)
LOG.info("Running in the following order: %s" % ("->".join(component_order)))
for (start_msg, functor, end_msg) in ACTION_MP[self.action]:
for c in component_order:
instance = instances[c]
if start_msg:
LOG.info(start_msg.format(name=c))
result = None
try:
result = functor(instance)
except (excp.NoTraceException) as e:
if self.force:
LOG.debug("Skipping exception [%s]" % (e))
else:
raise
if end_msg:
LOG.info(end_msg.format(name=c, result=result))
def _apply_reverse(self, component_order):
adjusted_order = list(component_order)
if self.action in _REVERSE_ACTIONS:
adjusted_order.reverse()
return adjusted_order
def _start(self, components, component_order):
LOG.info("Activating components required to complete action [%s]" % (self.action))
instances = self._instanciate_components(components)
self._pre_run(instances, component_order)
self._run_preqs(components, component_order)
self._run_instances(instances, component_order)
def run(self):
(components, component_order) = self._order_components(self._get_components())
self._start(self._inject_references(components), component_order)