More updates and cleanups around making common install/uninstall/runtime code useful for all.

This commit is contained in:
Joshua Harlow 2012-01-13 18:39:05 -08:00
parent a0a272d71c
commit ffd99219ec
6 changed files with 373 additions and 413 deletions

View File

@ -1,4 +1,5 @@
# http://docs.python.org/dev/library/logging.config.html # http://docs.python.org/dev/library/logging.config.html
[default] [default]
[loggers] [loggers]
@ -24,3 +25,4 @@ keys=form01
format=%(levelname)s: @%(name)s : %(message)s format=%(levelname)s: @%(name)s : %(message)s
class=Logger.TermFormatter class=Logger.TermFormatter

View File

@ -13,13 +13,24 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from Util import (component_pths) from Util import (component_pths,
get_pkg_list,
param_replace,
STACK_CONFIG_DIR)
import Downloader
import Logger
from Shell import (execute, mkdirslist, write_file,
load_file, joinpths, touch_file,
unlink, deldir)
from Trace import (TraceWriter, TraceReader,
touch_trace, parse_fn,
IN_TRACE, PY_TRACE, START_TRACE)
import Runner
from runners.Foreground import (ForegroundRunner)
""" LOG = Logger.getLogger("install.component")
An abstraction that different components PY_INSTALL = ['python', 'setup.py', 'develop']
can inherit from to perform or basic install PY_UNINSTALL = ['python', 'setup.py', 'develop', '--uninstall']
and configure and uninstall actions.
"""
class ComponentBase(): class ComponentBase():
@ -34,6 +45,8 @@ class ComponentBase():
self.tracedir = pths.get("trace_dir") self.tracedir = pths.get("trace_dir")
self.appdir = pths.get("app_dir") self.appdir = pths.get("app_dir")
self.cfgdir = pths.get('config_dir') self.cfgdir = pths.get('config_dir')
self.component_name = component_name
# #
#the following are just interfaces... #the following are just interfaces...
@ -71,3 +84,264 @@ class RuntimeComponent():
def restart(self): def restart(self):
raise NotImplementedError() raise NotImplementedError()
# useful impls
class PkgInstallComponent(ComponentBase, InstallComponent):
def __init__(self, component_name, *args, **kargs):
ComponentBase.__init__(self, component_name, *args, **kargs)
self.tracewriter = TraceWriter(self.tracedir, IN_TRACE)
def _get_download_location(self):
raise NotImplementedError()
def download(self):
#find out where to get it
(uri, branch) = self._get_download_location()
if(uri):
#now get it
dirsmade = Downloader.download(self.appdir, uri, branch)
#this trace isn't used yet but could be
self.tracewriter.downloaded(self.appdir, uri)
#this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade)
return self.tracedir
def _get_param_map(self, fn=None):
return None
def _do_pkg_install(self):
pkgs = get_pkg_list(self.distro, self.component_name)
if(len(pkgs)):
pkgnames = sorted(pkgs.keys())
LOG.debug("Installing packages %s" % (", ".join(pkgnames)))
mp = self._get_param_map()
#run pre, install, then post
self.packager.pre_install(pkgs, mp)
self.packager.install_batch(pkgs)
self.packager.post_install(pkgs, mp)
#add trace used to remove the pkgs
for name in pkgnames:
self.tracewriter.package_install(name, pkgs.get(name))
def install(self):
self._do_pkg_install()
return self.tracedir
def _get_config_files(self):
return list()
def _config_adjust(fn, contents):
return contents
def configure(self):
dirsmade = mkdirslist(self.cfgdir)
self.tracewriter.dir_made(*dirsmade)
configs = self._get_config_files()
if(configs and len(configs)):
for fn in configs:
parameters = self._get_param_map(fn)
sourcefn = joinpths(STACK_CONFIG_DIR, self.component_name, fn)
tgtfn = joinpths(self.cfgdir, fn)
LOG.info("Configuring template file %s" % (sourcefn))
contents = load_file(sourcefn)
LOG.info("Replacing parameters in file %s" % (sourcefn))
LOG.debug("Replacements = %s" % (parameters))
contents = param_replace(contents, parameters)
LOG.debug("Applying side-effects of param replacement for template %s" % (sourcefn))
contents = self._config_adjust(contents, fn)
LOG.info("Writing configuration file %s" % (tgtfn))
write_file(tgtfn, contents)
#this trace is used to remove the files configured
self.tracewriter.cfg_write(tgtfn)
return self.tracedir
class PythonInstallComponent(PkgInstallComponent):
def __init__(self, component_name, *args, **kargs):
PkgInstallComponent.__init__(self, component_name, *args, **kargs)
def _python_install(self):
pips = get_pip_list(self.distro, self.component_name)
#install any need pip items
if(len(pips)):
Pip.install(pips)
for name in pips.keys():
self.tracewriter.pip_install(name, pips.get(name))
#do the actual python install
dirsmade = mkdirslist(self.tracedir)
self.tracewriter.dir_made(*dirsmade)
recordwhere = touch_trace(self.tracedir, PY_TRACE)
self.tracewriter.py_install(recordwhere)
(sysout, stderr) = execute(*PY_INSTALL, cwd=self.appdir, run_as_root=True)
write_file(recordwhere, sysout)
def install(self):
self._do_pkg_install()
self._python_install()
return self.tracedir
class PkgUninstallComponent(ComponentBase, UninstallComponent):
def __init__(self, component_name, *args, **kargs):
ComponentBase.__init__(self, component_name, *args, **kargs)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
def unconfigure(self):
self._unconfigure_files()
def _unconfigure_files(self):
cfgfiles = self.tracereader.files_configured()
if(len(cfgfiles)):
LOG.info("Removing %s configuration files" % (len(cfgfiles)))
for fn in cfgfiles:
if(len(fn)):
unlink(fn)
LOG.info("Removed %s" % (fn))
def uninstall(self):
self._uninstall_pkgs()
self._uninstall_touched_files()
self._uninstall_dirs()
def _uninstall_pkgs(self):
pkgsfull = self.tracereader.packages_installed()
if(len(pkgsfull)):
LOG.info("Potentially removing %s packages" % (len(pkgsfull)))
self.packager.remove_batch(pkgsfull)
def _uninstall_touched_files(self):
filestouched = self.tracereader.files_touched()
if(len(filestouched)):
LOG.info("Removing %s touched files" % (len(filestouched)))
for fn in filestouched:
if(len(fn)):
unlink(fn)
LOG.info("Removed %s" % (fn))
def _uninstall_dirs(self):
dirsmade = self.tracereader.dirs_made()
if(len(dirsmade)):
LOG.info("Removing %s created directories" % (len(dirsmade)))
for dirname in dirsmade:
deldir(dirname)
LOG.info("Removed %s" % (dirname))
class PythonUninstallComponent(PkgUninstallComponent):
def __init__(self, component_name, *args, **kargs):
PkgUninstallComponent.__init__(self, component_name, *args, **kargs)
def uninstall(self):
self._uninstall_pkgs()
self._uninstall_touched_files()
self._uninstall_python()
self._uninstall_dirs()
def _uninstall_python(self):
pylisting = self.tracereader.py_listing()
if(pylisting and len(pylisting)):
execute(*PY_UNINSTALL, cwd=self.appdir, run_as_root=True)
class ProgramRuntime(ComponentBase, RuntimeComponent):
def __init__(self, component_name, *args, **kargs):
ComponentBase.__init__(self, component_name, *args, **kargs)
self.foreground = kargs.get("foreground", True)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
self.tracewriter = TraceWriter(self.tracedir, START_TRACE)
self.starttracereader = TraceReader(self.tracedir, START_TRACE)
def _getstartercls(self):
if(self.foreground):
return ForegroundRunner
else:
raise NotImplementedError("Can not yet start in non-foreground mode")
def _getstoppercls(self, starttype):
if(starttype == Foreground.RUN_TYPE):
return ForegroundRunner
else:
raise NotImplementedError("Can not yet stop type [%s]" % (starttype))
def _was_installed(self):
pkgsinstalled = self.tracereader.packages_installed()
if(len(pkgsinstalled) == 0):
return False
def _get_apps_to_start(self):
raise NotImplementedError()
def _get_app_options(self, app, params):
return list()
def _get_param_map(self, app=None):
replacements = dict()
replacements['ROOT'] = self.appdir
return replacements
def start(self):
#ensure it was installed
if(not self._was_installed()):
msg = "Can not start %s since it was not installed" % (self.component_name)
raise StartException(msg)
#select how we are going to start it
startercls = self._getstartercls()
starter = startercls()
#start all apps
#this fns list will have info about what was started
fns = list()
apps = self._get_apps_to_start()
for app in apps:
#adjust the program options now that we have real locations
params = self._get_param_map(app)
program_opts = self._get_app_options(app, params)
LOG.info("Starting %s with options [%s]" % (app, ", ".join(program_opts)))
#start it with the given settings
fn = starter.start(app, app, *program_opts, app_dir=self.appdir, trace_dir=self.tracedir)
if(fn and len(fn)):
fns.append(fn)
LOG.info("Started %s, details are in %s" % (app, fn))
#this trace is used to locate details about what to stop
self.tracewriter.started_info(app, fn)
else:
LOG.info("Started %s" % (app))
return fns
def stop(self):
#ensure it was installed
if(not self._was_installed()):
msg = "Can not stop %s since it was not installed" % (self.component_name)
raise StopException(msg)
#we can only stop what has a started trace
start_traces = self.starttracereader.apps_started()
killedam = 0
for mp in start_traces:
#extract the apps name and where its trace is
fn = mp.get('trace_fn')
name = mp.get('name')
#missing some key info, skip it
if(fn == None or name == None):
continue
#figure out which class will stop it
contents = parse_fn(fn)
killcls = None
for (cmd, action) in contents:
if(cmd == Runner.RUN_TYPE):
killcls = self._getstoppercls(action)
break
#did we find a class that can do it?
if(killcls):
#we can try to stop it
LOG.info("Stopping %s with %s in %s" % (name, runtype, self.tracedir))
#create an instance of the killer class and attempt to stop
killer = killcls()
killer.stop(name, trace_dir=self.tracedir)
killedam += 1
#if we got rid of them all get rid of the trace
if(killedam == len(start_traces)):
fn = self.starttracereader.trace_fn
LOG.info("Deleting trace file %s" % (fn))
unlink(fn)

View File

@ -17,17 +17,16 @@ import re
import Logger import Logger
import Packager import Packager
from Component import (ComponentBase, RuntimeComponent, from Component import (PkgUninstallComponent, PkgInstallComponent,
UninstallComponent, InstallComponent) ComponentBase, RuntimeComponent)
from Util import (DB, from Util import (DB,
get_pkg_list, get_host_ip, get_host_ip,
execute_template) execute_template)
from Exceptions import (StartException, StopException, from Exceptions import (StartException, StopException,
StatusException, RestartException) StatusException, RestartException)
from Trace import (TraceWriter, TraceReader, from Shell import (execute)
from Trace import (TraceReader,
IN_TRACE) IN_TRACE)
from Shell import (mkdirslist, execute, deldir,
load_file, write_file)
LOG = Logger.getLogger("install.db") LOG = Logger.getLogger("install.db")
TYPE = DB TYPE = DB
@ -56,45 +55,20 @@ DB_ACTIONS = {
BASE_ERROR = 'Currently we do not know how to %s for database type [%s]' BASE_ERROR = 'Currently we do not know how to %s for database type [%s]'
class DBUninstaller(ComponentBase, UninstallComponent): class DBUninstaller(PkgUninstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
ComponentBase.__init__(self, TYPE, *args, **kargs) PkgUninstallComponent.__init__(self, TYPE, *args, **kargs)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
class DBInstaller(PkgInstallComponent):
def __init__(self, *args, **kargs):
PkgInstallComponent.__init__(self, TYPE, *args, **kargs)
self.runtime = DBRuntime(*args, **kargs) self.runtime = DBRuntime(*args, **kargs)
def unconfigure(self): def _get_download_location(self):
#nothing to unconfigure, we are just a pkg return (None, None)
pass
def uninstall(self): def _get_param_map(self, fn=None):
#clean out removeable packages
pkgsfull = self.tracereader.packages_installed()
if(len(pkgsfull)):
LOG.info("Potentially removing %s packages" % (len(pkgsfull)))
self.packager.remove_batch(pkgsfull)
dirsmade = self.tracereader.dirs_made()
if(len(dirsmade)):
LOG.info("Removing %s created directories" % (len(dirsmade)))
for dirname in dirsmade:
deldir(dirname)
LOG.info("Removed %s" % (dirname))
class DBInstaller(ComponentBase, InstallComponent):
def __init__(self, *args, **kargs):
ComponentBase.__init__(self, TYPE, *args, **kargs)
self.tracewriter = TraceWriter(self.tracedir, IN_TRACE)
self.runtime = DBRuntime(*args, **kargs)
def download(self):
#nothing to download, we are just a pkg
pass
def configure(self):
#nothing to configure, we are just a pkg
pass
def _get_install_params(self):
#this dictionary will be used for parameter replacement #this dictionary will be used for parameter replacement
#in pre-install and post-install sections #in pre-install and post-install sections
out = dict() out = dict()
@ -106,20 +80,15 @@ class DBInstaller(ComponentBase, InstallComponent):
out['HOST_IP'] = hostip out['HOST_IP'] = hostip
return out return out
def _do_install(self, pkgs): def install(self):
mp = self._get_install_params() PkgInstallComponent.install(self)
self.packager.pre_install(pkgs, mp)
self.packager.install_batch(pkgs)
self.packager.post_install(pkgs, mp)
#
#extra actions to ensure we are granted access #extra actions to ensure we are granted access
#
dbtype = self.cfg.get("db", "type") dbtype = self.cfg.get("db", "type")
dbactions = DB_ACTIONS.get(dbtype) dbactions = DB_ACTIONS.get(dbtype)
if(dbactions and dbactions.get('grant_all')): if(dbactions and dbactions.get('grant_all')):
#update the DB to give user 'USER'@'%' full control of the all databases: #update the DB to give user 'USER'@'%' full control of the all databases:
grant_cmd = dbactions.get('grant_all') grant_cmd = dbactions.get('grant_all')
params = mp params = self._get_param_map()
cmds = list() cmds = list()
cmds.append({ cmds.append({
'cmd': grant_cmd, 'cmd': grant_cmd,
@ -128,25 +97,13 @@ class DBInstaller(ComponentBase, InstallComponent):
#shell seems to be needed here #shell seems to be needed here
#since python escapes this to much... #since python escapes this to much...
execute_template(*cmds, params=params, shell=True) execute_template(*cmds, params=params, shell=True)
#
#special mysql actions #special mysql actions
if(dbactions and dbtype == MYSQL): if(dbactions and dbtype == MYSQL):
cmd = dbactions.get('host_adjust') cmd = dbactions.get('host_adjust')
if(cmd): if(cmd):
execute(*cmd, run_as_root=True, shell=True) execute(*cmd, run_as_root=True, shell=True)
def install(self):
#just install the pkgs
pkgs = get_pkg_list(self.distro, TYPE)
pkgnames = sorted(pkgs.keys())
LOG.info("Installing packages %s" % (", ".join(pkgnames)))
self._do_install(pkgs)
#add trace used to remove the pkgs
for name in pkgnames:
self.tracewriter.package_install(name, pkgs.get(name))
#restart it to make sure all good #restart it to make sure all good
self.runtime.restart() self.runtime.restart()
return self.tracedir
class DBRuntime(ComponentBase, RuntimeComponent): class DBRuntime(ComponentBase, RuntimeComponent):

View File

@ -17,24 +17,19 @@ import json
import os.path import os.path
import Logger import Logger
from Component import (ComponentBase, RuntimeComponent, from Component import (PythonUninstallComponent,
UninstallComponent, InstallComponent) PythonInstallComponent,
ProgramRuntime)
import Shell import Shell
import Util import Util
from Trace import (TraceWriter, TraceReader,
IN_TRACE, START_TRACE, PY_TRACE,
parse_fn, touch_trace)
import Downloader
import Packager
import Runner import Runner
from runners.Foreground import (ForegroundRunner) from runners.Foreground import (ForegroundRunner)
from Util import (GLANCE, from Util import (GLANCE,
STACK_CONFIG_DIR, get_host_ip,
get_pkg_list, get_host_ip,
param_replace, get_dbdsn, param_replace, get_dbdsn,
) )
from Shell import (execute, deldir, mkdirslist, unlink, from Shell import (deldir, mkdirslist, unlink,
joinpths, load_file, write_file, touch_file) joinpths, touch_file)
from Exceptions import (StopException, StartException, InstallException) from Exceptions import (StopException, StartException, InstallException)
LOG = Logger.getLogger("install.glance") LOG = Logger.getLogger("install.glance")
@ -46,225 +41,60 @@ REG_CONF = "glance-registry.conf"
CONFIGS = [API_CONF, REG_CONF] CONFIGS = [API_CONF, REG_CONF]
DB_NAME = "glance" DB_NAME = "glance"
#why doesn't --record do anything??
PY_INSTALL = ['python', 'setup.py', 'develop']
PY_UNINSTALL = ['python', 'setup.py', 'develop', '--uninstall']
#what to start #what to start
APPS_TO_START = ['glance-api', 'glance-registry'] APPS_TO_START = ['glance-api', 'glance-registry']
APP_OPTIONS = { APP_OPTIONS = {
'glance-api': ['--config-file', joinpths('%ROOT%', "etc", API_CONF)], 'glance-api': ['--config-file', joinpths('%ROOT%', "etc", API_CONF)],
'glance-registry': ['--config-file', joinpths('%ROOT%', "etc", REG_CONF)] 'glance-registry': ['--config-file', joinpths('%ROOT%', "etc", REG_CONF)]
} }
CONFIG_ACTUAL_DIR = 'etc'
class GlanceBase(ComponentBase): class GlanceUninstaller(PythonUninstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
ComponentBase.__init__(self, TYPE, *args, **kargs) PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
#note, not config that parent sets self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
self.cfgdir = joinpths(self.appdir, "etc")
class GlanceRuntime(ProgramRuntime):
class GlanceUninstaller(GlanceBase, UninstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
GlanceBase.__init__(self, *args, **kargs) ProgramRuntime.__init__(self, TYPE, *args, **kargs)
self.tracereader = TraceReader(self.tracedir, IN_TRACE) self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
def unconfigure(self): def _was_installed(self):
#get rid of all files configured pres = ProgramRuntime._was_installed(self)
cfgfiles = self.tracereader.files_configured() if(pres == False):
if(len(cfgfiles)): return False
LOG.info("Removing %s configuration files" % (len(cfgfiles)))
for fn in cfgfiles:
if(len(fn)):
unlink(fn)
LOG.info("Removed %s" % (fn))
def uninstall(self):
#clean out removeable packages
pkgsfull = self.tracereader.packages_installed()
if(len(pkgsfull)):
LOG.info("Potentially removing %s packages" % (len(pkgsfull)))
self.packager.remove_batch(pkgsfull)
#clean out files touched
filestouched = self.tracereader.files_touched()
if(len(filestouched)):
LOG.info("Removing %s touched files" % (len(filestouched)))
for fn in filestouched:
if(len(fn)):
unlink(fn)
LOG.info("Removed %s" % (fn))
#undevelop python???
#how should this be done??
pylisting = self.tracereader.py_listing() pylisting = self.tracereader.py_listing()
if(pylisting != None): if(pylisting and len(pylisting)):
execute(*PY_UNINSTALL, cwd=self.appdir, run_as_root=True) return True
#clean out dirs created return False
dirsmade = self.tracereader.dirs_made()
if(len(dirsmade)):
LOG.info("Removing %s created directories" % (len(dirsmade)))
for dirname in dirsmade:
deldir(dirname)
LOG.info("Removed %s" % (dirname))
def _get_apps_to_start(self):
raise list(APPS_TO_START)
class GlanceRuntime(GlanceBase, RuntimeComponent): def _get_app_options(self, app, params):
def __init__(self, *args, **kargs): opts = list()
GlanceBase.__init__(self, *args, **kargs) if(app in APP_OPTIONS):
self.foreground = kargs.get("foreground", True)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
self.tracewriter = TraceWriter(self.tracedir, START_TRACE)
self.starttracereader = TraceReader(self.tracedir, START_TRACE)
def _getstartercls(self):
if(self.foreground):
return ForegroundRunner
else:
raise NotImplementedError("Can not yet start in non-foreground mode")
def _getstoppercls(self, starttype):
if(starttype == Foreground.RUN_TYPE):
return ForegroundRunner
else:
raise NotImplementedError("Can not yet stop type [%s]" % (starttype))
def start(self):
#ensure it was installed
pylisting = self.tracereader.py_listing()
if(len(pylisting) == 0):
msg = "Can not start %s since it was not installed" % (TYPE)
raise StartException(msg)
#select how we are going to start it
startercls = self._getstoppercls()
starter = startercls()
#start all apps
#this fns list will have info about what was started
fns = list()
#this dictionary will be used to adjust our start templates with actual values
replacements = dict()
replacements['ROOT'] = self.appdir
for app in APPS_TO_START:
#adjust the program options now that we have real locations
program_opts = []
for opt in APP_OPTIONS.get(app): for opt in APP_OPTIONS.get(app):
program_opts.append(param_replace(opt, replacements)) opts.append(param_replace(opt, params))
LOG.info("Starting %s with options [%s]" % (app, ", ".join(program_opts))) return opts
#start it with the given settings
fn = starter.start(app, app, *program_opts, app_dir=self.appdir, trace_dir=self.tracedir)
if(fn):
fns.append(fn)
LOG.info("Started %s, details are in %s" % (app, fn))
#this trace is used to locate details about what to stop
self.tracewriter.started_info(app, fn)
else:
LOG.info("Started %s" % (app))
return fns
def stop(self): class GlanceInstaller(PythonInstallComponent):
#ensure it was installed
pylisting = self.tracereader.py_listing()
if(pylisting == None or len(pylisting) == 0):
msg = "Can not start %s since it was not installed" % (TYPE)
raise StopException(msg)
#we can only stop what has a started trace
start_traces = self.starttracereader.apps_started()
killedam = 0
for mp in start_traces:
#extract the apps name and where its trace is
fn = mp.get('trace_fn')
name = mp.get('name')
#missing some key info, skip it
if(fn == None or name == None):
continue
#figure out which class will stop it
contents = parse_fn(fn)
killcls = None
for (cmd, action) in contents:
if(cmd == Runner.RUN_TYPE):
killcls = self._getstoppercls(action)
break
#did we find a class that can do it?
if(killcls):
#we can try to stop it
LOG.info("Stopping %s with %s in %s" % (name, runtype, self.tracedir))
#create an instance of the killer class and attempt to stop
killer = killcls()
killer.stop(name, trace_dir=self.tracedir)
killedam += 1
#if we got rid of them all get rid of the trace
if(killedam == len(start_traces)):
fn = self.starttracereader.trace_fn
LOG.info("Deleting trace file %s" % (fn))
unlink(fn)
class GlanceInstaller(GlanceBase, InstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
GlanceBase.__init__(self, *args, **kargs) PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.gitloc = self.cfg.get("git", "glance_repo") self.gitloc = self.cfg.get("git", "glance_repo")
self.brch = self.cfg.get("git", "glance_branch") self.brch = self.cfg.get("git", "glance_branch")
self.tracewriter = TraceWriter(self.tracedir, IN_TRACE) self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
def download(self): def _get_download_location(self):
dirsmade = Downloader.download(self.appdir, self.gitloc, self.brch) uri = self.gitloc
#this trace isn't used yet but could be branch = self.brch
self.tracewriter.downloaded(self.appdir, self.gitloc) return (uri, branch)
#this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade)
return self.tracedir
def _do_install(self, pkgs): def _get_config_files(self):
mp = self._get_param_map() return list(CONFIGS)
self.packager.pre_install(pkgs, mp)
self.packager.install_batch(pkgs)
self.packager.post_install(pkgs, mp)
def install(self): def _config_adjust(self, contents, fn):
#get all the packages for glance for the specified distro
pkgs = get_pkg_list(self.distro, TYPE)
pkgnames = sorted(pkgs.keys())
LOG.debug("Installing packages %s" % (", ".join(pkgnames)))
self._do_install(pkgs)
#add trace used to remove the pkgs
for name in pkgnames:
self.tracewriter.package_install(name, pkgs.get(name))
#make a directory for the python trace file (if its not already there)
dirsmade = mkdirslist(self.tracedir)
#this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade)
recordwhere = touch_trace(self.tracedir, PY_TRACE)
#this trace is used to remove the trace created
self.tracewriter.py_install(recordwhere)
(sysout, stderr) = execute(*PY_INSTALL, cwd=self.appdir, run_as_root=True)
write_file(recordwhere, sysout)
return self.tracedir
def configure(self):
dirsmade = mkdirslist(self.cfgdir)
#this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade)
parameters = self._get_param_map()
for fn in CONFIGS:
#go through each config in devstack (which is really a template)
#and adjust that template to have real values and then go through
#the resultant config file and perform and adjustments (directory creation...)
#and then write that to the glance configuration directory.
sourcefn = joinpths(STACK_CONFIG_DIR, TYPE, fn)
tgtfn = joinpths(self.cfgdir, fn)
LOG.info("Configuring template file %s" % (sourcefn))
contents = load_file(sourcefn)
LOG.info("Replacing parameters in file %s" % (sourcefn))
LOG.debug("Replacements = %s" % (parameters))
contents = param_replace(contents, parameters)
LOG.debug("Applying side-effects of param replacement for template %s" % (sourcefn))
self._config_apply(contents, fn)
LOG.info("Writing configuration file %s" % (tgtfn))
write_file(tgtfn, contents)
#this trace is used to remove the files configured
self.tracewriter.cfg_write(tgtfn)
return self.tracedir
def _config_apply(self, contents, fn):
lines = contents.splitlines() lines = contents.splitlines()
for line in lines: for line in lines:
cleaned = line.strip() cleaned = line.strip()
@ -308,8 +138,9 @@ class GlanceInstaller(GlanceBase, InstallComponent):
dirsmade = mkdirslist(val) dirsmade = mkdirslist(val)
#this trace is used to remove the dirs created #this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade) self.tracewriter.dir_made(*dirsmade)
return contents
def _get_param_map(self): def _get_param_map(self, fn=None):
#this dict will be used to fill in the configuration #this dict will be used to fill in the configuration
#params with actual values #params with actual values
mp = dict() mp = dict()

View File

@ -18,175 +18,68 @@ import os.path
import Pip import Pip
from Util import (KEYSTONE, from Util import (KEYSTONE,
CONFIG_DIR, STACK_CONFIG_DIR, CONFIG_DIR,
NOVA, GLANCE, SWIFT, NOVA, GLANCE, SWIFT,
get_pkg_list, get_pip_list,
get_dbdsn, get_dbdsn,
param_replace, get_host_ip, get_host_ip,
execute_template) execute_template)
import Logger import Logger
import Downloader
import Db import Db
from Trace import (TraceWriter, TraceReader, from Component import (PythonUninstallComponent, PythonInstallComponent, ProgramRuntime)
touch_trace, from Shell import (mkdirslist, unlink, touch_file, joinpths)
IN_TRACE, PY_TRACE)
from Shell import (execute, mkdirslist, write_file,
load_file, joinpths, touch_file,
unlink, deldir)
from Component import (ComponentBase, RuntimeComponent,
UninstallComponent, InstallComponent)
LOG = Logger.getLogger("install.keystone") LOG = Logger.getLogger("install.keystone")
TYPE = KEYSTONE TYPE = KEYSTONE
PY_INSTALL = ['python', 'setup.py', 'develop']
PY_UNINSTALL = ['python', 'setup.py', 'develop', '--uninstall']
ROOT_CONF = "keystone.conf" ROOT_CONF = "keystone.conf"
CONFIGS = [ROOT_CONF] CONFIGS = [ROOT_CONF]
BIN_DIR = "bin" BIN_DIR = "bin"
DB_NAME = "keystone" DB_NAME = "keystone"
class KeystoneUninstaller(PythonUninstallComponent):
class KeystoneBase(ComponentBase):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
ComponentBase.__init__(self, TYPE, *args, **kargs) PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
self.cfgdir = joinpths(self.appdir, CONFIG_DIR) self.cfgdir = joinpths(self.appdir, CONFIG_DIR)
self.bindir = joinpths(self.appdir, BIN_DIR) self.bindir = joinpths(self.appdir, BIN_DIR)
class KeystoneInstaller(PythonInstallComponent):
class KeystoneUninstaller(KeystoneBase, UninstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
KeystoneBase.__init__(self, *args, **kargs) PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
def unconfigure(self):
#get rid of all files configured
cfgfiles = self.tracereader.files_configured()
if(len(cfgfiles)):
LOG.info("Removing %s configuration files" % (len(cfgfiles)))
for fn in cfgfiles:
if(len(fn)):
unlink(fn)
LOG.info("Removed %s" % (fn))
def uninstall(self):
#clean out removeable packages
pkgsfull = self.tracereader.packages_installed()
if(len(pkgsfull)):
LOG.info("Potentially removing %s packages" % (len(pkgsfull)))
self.packager.remove_batch(pkgsfull)
#clean out pips
pipsfull = self.tracereader.pips_installed()
if(len(pipsfull)):
LOG.info("Potentially removing %s pips" % (len(pipsfull)))
Pip.uninstall(pipsfull)
#clean out files touched
filestouched = self.tracereader.files_touched()
if(len(filestouched)):
LOG.info("Removing %s touched files" % (len(filestouched)))
for fn in filestouched:
if(len(fn)):
unlink(fn)
LOG.info("Removed %s" % (fn))
#undevelop python???
#how should this be done??
pylisting = self.tracereader.py_listing()
if(pylisting != None):
execute(*PY_UNINSTALL, cwd=self.appdir, run_as_root=True)
#clean out dirs created
dirsmade = self.tracereader.dirs_made()
if(len(dirsmade)):
LOG.info("Removing %s created directories" % (len(dirsmade)))
for dirname in dirsmade:
deldir(dirname)
LOG.info("Removed %s" % (dirname))
class KeystoneInstaller(KeystoneBase, InstallComponent):
def __init__(self, *args, **kargs):
KeystoneBase.__init__(self, *args, **kargs)
self.gitloc = self.cfg.get("git", "keystone_repo") self.gitloc = self.cfg.get("git", "keystone_repo")
self.brch = self.cfg.get("git", "keystone_branch") self.brch = self.cfg.get("git", "keystone_branch")
self.tracewriter = TraceWriter(self.tracedir, IN_TRACE) self.cfgdir = joinpths(self.appdir, CONFIG_DIR)
self.bindir = joinpths(self.appdir, BIN_DIR)
def download(self): def _get_download_location(self):
dirsmade = Downloader.download(self.appdir, self.gitloc, self.brch) uri = self.gitloc
#this trace isn't used yet but could be branch = self.brch
self.tracewriter.downloaded(self.appdir, self.gitloc) return (uri, branch)
#this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade)
return self.tracedir
def _do_install(self, pkgs):
LOG.debug("Installing packages %s" % (", ".join(pkgs.keys())))
self.packager.pre_install(pkgs)
self.packager.install_batch(pkgs)
self.packager.post_install(pkgs)
def install(self): def install(self):
#install needed pkgs PythonInstallComponent.install(self)
pkgs = get_pkg_list(self.distro, TYPE)
if(len(pkgs)):
#do the install
self._do_install(pkgs)
#this trace is used to remove the pkgs installed
for name in pkgs.keys():
self.tracewriter.package_install(name, pkgs.get(name))
#install the needed pips
pips = get_pip_list(self.distro, TYPE)
if(len(pips)):
Pip.install(pips)
#this trace is used to remove the pips installed
for name in pips.keys():
self.tracewriter.pip_install(name, pips.get(name))
#this trace is used to remove the dirs created
dirsmade = mkdirslist(self.tracedir)
self.tracewriter.dir_made(*dirsmade)
recordwhere = touch_trace(self.tracedir, PY_TRACE)
#this trace is used to remove the trace created
self.tracewriter.py_install(recordwhere)
(sysout, stderr) = execute(*PY_INSTALL, cwd=self.appdir, run_as_root=True)
write_file(recordwhere, sysout)
#adjust db #adjust db
self._setup_db() self._setup_db()
#setup any data #setup any data
self._setup_data() self._setup_data()
return self.tracedir return self.tracedir
def configure(self): def _get_config_files(self):
dirsmade = mkdirslist(self.cfgdir) return list(CONFIGS)
self.tracewriter.dir_made(*dirsmade)
for fn in CONFIGS:
sourcefn = joinpths(STACK_CONFIG_DIR, TYPE, fn)
tgtfn = joinpths(self.cfgdir, fn)
LOG.info("Configuring template file %s" % (sourcefn))
contents = load_file(sourcefn)
pmap = self._get_param_map()
LOG.info("Replacing parameters in file %s" % (sourcefn))
LOG.debug("Replacements = %s" % (pmap))
contents = param_replace(contents, pmap)
LOG.debug("Applying side-effects of param replacement for template %s" % (sourcefn))
self._config_apply(contents, fn)
LOG.info("Writing configuration file %s" % (tgtfn))
write_file(tgtfn, contents)
#this trace is used to remove the files configured
self.tracewriter.cfg_write(tgtfn)
return self.tracedir
def _setup_db(self): def _setup_db(self):
Db.drop_db(self.cfg, DB_NAME) Db.drop_db(self.cfg, DB_NAME)
Db.create_db(self.cfg, DB_NAME) Db.create_db(self.cfg, DB_NAME)
def _setup_data(self): def _setup_data(self):
params = self._get_param_map() params = self._get_param_map(None)
cmds = _keystone_setup_cmds(self.othercomponents) cmds = _keystone_setup_cmds(self.othercomponents)
execute_template(*cmds, params=params, ignore_missing=True) execute_template(*cmds, params=params, ignore_missing=True)
def _config_apply(self, contents, fn): def _config_adjust(self, contents, fn):
lines = contents.splitlines() lines = contents.splitlines()
for line in lines: for line in lines:
cleaned = line.strip() cleaned = line.strip()
if(len(cleaned) == 0 or cleaned[0] == '#' or cleaned[0] == '['): if(len(cleaned) == 0 or
cleaned[0] == '#' or cleaned[0] == '['):
#not useful to examine these #not useful to examine these
continue continue
pieces = cleaned.split("=", 1) pieces = cleaned.split("=", 1)
@ -208,8 +101,9 @@ class KeystoneInstaller(KeystoneBase, InstallComponent):
unlink(val) unlink(val)
touch_file(val) touch_file(val)
self.tracewriter.file_touched(val) self.tracewriter.file_touched(val)
return contents
def _get_param_map(self): def _get_param_map(self, fn=None):
#these be used to fill in the configuration/cmds + #these be used to fill in the configuration/cmds +
#params with actual values #params with actual values
mp = dict() mp = dict()
@ -223,9 +117,11 @@ class KeystoneInstaller(KeystoneBase, InstallComponent):
return mp return mp
class KeystoneRuntime(KeystoneBase, RuntimeComponent): class KeystoneRuntime(ProgramRuntime):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
KeystoneBase.__init__(self, *args, **kargs) ProgramRuntime.__init__(self, TYPE, *args, **kargs)
self.cfgdir = joinpths(self.appdir, CONFIG_DIR)
self.bindir = joinpths(self.appdir, BIN_DIR)
# Keystone setup commands are the the following # Keystone setup commands are the the following

8
stack
View File

@ -150,15 +150,15 @@ def start(components, distro, rootdir, args):
def print_cfgs(cfg, action): def print_cfgs(cfg, action):
pws = dict(cfg.pws) pws = dict(cfg.pws)
configs_fetched = dict(cfg.configs_fetched) configs_fetched = dict(cfg.configs_fetched)
LOG.info("After %s your passwords are:" % (action)) LOG.info("After %s your fetched/generated passwords are:" % (action))
for (pwkey, val) in pws.items(): for (pwkey, val) in pws.items():
LOG.info("%s = %s" % (pwkey, val)) LOG.info("\t%s = %s" % (pwkey, val))
LOG.info("After %s your other configuration is:" % (action)) LOG.info("After %s your other fetched configuration was:" % (action))
for (key, val) in configs_fetched.items(): for (key, val) in configs_fetched.items():
if(key in pws): if(key in pws):
#already shown #already shown
continue continue
LOG.info("%s = %s" % (key, val)) LOG.info("\t%s = %s" % (key, val))
def install(components, distro, rootdir, args): def install(components, distro, rootdir, args):