#!/usr/bin/env 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 operator import os import os.path import sys #TODO is this needed? sys.path.append("devstack") import Logger import Options from Util import (welcome, rcf8222date, determine_os, get_pkg_list, fetch_deps) from Util import (NOVA, GLANCE, QUANTUM, SWIFT, KEYSTONE, HORIZON, DB, RABBIT, INSTALL, UNINSTALL, START, STOP, ACTIONS, COMPONENT_NAMES, NAMES_PRIORITY, UBUNTU11, RHEL6, STACK_CFG_LOC) from Shell import (mkdir, joinpths, unlink) from Config import (EnvConfigParser) from Exceptions import (NoTraceException) import Glance import Horizon import Keystone import Nova import Quantum import Config import Swift import Db import Rabbit LOG = Logger.getLogger("install") #this determines what classes to use to install/uninstall/... ACTION_CLASSES = { INSTALL: { NOVA: Nova.NovaInstaller, GLANCE: Glance.GlanceInstaller, QUANTUM: Quantum.QuantumInstaller, SWIFT: Swift.SwiftInstaller, HORIZON: Horizon.HorizonInstaller, KEYSTONE: Keystone.KeystoneInstaller, DB: Db.DBInstaller, RABBIT: Rabbit.RabbitInstaller, }, UNINSTALL: { NOVA: Nova.NovaUninstaller, GLANCE: Glance.GlanceUninstaller, QUANTUM: Quantum.QuantumUninstaller, SWIFT: Swift.SwiftUninstaller, HORIZON: Horizon.HorizonUninstaller, KEYSTONE: Keystone.KeystoneUninstaller, DB: Db.DBUninstaller, RABBIT: Rabbit.RabbitUninstaller, }, START: { NOVA: Nova.NovaRuntime, GLANCE: Glance.GlanceRuntime, QUANTUM: Quantum.QuantumRuntime, SWIFT: Swift.SwiftRuntime, HORIZON: Horizon.HorizonRuntime, KEYSTONE: Keystone.KeystoneRuntime, DB: Db.DBRuntime, RABBIT: Rabbit.RabbitRuntime, }, STOP: { NOVA: Nova.NovaRuntime, GLANCE: Glance.GlanceRuntime, QUANTUM: Quantum.QuantumRuntime, SWIFT: Swift.SwiftRuntime, HORIZON: Horizon.HorizonRuntime, KEYSTONE: Keystone.KeystoneRuntime, DB: Db.DBRuntime, RABBIT: Rabbit.RabbitRuntime, }, } #actions which need dependent actions to occur DEP_ACTIONS_NEEDED = set([START, STOP, INSTALL]) def get_package_manager_class(distro): klass = None if(distro == UBUNTU11): #late import required #TODO better way to do this? from packaging import Apt klass = Apt.AptPackager elif(distro == RHEL6): #late import required #TODO better way to do this? from packaging import Yum klass = Yum.YumPackager return klass def get_config(action): LOG.info("Loading config from %s" % (STACK_CFG_LOC)) cfg = EnvConfigParser() cfg.read(STACK_CFG_LOC) return cfg def print_cfgs(cfg, action): cfg_str = str(cfg).strip() if(len(cfg)): LOG.info("After %s your config is:" % (action)) LOG.info(cfg_str) def runner(action_name, component_set, distro, root_dir, program_args): #have to make the root dir.... if(action_name == INSTALL): mkdir(root_dir) pkg_manager_cls = get_package_manager_class(distro) pkg_manager = pkg_manager_cls() config = get_config(action_name) LOG.info("Will %s [%s] using root directory %s" % (action_name, ", ".join(component_set), root_dir)) results = list() class_lookup = ACTION_CLASSES.get(action_name) force = program_args.get('force', False) for c in component_set: klass = class_lookup.get(c) instance = klass(components=component_set, distro=distro, pkg=pkg_manager, cfg=config, root=root_dir) if(action_name == INSTALL): LOG.info("Downloading %s." % (c)) instance.download() LOG.info("Configuring %s." % (c)) instance.configure() LOG.info("Installing %s." % (c)) trace = instance.install() if(trace): LOG.info("Finished install of %s - check %s for traces of what happened." % (c, trace)) results.append(trace) else: LOG.info("Finished install of %s" % (c)) elif(action_name == STOP): try: LOG.info("Stopping %s." % (c)) instance.stop() LOG.info("Finished stop of %s" % (c)) except NoTraceException, e: if(force): LOG.info("Passing on stopping %s since no trace file was found." % (c)) else: raise elif(action_name == START): LOG.info("Starting %s." % (c)) trace_locs = instance.start() or list() LOG.info("Finished start of %s - check [%s] for traces of what happened." % (c, ", ".join(trace_locs))) if(trace_locs): results = results + trace_locs elif(action_name == UNINSTALL): try: LOG.info("Unconfiguring %s." % (c)) instance.unconfigure() LOG.info("Uninstalling %s." % (c)) instance.uninstall() except NoTraceException, e: if(force): LOG.info("Passing on uninstalling %s since no trace file was found." % (c)) else: raise #display any configs touched... print_cfgs(config, action_name) #attempt to remove the root dir (might fail if not empty) if(action_name == UNINSTALL): try: os.rmdir(root_dir) except OSError, e: pass return results def resolve_dependencies(action, components): if(action in DEP_ACTIONS_NEEDED): new_components = list() for c in components: component_deps = list(set(fetch_deps(c))) if(len(component_deps)): LOG.info("Having to %s [%s] since they are dependencies for %s." % (action, ", ".join(component_deps), c)) new_components = new_components + component_deps new_components.append(c) return set(new_components) else: return set(components) def check_root(action, rootdir): if(action == INSTALL): root_there = False if(os.path.isdir(rootdir)): sublisting = os.listdir(rootdir) if(len(sublisting) != 0): #something exists, not good root_there = True if(root_there): LOG.error("Root directory [%s] already exists (and it's not empty)! Please remove it or uninstall components!" % (rootdir)) return False else: return True else: return True def prioritize_components(action, components): #get the right component order (by priority) mporder = dict() for c in components: priority = NAMES_PRIORITY.get(c) if(priority == None): priority = sys.maxint mporder[c] = priority #sort by priority value priority_order = sorted(mporder.iteritems(), key=operator.itemgetter(1)) #extract the right order component_order = [x[0] for x in priority_order] return component_order def main(): me = __file__ args = Options.parse() components = args.pop("component") or [] if(len(components) == 0): components = list(COMPONENT_NAMES) components = set([x.lower() for x in components]) components = set(COMPONENT_NAMES).intersection(components) if(len(components) == 0): LOG.error("No valid components specified!") LOG.info("Perhaps you should try %s --help" % (me)) return 1 action = args.pop("action") or "" #normalize the action action = action.strip().lower() if(not (action in ACTIONS)): LOG.error("No valid action specified!") LOG.info("Perhaps you should try %s --help" % (me)) return 1 rootdir = args.pop("dir") or "" if(len(rootdir) == 0 or not check_root(action, rootdir)): LOG.error("No valid root directory specified!") LOG.info("Perhaps you should try %s --help" % (me)) return 1 #ensure os/distro is known (install_os, plt) = determine_os() if(install_os == None): LOG.error("Unsupported operating system/distro: %s" % (plt)) return 1 #start it welcome(action) #need to figure out dependencies for components (if any) components = resolve_dependencies(action, components) #get the right component order (by priority) components = prioritize_components(action, components) #now do it! LOG.info("Starting action [%s] on %s for operating system/distro [%s]" % (action, rcf8222date(), install_os)) resultList = runner(action, components, install_os, rootdir, args) LOG.info("Finished action [%s] on %s" % (action, rcf8222date())) if(resultList and len(resultList)): msg = "Check [%s] for traces of what happened." % (", ".join(resultList)) LOG.info(msg) return 0 if __name__ == "__main__": rc = main() sys.exit(rc)