316 lines
11 KiB
Python
Executable File
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)
|