anvil/stack

316 lines
11 KiB
Python
Executable File

#!/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 os
import os.path
import sys
#TODO is this needed?
sys.path.append("devstack")
import Logger
import Options
#TODO fix these
from Util import (welcome, rcf8222date, determine_os,
prioritize_components, resolve_dependencies)
from Util import (NOVA, GLANCE, QUANTUM, SWIFT, KEYSTONE, HORIZON, DB, RABBIT, KEYSTONE_CLIENT,
INSTALL, UNINSTALL, START, STOP,
ACTIONS, COMPONENT_NAMES, NAMES_PRIORITY,
UBUNTU11, RHEL6,
STACK_CFG_LOC)
from Shell import (mkdir, joinpths, unlink)
from Exceptions import (NoTraceException)
import Glance
import Horizon
import Keystone
import Nova
import Quantum
import Config
import Swift
import Db
import Rabbit
import Config
import KeystoneClient
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,
KEYSTONE_CLIENT: KeystoneClient.KeyStoneClientInstaller,
},
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,
KEYSTONE_CLIENT: KeystoneClient.KeyStoneClientUninstaller,
},
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,
KEYSTONE_CLIENT: KeystoneClient.KeyStoneClientRuntime,
},
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,
KEYSTONE_CLIENT: KeystoneClient.KeyStoneClientRuntime,
},
}
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):
fn = STACK_CFG_LOC
LOG.info("Loading config from %s" % (fn))
cfg = Config.EnvConfigParser()
cfg.read(fn)
return cfg
def print_cfgs(cfg, action):
#this will make the items nice and pretty
def item_format(k, v):
return "\t%s=%s" % (str(k), str(v))
def map_print(mp):
for key in sorted(mp.keys()):
value = mp.get(key)
LOG.info(item_format(key, value))
#now make it pretty
passwords_gotten = cfg.pws
full_cfgs = cfg.configs_fetched
db_dsns = cfg.db_dsns
if(len(passwords_gotten) or len(full_cfgs) or len(db_dsns)):
LOG.info("After %s your config is:" % (action))
if(len(passwords_gotten)):
LOG.info("Passwords:")
map_print(passwords_gotten)
if(len(full_cfgs)):
#TOD
#better way to do this?? (ie a list difference?)
filtered_mp = dict()
for key in full_cfgs.keys():
if(key in passwords_gotten):
continue
filtered_mp[key] = full_cfgs.get(key)
if(len(filtered_mp)):
LOG.info("Configs:")
map_print(filtered_mp)
if(len(db_dsns)):
LOG.info("Data source names:")
map_print(db_dsns)
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(distro)
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))
am_downloaded = instance.download()
LOG.info("Performed %s downloads." % (str(am_downloaded)))
LOG.info("Configuring %s." % (c))
am_configured = instance.configure()
LOG.info("Configured %s files." % (str(am_configured)))
LOG.info("Pre-installing %s." % (c))
instance.pre_install()
LOG.info("Installing %s." % (c))
instance.install()
LOG.info("Post-installing %s." % (c))
trace = instance.post_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))
stop_am = instance.stop()
LOG.info("Stopped %s applications." % (str(stop_am)))
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))
start_info = instance.start()
if(type(start_info) == list):
LOG.info("Check [%s] for traces of what happened." % (", ".join(start_info)))
results = results + start_info
elif(type(start_info) == int):
LOG.info("Started %s applications." % (str(start_info)))
LOG.info("Finished start of %s." % (c))
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 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 check_python():
py_version = sys.version_info
major = py_version[0]
minor = py_version[1]
if(major < 2 or (major == 2 and minor < 6)):
return False
if(major >= 3):
LOG.warn("This script has not been tested in python %s, use at your own risk!" % (major))
return True
def main():
if(not check_python()):
LOG.error("Your python version is to old, please upgrade to >= 2.6!")
return 1
me = __file__
args = Options.parse()
components = args.pop("component") or []
if(len(components) == 0):
#assume user wants them all
components = list(COMPONENT_NAMES)
else:
#clean the names up and see what is valid after an intersection
components = set([x.lower().strip() 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)
new_components = resolve_dependencies(action, components)
component_diff = new_components.difference(components)
if(len(component_diff)):
LOG.info("Having to install dependent components: [%s]" % (",".join(component_diff)))
components = new_components
#get the right component order (by priority)
components = prioritize_components(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)