Large amount of renaming and cleanups to make everything much more pythonic. Yippe.

This commit is contained in:
Joshua Harlow
2012-01-20 14:12:20 -08:00
parent ca8046f5c2
commit 0b46c02ac8
39 changed files with 1025 additions and 943 deletions

View File

@@ -14,7 +14,7 @@ formatter=form01
keys=hand01
[handler_hand01]
class=Logger.TermHandler
class=devstack.log.TermHandler
formatter=form01
args=()
@@ -23,6 +23,6 @@ keys=form01
[formatter_form01]
format=%(levelname)s: @%(name)s : %(message)s
class=Logger.TermFormatter
class=devstack.log.TermFormatter

View File

@@ -12,3 +12,4 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

94
devstack/actions.py Normal file
View File

@@ -0,0 +1,94 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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 constants as c
from devstack.components import db
from devstack.components import glance
from devstack.components import horizon
from devstack.components import keystone
from devstack.components import keystone_client
from devstack.components import nova
from devstack.components import nova_client
from devstack.components import openstack_x
from devstack.components import quantum
from devstack.components import rabbit
from devstack.components import swift
# This determines what classes to use to install/uninstall/...
ACTION_CLASSES = {
c.INSTALL: {
c.NOVA: nova.NovaInstaller,
c.GLANCE: glance.GlanceInstaller,
c.QUANTUM: quantum.QuantumInstaller,
c.SWIFT: swift.SwiftInstaller,
c.HORIZON: horizon.HorizonInstaller,
c.KEYSTONE: keystone.KeystoneInstaller,
c.DB: db.DBInstaller,
c.RABBIT: rabbit.RabbitInstaller,
c.KEYSTONE_CLIENT: keystone_client.KeyStoneClientInstaller,
c.NOVA_CLIENT: nova_client.NovaClientInstaller,
c.OPENSTACK_X: openstack_x.OpenstackXInstaller,
},
c.UNINSTALL: {
c.NOVA: nova.NovaUninstaller,
c.GLANCE: glance.GlanceUninstaller,
c.QUANTUM: quantum.QuantumUninstaller,
c.SWIFT: swift.SwiftUninstaller,
c.HORIZON: horizon.HorizonUninstaller,
c.KEYSTONE: keystone.KeystoneUninstaller,
c.DB: db.DBUninstaller,
c.RABBIT: rabbit.RabbitUninstaller,
c.KEYSTONE_CLIENT: keystone_client.KeyStoneClientUninstaller,
c.NOVA_CLIENT: nova_client.NovaClientUninstaller,
c.OPENSTACK_X: openstack_x.OpenstackXUninstaller,
},
c.START: {
c.NOVA: nova.NovaRuntime,
c.GLANCE: glance.GlanceRuntime,
c.QUANTUM: quantum.QuantumRuntime,
c.SWIFT: swift.SwiftRuntime,
c.HORIZON: horizon.HorizonRuntime,
c.KEYSTONE: keystone.KeystoneRuntime,
c.DB: db.DBRuntime,
c.RABBIT: rabbit.RabbitRuntime,
c.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime,
c.NOVA_CLIENT: nova_client.NovaClientRuntime,
c.OPENSTACK_X: openstack_x.OpenstackXRuntime,
},
c.STOP: {
c.NOVA: nova.NovaRuntime,
c.GLANCE: glance.GlanceRuntime,
c.QUANTUM: quantum.QuantumRuntime,
c.SWIFT: swift.SwiftRuntime,
c.HORIZON: horizon.HorizonRuntime,
c.KEYSTONE: keystone.KeystoneRuntime,
c.DB: db.DBRuntime,
c.RABBIT: rabbit.RabbitRuntime,
c.KEYSTONE_CLIENT: keystone_client.KeyStoneClientRuntime,
c.NOVA_CLIENT: nova_client.NovaClientRuntime,
c.OPENSTACK_X: openstack_x.OpenstackXRuntime,
},
}
def get_action_cls(action_name, component_name):
action_cls_map = ACTION_CLASSES.get(action_name)
if(not action_cls_map):
return None
cls = action_cls_map.get(component_name)
return cls

View File

@@ -13,18 +13,16 @@
# License for the specific language governing permissions and limitations
# under the License.
import ConfigParser
import os
import re
import ConfigParser
#TODO fix these
from Exceptions import (BadParamException)
from Environment import (get_environment_key)
from devstack import env
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
import Logger
import Shell
LOG = Logger.getLogger("install.config")
LOG = logging.getLogger("devstack.cfg")
PW_TMPL = "Enter a password for %s: "
ENV_PAT = re.compile(r"^\s*\$\{([\w\d]+):\-(.*)\}\s*$")
CACHE_MSG = "(value will now be internally cached)"
@@ -103,10 +101,10 @@ class EnvConfigParser(ConfigParser.RawConfigParser):
defv = mtch.group(2)
if(len(defv) == 0 and len(key) == 0):
msg = "Invalid bash-like value \"%s\" for \"%s\"" % (v, key)
raise BadParamException(msg)
raise excp.BadParamException(msg)
if(len(key) == 0):
return defv
v = get_environment_key(key)
v = env.get_key(key)
if(v == None):
v = defv
return v
@@ -125,11 +123,11 @@ class EnvConfigParser(ConfigParser.RawConfigParser):
#dsn = "<driver>://<username>:<password>@<host>:<port>/<database>"
if(not host):
msg = "Unable to fetch a database dsn - no host found"
raise BadParamException(msg)
raise excp.BadParamException(msg)
driver = self.get("db", "type")
if(not driver):
msg = "Unable to fetch a database dsn - no driver type found"
raise BadParamException(msg)
raise excp.BadParamException(msg)
dsn = driver + "://"
if(user):
dsn += user
@@ -159,7 +157,7 @@ class EnvConfigParser(ConfigParser.RawConfigParser):
pw = ""
if(len(pw) == 0):
while(len(pw) == 0):
pw = Shell.password(PW_TMPL % (key))
pw = sh.password(PW_TMPL % (key))
LOG.debug("Password for \"%s\" will be \"%s\" %s" % (key, pw, CACHE_MSG))
self.pws[key] = pw
return pw

View File

@@ -14,42 +14,28 @@
# under the License.
import os
import os.path
import Downloader
import Exceptions
import Logger
import Pip
import Runner
import runners.Foreground
import runners.Screen
import Shell
import Trace
import Util
from devstack import constants as c
from devstack import downloader as down
from devstack import exceptions as excp
from devstack import log as logging
from devstack import pip
from devstack import shell as sh
from devstack import trace as tr
from devstack import utils
from devstack.runners import fork
from devstack.runners import screen
LOG = Logger.getLogger("install.component")
LOG = logging.getLogger("devstack.component")
PY_INSTALL = ['python', 'setup.py', 'develop']
PY_UNINSTALL = ['python', 'setup.py', 'develop', '--uninstall']
class ComponentBase():
def __init__(self, component_name, **kargs):
self.cfg = kargs.get("cfg")
self.packager = kargs.get("pkg")
self.distro = kargs.get("distro")
self.root = kargs.get("root")
self.all_components = set(kargs.get("components", []))
(self.componentroot, self.tracedir,
self.appdir, self.cfgdir) = Util.component_paths(self.root, component_name)
self.component_name = component_name
self.component_info = kargs.get('component_info')
#
#the following are just interfaces...
#
class InstallComponent():
def __init__(self):
pass
@@ -101,11 +87,24 @@ class RuntimeComponent():
# useful impls
class ComponentBase():
def __init__(self, component_name, **kargs):
self.cfg = kargs.get("cfg")
self.packager = kargs.get("pkg")
self.distro = kargs.get("distro")
self.root = kargs.get("root")
self.all_components = set(kargs.get("components", []))
(self.componentroot, self.tracedir,
self.appdir, self.cfgdir) = utils.component_paths(self.root, component_name)
self.component_name = component_name
self.component_info = kargs.get('component_info')
class PkgInstallComponent(ComponentBase, InstallComponent):
def __init__(self, component_name, *args, **kargs):
ComponentBase.__init__(self, component_name, *args, **kargs)
InstallComponent.__init__(self)
self.tracewriter = Trace.TraceWriter(self.tracedir, Trace.IN_TRACE)
self.tracewriter = tr.TraceWriter(self.tracedir, tr.IN_TRACE)
def _get_download_locations(self):
return list()
@@ -122,10 +121,10 @@ class PkgInstallComponent(ComponentBase, InstallComponent):
subdir = location_info.get("subdir")
target_loc = None
if(subdir and len(subdir)):
target_loc = Shell.joinpths(base_dir, subdir)
target_loc = sh.joinpths(base_dir, subdir)
else:
target_loc = base_dir
dirsmade = Downloader.download(target_loc, uri, branch)
dirsmade = down.download(target_loc, uri, branch)
self.tracewriter.downloaded(target_loc, uri)
self.tracewriter.dir_made(*dirsmade)
am_downloaded += 1
@@ -135,10 +134,10 @@ class PkgInstallComponent(ComponentBase, InstallComponent):
return None
def install(self):
pkgs = Util.get_pkg_list(self.distro, self.component_name)
pkgs = utils.get_pkg_list(self.distro, self.component_name)
if(len(pkgs)):
pkgnames = sorted(pkgs.keys())
LOG.info("Installing packages %s" % (", ".join(pkgnames)))
LOG.info("Installing packages (%s)." % (", ".join(pkgnames)))
self.packager.install_batch(pkgs)
#add trace used to remove the pkgs
for name in pkgnames:
@@ -146,14 +145,14 @@ class PkgInstallComponent(ComponentBase, InstallComponent):
return self.tracedir
def pre_install(self):
pkgs = Util.get_pkg_list(self.distro, self.component_name)
pkgs = utils.get_pkg_list(self.distro, self.component_name)
if(len(pkgs)):
mp = self._get_param_map(None)
self.packager.pre_install(pkgs, mp)
return self.tracedir
def post_install(self):
pkgs = Util.get_pkg_list(self.distro, self.component_name)
pkgs = utils.get_pkg_list(self.distro, self.component_name)
if(len(pkgs)):
mp = self._get_param_map(None)
self.packager.post_install(pkgs, mp)
@@ -166,13 +165,13 @@ class PkgInstallComponent(ComponentBase, InstallComponent):
return contents
def _get_target_config_name(self, name):
return Shell.joinpths(self.cfgdir, name)
return sh.joinpths(self.cfgdir, name)
def _get_source_config_name(self, name):
return Shell.joinpths(Util.STACK_CONFIG_DIR, self.component_name, name)
return sh.joinpths(c.STACK_CONFIG_DIR, self.component_name, name)
def configure(self):
dirsmade = Shell.mkdirslist(self.cfgdir)
dirsmade = sh.mkdirslist(self.cfgdir)
self.tracewriter.dir_made(*dirsmade)
configs = self._get_config_files()
if(len(configs)):
@@ -183,19 +182,19 @@ class PkgInstallComponent(ComponentBase, InstallComponent):
sourcefn = self._get_source_config_name(fn)
tgtfn = self._get_target_config_name(fn)
#ensure directory is there (if not created previously)
dirsmade = Shell.mkdirslist(os.path.dirname(tgtfn))
dirsmade = sh.mkdirslist(sh.dirname(tgtfn))
self.tracewriter.dir_made(*dirsmade)
#now configure it
LOG.info("Configuring template file %s" % (sourcefn))
contents = Shell.load_file(sourcefn)
contents = sh.load_file(sourcefn)
LOG.info("Replacing parameters in file %s" % (sourcefn))
LOG.debug("Replacements = %s" % (parameters))
contents = Util.param_replace(contents, parameters)
contents = utils.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))
#this trace is used to remove the files configured
Shell.write_file(tgtfn, contents)
sh.write_file(tgtfn, contents)
self.tracewriter.cfg_write(tgtfn)
return len(configs)
@@ -214,10 +213,10 @@ class PythonInstallComponent(PkgInstallComponent):
def _install_pips(self):
#install any need pip items
pips = Util.get_pip_list(self.distro, self.component_name)
pips = utils.get_pip_list(self.distro, self.component_name)
if(len(pips)):
LOG.info("Setting up %s pips" % (len(pips)))
Pip.install(pips)
pip.install(pips)
for name in pips.keys():
self.tracewriter.pip_install(name, pips.get(name))
@@ -233,14 +232,14 @@ class PythonInstallComponent(PkgInstallComponent):
return combined_output
def _format_trace_name(self, name):
return "%s-%s" % (Trace.PY_TRACE, name)
return "%s-%s" % (tr.PY_TRACE, name)
def _install_python_setups(self):
#setup any python directories
pydirs = self._get_python_directories()
if(len(pydirs)):
LOG.info("Setting up %s python directories" % (len(pydirs)))
dirsmade = Shell.mkdirslist(self.tracedir)
dirsmade = sh.mkdirslist(self.tracedir)
self.tracewriter.dir_made(*dirsmade)
for pydir_info in pydirs:
name = pydir_info.get("name")
@@ -248,10 +247,10 @@ class PythonInstallComponent(PkgInstallComponent):
#TODO should we raise an exception here?
continue
working_dir = pydir_info.get('work_dir', self.appdir)
record_fn = Trace.touch_trace(self.tracedir, self._format_trace_name(name))
record_fn = tr.touch_trace(self.tracedir, self._format_trace_name(name))
self.tracewriter.file_touched(record_fn)
(stdout, stderr) = Shell.execute(*PY_INSTALL, cwd=working_dir, run_as_root=True)
Shell.write_file(record_fn, self._format_stderr_out(stderr, stdout))
(stdout, stderr) = sh.execute(*PY_INSTALL, cwd=working_dir, run_as_root=True)
sh.write_file(record_fn, self._format_stderr_out(stderr, stdout))
self.tracewriter.py_install(name, record_fn, working_dir)
def _python_install(self):
@@ -268,7 +267,7 @@ class PkgUninstallComponent(ComponentBase, UninstallComponent):
def __init__(self, component_name, *args, **kargs):
ComponentBase.__init__(self, component_name, *args, **kargs)
UninstallComponent.__init__(self)
self.tracereader = Trace.TraceReader(self.tracedir, Trace.IN_TRACE)
self.tracereader = tr.TraceReader(self.tracedir, tr.IN_TRACE)
def unconfigure(self):
self._unconfigure_files()
@@ -279,7 +278,7 @@ class PkgUninstallComponent(ComponentBase, UninstallComponent):
LOG.info("Removing %s configuration files" % (len(cfgfiles)))
for fn in cfgfiles:
if(len(fn)):
Shell.unlink(fn)
sh.unlink(fn)
def uninstall(self):
self._uninstall_pkgs()
@@ -298,14 +297,14 @@ class PkgUninstallComponent(ComponentBase, UninstallComponent):
LOG.info("Removing %s touched files" % (len(filestouched)))
for fn in filestouched:
if(len(fn)):
Shell.unlink(fn)
sh.unlink(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:
Shell.deldir(dirname)
sh.deldir(dirname)
class PythonUninstallComponent(PkgUninstallComponent):
@@ -323,7 +322,7 @@ class PythonUninstallComponent(PkgUninstallComponent):
pips = self.tracereader.pips_installed()
if(len(pips)):
LOG.info("Uninstalling %s pips" % (len(pips)))
Pip.uninstall(pips)
pip.uninstall(pips)
def _uninstall_python(self):
pylisting = self.tracereader.py_listing()
@@ -331,28 +330,28 @@ class PythonUninstallComponent(PkgUninstallComponent):
LOG.info("Uninstalling %s python setups" % (len(pylisting)))
for entry in pylisting:
where = entry.get('where')
Shell.execute(*PY_UNINSTALL, cwd=where, run_as_root=True)
sh.execute(*PY_UNINSTALL, cwd=where, run_as_root=True)
class ProgramRuntime(ComponentBase, RuntimeComponent):
#this here determines how we start and stop and
#what classes handle different running/stopping types
STARTER_CLS_MAPPING = {
runners.Foreground.RUN_TYPE: runners.Foreground.ForegroundRunner,
runners.Screen.RUN_TYPE: runners.Screen.ScreenRunner,
fork.RUN_TYPE: fork.ForkRunner,
screen.RUN_TYPE: screen.ScreenRunner,
}
STOPPER_CLS_MAPPING = {
runners.Foreground.RUN_TYPE: runners.Foreground.ForegroundRunner,
runners.Screen.RUN_TYPE: runners.Screen.ScreenRunner,
fork.RUN_TYPE: fork.ForkRunner,
screen.RUN_TYPE: screen.ScreenRunner,
}
def __init__(self, component_name, *args, **kargs):
ComponentBase.__init__(self, component_name, *args, **kargs)
RuntimeComponent.__init__(self)
self.run_type = kargs.get("run_type", runners.Foreground.RUN_TYPE)
self.tracereader = Trace.TraceReader(self.tracedir, Trace.IN_TRACE)
self.tracewriter = Trace.TraceWriter(self.tracedir, Trace.START_TRACE)
self.starttracereader = Trace.TraceReader(self.tracedir, Trace.START_TRACE)
self.run_type = kargs.get("run_type", fork.RUN_TYPE)
self.tracereader = tr.TraceReader(self.tracedir, tr.IN_TRACE)
self.tracewriter = tr.TraceWriter(self.tracedir, tr.START_TRACE)
self.starttracereader = tr.TraceReader(self.tracedir, tr.START_TRACE)
self.check_installed_pkgs = kargs.get("check_installed_pkgs", True)
def _getstartercls(self, start_mode):
@@ -387,7 +386,7 @@ class ProgramRuntime(ComponentBase, RuntimeComponent):
#ensure it was installed
if(not self._was_installed()):
msg = "Can not start %s since it was not installed" % (self.component_name)
raise Exceptions.StartException(msg)
raise excp.StartException(msg)
#select how we are going to start it
startercls = self._getstartercls(self.run_type)
starter = startercls()
@@ -406,7 +405,7 @@ class ProgramRuntime(ComponentBase, RuntimeComponent):
if(params and program_opts):
adjusted_opts = list()
for opt in program_opts:
adjusted_opts.append(Util.param_replace(opt, params))
adjusted_opts.append(utils.param_replace(opt, params))
program_opts = adjusted_opts
LOG.info("Starting [%s] with options [%s]" % (app_name, ", ".join(program_opts)))
#start it with the given settings
@@ -425,7 +424,7 @@ class ProgramRuntime(ComponentBase, RuntimeComponent):
#ensure it was installed
if(not self._was_installed()):
msg = "Can not stop %s since it was not installed" % (self.component_name)
raise Exceptions.StopException(msg)
raise excp.StopException(msg)
#we can only stop what has a started trace
start_traces = self.starttracereader.apps_started()
killedam = 0
@@ -437,7 +436,7 @@ class ProgramRuntime(ComponentBase, RuntimeComponent):
if(fn == None or name == None):
continue
#figure out which class will stop it
contents = Trace.parse_fn(fn)
contents = tr.parse_fn(fn)
killcls = None
for (cmd, action) in contents:
if(cmd == Runner.RUN_TYPE):
@@ -455,7 +454,7 @@ class ProgramRuntime(ComponentBase, RuntimeComponent):
if(killedam == len(start_traces)):
fn = self.starttracereader.trace_fn
LOG.info("Deleting trace file %s" % (fn))
Shell.unlink(fn)
sh.unlink(fn)
return killedam
def status(self):

View File

@@ -0,0 +1,14 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.

View File

@@ -15,23 +15,17 @@
import re
import Logger
import Packager
from devstack import component as comp
from devstack import constants
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
from devstack import trace as tr
from devstack import utils
#TODO fix these
from Component import (PkgUninstallComponent, PkgInstallComponent,
ComponentBase, RuntimeComponent)
from Util import (DB,
get_host_ip,
execute_template)
from Exceptions import (StartException, StopException,
StatusException, RestartException)
from Shell import (execute)
from Trace import (TraceReader,
IN_TRACE)
LOG = Logger.getLogger("install.db")
TYPE = DB
LOG = logging.getLogger("devstack.components.db")
TYPE = constants.DB
MYSQL = 'mysql'
DB_ACTIONS = {
MYSQL: {
@@ -57,14 +51,14 @@ DB_ACTIONS = {
BASE_ERROR = 'Currently we do not know how to %s for database type [%s]'
class DBUninstaller(PkgUninstallComponent):
class DBUninstaller(comp.PkgUninstallComponent):
def __init__(self, *args, **kargs):
PkgUninstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PkgUninstallComponent.__init__(self, TYPE, *args, **kargs)
class DBInstaller(PkgInstallComponent):
class DBInstaller(comp.PkgInstallComponent):
def __init__(self, *args, **kargs):
PkgInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PkgInstallComponent.__init__(self, TYPE, *args, **kargs)
self.runtime = DBRuntime(*args, **kargs)
def _get_param_map(self, config_fn):
@@ -74,13 +68,13 @@ class DBInstaller(PkgInstallComponent):
out['PASSWORD'] = self.cfg.getpw("passwords", "sql")
out['BOOT_START'] = str(True).lower()
out['USER'] = self.cfg.get("db", "sql_user")
hostip = get_host_ip(self.cfg)
hostip = utils.get_host_ip(self.cfg)
out['SERVICE_HOST'] = hostip
out['HOST_IP'] = hostip
return out
def post_install(self):
parent_result = PkgInstallComponent.post_install(self)
parent_result = comp.PkgInstallComponent.post_install(self)
#extra actions to ensure we are granted access
dbtype = self.cfg.get("db", "type")
dbactions = DB_ACTIONS.get(dbtype)
@@ -95,21 +89,21 @@ class DBInstaller(PkgInstallComponent):
})
#shell seems to be needed here
#since python escapes this to much...
execute_template(*cmds, params=params, shell=True)
utils.execute_template(*cmds, params=params, shell=True)
#special mysql actions
if(dbactions and dbtype == MYSQL):
cmd = dbactions.get('host_adjust')
if(cmd):
execute(*cmd, run_as_root=True, shell=True)
sh.execute(*cmd, run_as_root=True, shell=True)
#restart it to make sure all good
self.runtime.restart()
return parent_result
class DBRuntime(ComponentBase, RuntimeComponent):
class DBRuntime(comp.ComponentBase, comp.RuntimeComponent):
def __init__(self, *args, **kargs):
ComponentBase.__init__(self, TYPE, *args, **kargs)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
comp.ComponentBase.__init__(self, TYPE, *args, **kargs)
self.tracereader = tr.TraceReader(self.tracedir, tr.IN_TRACE)
def _gettypeactions(self, act, exception_cls):
pkgsinstalled = self.tracereader.packages_installed()
@@ -126,25 +120,25 @@ class DBRuntime(ComponentBase, RuntimeComponent):
def start(self):
if(self.status().find('start') == -1):
startcmd = self._gettypeactions('start', StartException)
execute(*startcmd, run_as_root=True)
startcmd = self._gettypeactions('start', excp.StartException)
sh.execute(*startcmd, run_as_root=True)
return None
def stop(self):
if(self.status().find('stop') == -1):
stopcmd = self._gettypeactions('stop', StopException)
execute(*stopcmd, run_as_root=True)
stopcmd = self._gettypeactions('stop', excp.StopException)
sh.execute(*stopcmd, run_as_root=True)
return 1
return 0
def restart(self):
restartcmd = self._gettypeactions('restart', RestartException)
execute(*restartcmd, run_as_root=True)
restartcmd = self._gettypeactions('restart', excp.RestartException)
sh.execute(*restartcmd, run_as_root=True)
return 1
def status(self):
statuscmd = self._gettypeactions('status', StatusException)
(sysout, stderr) = execute(*statuscmd, run_as_root=True)
statuscmd = self._gettypeactions('status', excp.StatusException)
(sysout, stderr) = sh.execute(*statuscmd, run_as_root=True)
return sysout.strip()
@@ -162,7 +156,7 @@ def drop_db(cfg, dbname):
'cmd': dropcmd,
'run_as_root': False,
})
execute_template(*cmds, params=params)
utils.execute_template(*cmds, params=params)
else:
msg = BASE_ERROR % ('drop', dbtype)
raise NotImplementedError(msg)
@@ -182,7 +176,7 @@ def create_db(cfg, dbname):
'cmd': createcmd,
'run_as_root': False,
})
execute_template(*cmds, params=params)
utils.execute_template(*cmds, params=params)
else:
msg = BASE_ERROR % ('create', dbtype)
raise NotImplementedError(msg)

View File

@@ -13,27 +13,23 @@
# License for the specific language governing permissions and limitations
# under the License.
import io
import json
import os.path
import io
import Config
import Logger
import Db
from devstack import cfg
from devstack import component as comp
from devstack import constants
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
from devstack.components import db
#TODO fix these
from Component import (PythonUninstallComponent,
PythonInstallComponent,
PythonRuntime)
from Util import (GLANCE,
get_host_ip, param_replace)
from Shell import (deldir, mkdirslist, unlink,
joinpths, touch_file)
LOG = Logger.getLogger("install.glance")
LOG = logging.getLogger("devstack.components.glance")
#naming + config files
TYPE = GLANCE
TYPE = constants.GLANCE
API_CONF = "glance-api.conf"
REG_CONF = "glance-registry.conf"
CONFIGS = [API_CONF, REG_CONF]
@@ -42,30 +38,30 @@ CFG_SECTION = 'DEFAULT'
#what to start
APP_OPTIONS = {
'glance-api': ['--config-file', joinpths('%ROOT%', "etc", API_CONF)],
'glance-registry': ['--config-file', joinpths('%ROOT%', "etc", REG_CONF)]
'glance-api': ['--config-file', sh.joinpths('%ROOT%', "etc", API_CONF)],
'glance-registry': ['--config-file', sh.joinpths('%ROOT%', "etc", REG_CONF)]
}
CONFIG_ACTUAL_DIR = 'etc'
BIN_DIR = 'bin'
class GlanceUninstaller(PythonUninstallComponent):
class GlanceUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
self.cfgdir = sh.joinpths(self.appdir, CONFIG_ACTUAL_DIR)
class GlanceRuntime(PythonRuntime):
class GlanceRuntime(comp.PythonRuntime):
def __init__(self, *args, **kargs):
PythonRuntime.__init__(self, TYPE, *args, **kargs)
self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
comp.PythonRuntime.__init__(self, TYPE, *args, **kargs)
self.cfgdir = sh.joinpths(self.appdir, CONFIG_ACTUAL_DIR)
def _get_apps_to_start(self):
apps = list()
for app_name in APP_OPTIONS.keys():
apps.append({
'name': app_name,
'path': joinpths(self.appdir, BIN_DIR, app_name),
'path': sh.joinpths(self.appdir, BIN_DIR, app_name),
})
return apps
@@ -73,15 +69,15 @@ class GlanceRuntime(PythonRuntime):
return APP_OPTIONS.get(app)
class GlanceInstaller(PythonInstallComponent):
class GlanceInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.git_loc = self.cfg.get("git", "glance_repo")
self.git_branch = self.cfg.get("git", "glance_branch")
self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
self.cfgdir = sh.joinpths(self.appdir, CONFIG_ACTUAL_DIR)
def _get_download_locations(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.git_loc,
'branch': self.git_branch,
@@ -93,13 +89,13 @@ class GlanceInstaller(PythonInstallComponent):
return list(CONFIGS)
def post_install(self):
parent_result = PythonInstallComponent.post_install(self)
parent_result = comp.PythonInstallComponent.post_install(self)
self._setup_db()
return parent_result
def _setup_db(self):
Db.drop_db(self.cfg, DB_NAME)
Db.create_db(self.cfg, DB_NAME)
db.drop_db(self.cfg, DB_NAME)
db.create_db(self.cfg, DB_NAME)
def _config_adjust(self, contents, name):
if(name not in CONFIGS):
@@ -108,7 +104,7 @@ class GlanceInstaller(PythonInstallComponent):
#then extract known configs that
#will need locations/directories/files made (or touched)...
with io.BytesIO(contents) as stream:
config = Config.IgnoreMissingConfigParser()
config = cfg.IgnoreMissingConfigParser()
config.readfp(stream)
if(config.getboolean('image_cache_enabled', CFG_SECTION)):
cache_dir = config.get("image_cache_datadir", CFG_SECTION)
@@ -163,7 +159,7 @@ class GlanceInstaller(PythonInstallComponent):
mp['SYSLOG'] = self.cfg.getboolean("default", "syslog")
mp['SERVICE_TOKEN'] = self.cfg.getpw("passwords", "service_token")
mp['SQL_CONN'] = self.cfg.get_dbdsn(DB_NAME)
hostip = get_host_ip(self.cfg)
hostip = utils.get_host_ip(self.cfg)
mp['SERVICE_HOST'] = hostip
mp['HOST_IP'] = hostip
return mp

View File

@@ -14,17 +14,13 @@
# under the License.
import Logger
import Util
import Shell
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
#TODO fix these
from Component import (PythonUninstallComponent,
PythonInstallComponent,
NullRuntime)
LOG = Logger.getLogger("install.horizon")
TYPE = Util.HORIZON
TYPE = constants.HORIZON
ROOT_HORIZON = 'horizon'
HORIZON_NAME = 'horizon'
@@ -35,22 +31,24 @@ HORIZON_PY_CONF = "horizon_settings.py"
HORIZON_PY_CONF_TGT = ['local', 'local_settings.py']
CONFIGS = [HORIZON_PY_CONF]
LOG = logging.getLogger("devstack.components.horizon")
class HorizonUninstaller(PythonUninstallComponent):
class HorizonUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
class HorizonInstaller(PythonInstallComponent):
class HorizonInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.git_loc = self.cfg.get("git", "horizon_repo")
self.git_branch = self.cfg.get("git", "horizon_branch")
self.horizon_dir = Shell.joinpths(self.appdir, ROOT_HORIZON)
self.dash_dir = Shell.joinpths(self.appdir, ROOT_DASH)
self.horizon_dir = sh.joinpths(self.appdir, ROOT_HORIZON)
self.dash_dir = sh.joinpths(self.appdir, ROOT_DASH)
def _get_download_locations(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.git_loc,
'branch': self.git_branch,
@@ -59,9 +57,9 @@ class HorizonInstaller(PythonInstallComponent):
def _get_target_config_name(self, config_name):
if(config_name == HORIZON_PY_CONF):
return Shell.joinpths(self.dash_dir, *HORIZON_PY_CONF_TGT)
return sh.joinpths(self.dash_dir, *HORIZON_PY_CONF_TGT)
else:
return PythonInstallComponent._get_target_config_name(self, config_name)
return comp.PythonInstallComponent._get_target_config_name(self, config_name)
def _get_python_directories(self):
py_dirs = list()
@@ -83,10 +81,10 @@ class HorizonInstaller(PythonInstallComponent):
#this dict will be used to fill in the configuration
#params with actual values
mp = dict()
mp['OPENSTACK_HOST'] = Util.get_host_ip(self.cfg)
mp['OPENSTACK_HOST'] = utils.get_host_ip(self.cfg)
return mp
class HorizonRuntime(NullRuntime):
class HorizonRuntime(comp.NullRuntime):
def __init__(self, *args, **kargs):
NullRuntime.__init__(self, TYPE, *args, **kargs)
comp.NullRuntime.__init__(self, TYPE, *args, **kargs)

View File

@@ -13,58 +13,51 @@
# License for the specific language governing permissions and limitations
# under the License.
import io
import os
import os.path
import io
import Pip
import Logger
import Db
import Config
from devstack import cfg
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
from devstack.components import db
#TODO fix these
from Util import (KEYSTONE,
CONFIG_DIR,
NOVA, GLANCE, SWIFT,
get_host_ip,
execute_template,
param_replace)
from Component import (PythonUninstallComponent,
PythonInstallComponent, PythonRuntime)
from Shell import (mkdirslist, unlink, touch_file, joinpths)
LOG = logging.getLogger("devstack.components.keystone")
LOG = Logger.getLogger("install.keystone")
TYPE = KEYSTONE
TYPE = constants.KEYSTONE
ROOT_CONF = "keystone.conf"
CONFIGS = [ROOT_CONF]
BIN_DIR = "bin"
CONFIG_DIR = "config"
DB_NAME = "keystone"
CFG_SECTION = 'DEFAULT'
#what to start
APP_OPTIONS = {
'keystone': ['--config-file', joinpths('%ROOT%', "config", ROOT_CONF), "--verbose"],
'keystone': ['--config-file', sh.joinpths('%ROOT%', "config", ROOT_CONF), "--verbose"],
}
class KeystoneUninstaller(PythonUninstallComponent):
class KeystoneUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
self.cfgdir = joinpths(self.appdir, CONFIG_DIR)
self.bindir = joinpths(self.appdir, BIN_DIR)
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR)
self.bindir = sh.joinpths(self.appdir, BIN_DIR)
class KeystoneInstaller(PythonInstallComponent):
class KeystoneInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.git_loc = self.cfg.get("git", "keystone_repo")
self.git_branch = self.cfg.get("git", "keystone_branch")
self.cfgdir = joinpths(self.appdir, CONFIG_DIR)
self.bindir = joinpths(self.appdir, BIN_DIR)
self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR)
self.bindir = sh.joinpths(self.appdir, BIN_DIR)
def _get_download_locations(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.git_loc,
'branch': self.git_branch,
@@ -72,7 +65,7 @@ class KeystoneInstaller(PythonInstallComponent):
return places
def post_install(self):
parent_result = PythonInstallComponent.post_install(self)
parent_result = comp.PythonInstallComponent.post_install(self)
self._setup_db()
self._setup_data()
return parent_result
@@ -81,13 +74,13 @@ class KeystoneInstaller(PythonInstallComponent):
return list(CONFIGS)
def _setup_db(self):
Db.drop_db(self.cfg, DB_NAME)
Db.create_db(self.cfg, DB_NAME)
db.drop_db(self.cfg, DB_NAME)
db.create_db(self.cfg, DB_NAME)
def _setup_data(self):
params = self._get_param_map(None)
cmds = _keystone_setup_cmds(self.all_components)
execute_template(*cmds, params=params, ignore_missing=True)
utils.execute_template(*cmds, params=params, ignore_missing=True)
def _config_adjust(self, contents, name):
if(name not in CONFIGS):
@@ -96,7 +89,7 @@ class KeystoneInstaller(PythonInstallComponent):
#then extract known configs that
#will need locations/directories/files made (or touched)...
with io.BytesIO(contents) as stream:
config = Config.IgnoreMissingConfigParser()
config = cfg.IgnoreMissingConfigParser()
config.readfp(stream)
log_filename = config.get('log_file', CFG_SECTION)
if(log_filename):
@@ -104,12 +97,12 @@ class KeystoneInstaller(PythonInstallComponent):
log_dir = os.path.dirname(log_filename)
if(log_dir):
LOG.info("Ensuring log directory %s exists" % (log_dir))
dirsmade = mkdirslist(log_dir)
dirsmade = sh.mkdirslist(log_dir)
#this trace is used to remove the dirs created
self.tracewriter.dir_made(*dirsmade)
#destroy then recreate it (the log file)
unlink(log_filename)
touch_file(log_filename)
sh.unlink(log_filename)
sh.touch_file(log_filename)
self.tracewriter.file_touched(log_filename)
#we might need to handle more in the future...
#nothing modified so just return the original
@@ -122,25 +115,25 @@ class KeystoneInstaller(PythonInstallComponent):
mp['DEST'] = self.appdir
mp['SQL_CONN'] = self.cfg.get_dbdsn(DB_NAME)
mp['ADMIN_PASSWORD'] = self.cfg.getpw('passwords', 'horizon_keystone_admin')
mp['HOST_IP'] = get_host_ip(self.cfg)
mp['HOST_IP'] = utils.get_host_ip(self.cfg)
mp['SERVICE_TOKEN'] = self.cfg.getpw("passwords", "service_token")
mp['BIN_DIR'] = self.bindir
mp['CONFIG_FILE'] = joinpths(self.cfgdir, ROOT_CONF)
mp['CONFIG_FILE'] = sh.joinpths(self.cfgdir, ROOT_CONF)
return mp
class KeystoneRuntime(PythonRuntime):
class KeystoneRuntime(comp.PythonRuntime):
def __init__(self, *args, **kargs):
PythonRuntime.__init__(self, TYPE, *args, **kargs)
self.cfgdir = joinpths(self.appdir, CONFIG_DIR)
self.bindir = joinpths(self.appdir, BIN_DIR)
comp.PythonRuntime.__init__(self, TYPE, *args, **kargs)
self.cfgdir = sh.joinpths(self.appdir, CONFIG_DIR)
self.bindir = sh.joinpths(self.appdir, BIN_DIR)
def _get_apps_to_start(self):
apps = list()
for app_name in APP_OPTIONS.keys():
apps.append({
'name': app_name,
'path': joinpths(self.bindir, app_name),
'path': sh.joinpths(self.bindir, app_name),
})
return apps
@@ -233,7 +226,7 @@ def _keystone_setup_cmds(components):
"cmd": root_cmd + ["service", "add", "keystone", "identity", "Keystone Identity Service"]
})
if(NOVA in components):
if(constants.NOVA in components):
services.append({
"cmd": root_cmd + ["service", "add", "nova", "compute", "Nova Compute Service"]
})
@@ -241,12 +234,12 @@ def _keystone_setup_cmds(components):
"cmd": root_cmd + ["service", "add", "ec2", "ec2", "EC2 Compatability Layer"]
})
if(GLANCE in components):
if(constants.GLANCE in components):
services.append({
"cmd": root_cmd + ["service", "add", "glance", "image", "Glance Image Service"]
})
if(SWIFT in components):
if(constants.SWIFT in components):
services.append({
"cmd": root_cmd + ["service", "add", "swift", "object-store", "Swift Service"]
})
@@ -264,7 +257,7 @@ def _keystone_setup_cmds(components):
]
})
if(NOVA in components):
if(constants.NOVA in components):
endpoint_templates.append({
"cmd": root_cmd + ["endpointTemplates", "add",
"RegionOne", "nova",
@@ -286,7 +279,7 @@ def _keystone_setup_cmds(components):
]
})
if(GLANCE in components):
if(constants.GLANCE in components):
endpoint_templates.append({
"cmd": root_cmd + ["endpointTemplates", "add",
"RegionOne", "glance",
@@ -298,7 +291,7 @@ def _keystone_setup_cmds(components):
]
})
if(SWIFT in components):
if(constants.SWIFT in components):
endpoint_templates.append({
"cmd": root_cmd + ["endpointTemplates", "add",
"RegionOne", "swift",
@@ -321,7 +314,7 @@ def _keystone_setup_cmds(components):
# but keystone doesn't parse them - it is just a blob from keystone's
# point of view
ec2_creds = []
if(NOVA in components):
if(constants.NOVA in components):
ec2_creds = [
{
"cmd": root_cmd + ["credentials", "add",

View File

@@ -14,32 +14,29 @@
# under the License.
import Logger
import Util
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
#TODO fix these
from Component import (PythonUninstallComponent,
PythonInstallComponent,
NullRuntime)
TYPE = constants.KEYSTONE_CLIENT
LOG = logging.getLogger("devstack.components.keystone_client")
LOG = Logger.getLogger("install.keystone.client")
TYPE = Util.KEYSTONE_CLIENT
class KeyStoneClientUninstaller(PythonUninstallComponent):
class KeyStoneClientUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
class KeyStoneClientInstaller(PythonInstallComponent):
class KeyStoneClientInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.git_loc = self.cfg.get("git", "keystoneclient_repo")
self.git_branch = self.cfg.get("git", "keystoneclient_branch")
def _get_download_locations(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.git_loc,
'branch': self.git_branch,
@@ -47,6 +44,6 @@ class KeyStoneClientInstaller(PythonInstallComponent):
return places
class KeyStoneClientRuntime(NullRuntime):
class KeyStoneClientRuntime(comp.NullRuntime):
def __init__(self, *args, **kargs):
NullRuntime.__init__(self, TYPE, *args, **kargs)
comp.NullRuntime.__init__(self, TYPE, *args, **kargs)

View File

@@ -14,25 +14,18 @@
# under the License.
import Logger
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
from devstack.components import nova_conf as nc
from Component import (PythonUninstallComponent,
PythonInstallComponent,
PythonRuntime)
import Shell
import os
LOG = Logger.getLogger("install.nova")
LOG = logging.getLogger("devstack.components.nova")
API_CONF = "nova.conf"
CONFIGS = [API_CONF]
DB_NAME = "nova"
#
from Util import (NOVA)
from NovaConf import (NovaConf)
TYPE = NOVA
TYPE = constants.NOVA
#what to start
# Does this start nova-compute, nova-volume, nova-network, nova-scheduler
@@ -43,22 +36,22 @@ TYPE = NOVA
#}
class NovaUninstaller(PythonUninstallComponent):
class NovaUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
#self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
class NovaInstaller(PythonInstallComponent):
class NovaInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.gitloc = self.cfg.get("git", "nova_repo")
self.brch = self.cfg.get("git", "nova_branch")
# TBD is this the install location of the conf file?
#self.cfgdir = joinpths(self.appdir, CONFIG_ACTUAL_DIR)
def _get_download_location(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.gitloc,
'branch': self.brch,
@@ -67,9 +60,9 @@ class NovaInstaller(PythonInstallComponent):
def configure(self):
# FIXME, is this necessary? Is it for the template source?
dirsmade = Shell.mkdirslist(self.cfgdir)
dirsmade = sh.mkdirslist(self.cfgdir)
self.tracewriter.dir_made(*dirsmade)
nconf = NovaConf(self)
nconf = nc.NovaConf(self)
LOG.info("Getting dynamic content for nova.conf")
# Get dynamic content for nova.conf
lines = nconf.generate()
@@ -77,15 +70,15 @@ class NovaInstaller(PythonInstallComponent):
# Set up and write lines to the file
fn = API_CONF
tgtfn = self._get_full_config_name(fn)
dirsmade = Shell.mkdirslist(os.path.dirname(tgtfn))
dirsmade = sh.mkdirslist(os.path.dirname(tgtfn))
self.tracewriter.dir_made(*dirsmade)
LOG.info("Writing configuration file %s" % (tgtfn))
#this trace is used to remove the files configured
Shell.write_file(tgtfn, os.linesep.join(lines))
sh.write_file(tgtfn, os.linesep.join(lines))
self.tracewriter.cfg_write(tgtfn)
return 1
class NovaRuntime(PythonRuntime):
class NovaRuntime(comp.PythonRuntime):
def __init__(self, *args, **kargs):
PythonRuntime.__init__(self, TYPE, *args, **kargs)
comp.PythonRuntime.__init__(self, TYPE, *args, **kargs)

View File

@@ -13,33 +13,29 @@
# License for the specific language governing permissions and limitations
# under the License.
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
import Logger
import Util
#TODO fix these
from Component import (PythonUninstallComponent,
PythonInstallComponent,
NullRuntime)
LOG = logging.getLogger("devstack.components.nova_client")
TYPE = constants.NOVA_CLIENT
LOG = Logger.getLogger("install.nova.client")
TYPE = Util.NOVA_CLIENT
class NovaClientUninstaller(PythonUninstallComponent):
class NovaClientUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
class NovaClientInstaller(PythonInstallComponent):
class NovaClientInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.git_loc = self.cfg.get("git", "novaclient_repo")
self.git_branch = self.cfg.get("git", "novaclient_branch")
def _get_download_locations(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.git_loc,
'branch': self.git_branch,
@@ -51,10 +47,10 @@ class NovaClientInstaller(PythonInstallComponent):
#params with actual values
mp = dict()
mp['DEST'] = self.appdir
mp['OPENSTACK_HOST'] = Util.get_host_ip(self.cfg)
mp['OPENSTACK_HOST'] = utils.get_host_ip(self.cfg)
return mp
class NovaClientRuntime(NullRuntime):
class NovaClientRuntime(comp.NullRuntime):
def __init__(self, *args, **kargs):
NullRuntime.__init__(self, TYPE, *args, **kargs)
comp.NullRuntime.__init__(self, TYPE, *args, **kargs)

View File

@@ -12,11 +12,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import Logger
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
from Util import (QUANTUM, get_host_ip)
LOG = Logger.getLogger("install.nova_conf")
LOG = logging.getLogger("devstack.components.nova_conf")
QUANTUM_OPENSWITCH_OPS = [
'--libvirt_vif_type=ethernet',

View File

@@ -13,33 +13,29 @@
# License for the specific language governing permissions and limitations
# under the License.
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
import Logger
import Util
#TODO fix these
from Component import (PythonUninstallComponent,
PythonInstallComponent,
NullRuntime)
LOG = logging.getLogger("devstack.components.openstackx")
TYPE = constants.OPENSTACK_X
LOG = Logger.getLogger("install.openstackx")
TYPE = Util.OPENSTACK_X
class OpenstackXUninstaller(PythonUninstallComponent):
class OpenstackXUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs):
PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonUninstallComponent.__init__(self, TYPE, *args, **kargs)
class OpenstackXInstaller(PythonInstallComponent):
class OpenstackXInstaller(comp.PythonInstallComponent):
def __init__(self, *args, **kargs):
PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PythonInstallComponent.__init__(self, TYPE, *args, **kargs)
self.git_loc = self.cfg.get("git", "openstackx_repo")
self.git_branch = self.cfg.get("git", "openstackx_branch")
def _get_download_locations(self):
places = PythonInstallComponent._get_download_locations(self)
places = comp.PythonInstallComponent._get_download_locations(self)
places.append({
'uri': self.git_loc,
'branch': self.git_branch,
@@ -47,6 +43,6 @@ class OpenstackXInstaller(PythonInstallComponent):
return places
class OpenstackXRuntime(NullRuntime):
class OpenstackXRuntime(comp.NullRuntime):
def __init__(self, *args, **kargs):
NullRuntime.__init__(self, TYPE, *args, **kargs)
comp.NullRuntime.__init__(self, TYPE, *args, **kargs)

View File

@@ -13,17 +13,18 @@
# License for the specific language governing permissions and limitations
# under the License.
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
import Logger
LOG = logging.getLogger("devstack.components.quantum")
TYPE = constants.QUANTUM
import Component
LOG = Logger.getLogger("install.quantum")
class QuantumUninstaller(Component.UninstallComponent):
class QuantumUninstaller(comp.UninstallComponent):
def __init__(self, *args, **kargs):
Component.UninstallComponent.__init__(self)
comp.UninstallComponent.__init__(self)
def unconfigure(self):
pass
@@ -32,9 +33,9 @@ class QuantumUninstaller(Component.UninstallComponent):
pass
class QuantumInstaller(Component.InstallComponent):
class QuantumInstaller(comp.InstallComponent):
def __init__(self, *args, **kargs):
Component.InstallComponent.__init__(self)
comp.InstallComponent.__init__(self)
def download(self):
pass
@@ -52,9 +53,9 @@ class QuantumInstaller(Component.InstallComponent):
pass
class QuantumRuntime(Component.RuntimeComponent):
class QuantumRuntime(comp.RuntimeComponent):
def __init__(self, *args, **kargs):
Component.RuntimeComponent.__init__(self)
comp.RuntimeComponent.__init__(self)
def start(self):
pass

View File

@@ -16,21 +16,16 @@
from tempfile import TemporaryFile
import Logger
import Packager
from devstack import component as comp
from devstack import constants
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
from devstack import trace as tr
from devstack import utils
#TODO fix these
from Component import (ComponentBase, RuntimeComponent,
PkgUninstallComponent, PkgInstallComponent)
from Exceptions import (StartException, StopException,
StatusException, RestartException)
from Util import (RABBIT, UBUNTU11)
from Trace import (TraceReader,
IN_TRACE)
from Shell import (execute)
LOG = Logger.getLogger("install.rabbit")
TYPE = RABBIT
LOG = logging.getLogger("devstack.components.rabbit")
TYPE = constants.RABBIT
#hopefully these are distro independent..
START_CMD = ['service', "rabbitmq-server", "start"]
@@ -40,38 +35,38 @@ RESTART_CMD = ['service', "rabbitmq-server", "restart"]
PWD_CMD = ['rabbitmqctl', 'change_password', 'guest']
class RabbitUninstaller(PkgUninstallComponent):
class RabbitUninstaller(comp.PkgUninstallComponent):
def __init__(self, *args, **kargs):
PkgUninstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PkgUninstallComponent.__init__(self, TYPE, *args, **kargs)
class RabbitInstaller(PkgInstallComponent):
class RabbitInstaller(comp.PkgInstallComponent):
def __init__(self, *args, **kargs):
PkgInstallComponent.__init__(self, TYPE, *args, **kargs)
comp.PkgInstallComponent.__init__(self, TYPE, *args, **kargs)
self.runtime = RabbitRuntime(*args, **kargs)
def _setup_pw(self):
passwd = self.cfg.getpw("passwords", "rabbit")
cmd = PWD_CMD + [passwd]
execute(*cmd, run_as_root=True)
sh.execute(*cmd, run_as_root=True)
def post_install(self):
parent_result = PkgInstallComponent.post_install(self)
parent_result = comp.PkgInstallComponent.post_install(self)
self._setup_pw()
self.runtime.restart()
return parent_result
class RabbitRuntime(ComponentBase, RuntimeComponent):
class RabbitRuntime(comp.ComponentBase, comp.RuntimeComponent):
def __init__(self, *args, **kargs):
ComponentBase.__init__(self, TYPE, *args, **kargs)
self.tracereader = TraceReader(self.tracedir, IN_TRACE)
comp.ComponentBase.__init__(self, TYPE, *args, **kargs)
self.tracereader = tr.TraceReader(self.tracedir, tr.IN_TRACE)
def start(self):
pkgsinstalled = self.tracereader.packages_installed()
if(len(pkgsinstalled) == 0):
msg = "Can not start %s since it was not installed" % (TYPE)
raise StartException(msg)
raise excp.StartException(msg)
if(self.status().find('start') == -1):
self._run_cmd(START_CMD)
return None
@@ -80,23 +75,23 @@ class RabbitRuntime(ComponentBase, RuntimeComponent):
pkgsinstalled = self.tracereader.packages_installed()
if(len(pkgsinstalled) == 0):
msg = "Can not check the status of %s since it was not installed" % (TYPE)
raise StatusException(msg)
(sysout, stderr) = execute(*STATUS_CMD, run_as_root=True)
raise excp.StatusException(msg)
(sysout, stderr) = sh.execute(*STATUS_CMD, run_as_root=True)
return sysout.strip().lower()
def _run_cmd(self, cmd):
if(self.distro == UBUNTU11):
if(self.distro == constants.UBUNTU11):
with TemporaryFile() as f:
execute(*cmd, run_as_root=True,
sh.execute(*cmd, run_as_root=True,
stdout_fh=f, stderr_fh=f)
else:
execute(*cmd, run_as_root=True)
sh.execute(*cmd, run_as_root=True)
def restart(self):
pkgsinstalled = self.tracereader.packages_installed()
if(len(pkgsinstalled) == 0):
msg = "Can not check the status of %s since it was not installed" % (TYPE)
raise RestartException(msg)
raise excp.RestartException(msg)
self._run_cmd(RESTART_CMD)
return None
@@ -104,7 +99,7 @@ class RabbitRuntime(ComponentBase, RuntimeComponent):
pkgsinstalled = self.tracereader.packages_installed()
if(len(pkgsinstalled) == 0):
msg = "Can not stop %s since it was not installed" % (TYPE)
raise StopException(msg)
raise excp.StopException(msg)
if(self.status().find('stop') == -1):
self._run_cmd(STOP_CMD)
return None

View File

@@ -14,25 +14,25 @@
# under the License.
import Logger
from devstack import component as comp
from devstack import constants
from devstack import log as logging
from devstack import shell as sh
from devstack import utils
#TODO fix these
from Component import (ComponentBase, RuntimeComponent,
UninstallComponent, InstallComponent)
LOG = Logger.getLogger("install.swift")
LOG = logging.getLogger("devstack.components.swift")
class SwiftUninstaller(UninstallComponent):
class SwiftUninstaller(comp.UninstallComponent):
def __init__(self, *args, **kargs):
pass
class SwiftInstaller(InstallComponent):
class SwiftInstaller(comp.InstallComponent):
def __init__(self, *args, **kargs):
pass
class SwiftRuntime(RuntimeComponent):
class SwiftRuntime(comp.RuntimeComponent):
def __init__(self, *args, **kargs):
pass

203
devstack/constants.py Normal file
View File

@@ -0,0 +1,203 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.path
import re
# These also have meaning outside python,
# ie in the pkg/pip listings so update there also!
UBUNTU11 = "ubuntu-oneiric"
RHEL6 = "rhel-6"
# What this program is called
PROG_NICE_NAME = "DEVSTACK"
# These 2 identify the json post and pre install sections
PRE_INSTALL = 'pre-install'
POST_INSTALL = 'post-install'
# Default interfaces for network ip detection
IPV4 = 'IPv4'
IPV6 = 'IPv6'
DEFAULT_NET_INTERFACE = 'eth0'
DEFAULT_NET_INTERFACE_IP_VERSION = IPV4
# Component name mappings
NOVA = "nova"
NOVA_CLIENT = 'nova-client'
GLANCE = "glance"
QUANTUM = "quantum"
SWIFT = "swift"
HORIZON = "horizon"
KEYSTONE = "keystone"
KEYSTONE_CLIENT = 'keystone-client'
DB = "db"
RABBIT = "rabbit"
OPENSTACK_X = 'openstack-x'
COMPONENT_NAMES = [
NOVA, NOVA_CLIENT,
GLANCE,
QUANTUM,
SWIFT,
HORIZON,
KEYSTONE, KEYSTONE_CLIENT,
OPENSTACK_X,
DB,
RABBIT,
]
# Ordering of install (lower priority means earlier)
COMPONENT_NAMES_PRIORITY = {
DB: 1,
RABBIT: 2,
KEYSTONE: 3,
GLANCE: 4,
QUANTUM: 4,
SWIFT: 4,
NOVA: 5,
KEYSTONE_CLIENT: 6,
NOVA_CLIENT: 6,
OPENSTACK_X: 6,
HORIZON: 10,
}
# When a component is asked for it may
# need another component, that dependency
# mapping is listed here
COMPONENT_DEPENDENCIES = {
DB: [],
KEYSTONE_CLIENT: [],
RABBIT: [],
GLANCE: [KEYSTONE, DB],
KEYSTONE: [DB],
NOVA: [KEYSTONE, GLANCE, DB, RABBIT],
SWIFT: [],
HORIZON: [KEYSTONE_CLIENT, GLANCE, NOVA_CLIENT, OPENSTACK_X],
QUANTUM: [],
}
# Default subdirs of a components root directory
COMPONENT_TRACE_DIR = "traces"
COMPONENT_APP_DIR = "app"
COMPONENT_CONFIG_DIR = "config"
# Program
# actions
INSTALL = "install"
UNINSTALL = "uninstall"
START = "start"
STOP = "stop"
ACTIONS = [INSTALL, UNINSTALL, START, STOP]
# This is used to map an action to a useful string for
# the welcome display
WELCOME_MAP = {
INSTALL: "Installer",
UNINSTALL: "Uninstaller",
START: "Runner",
STOP: "Stopper",
}
# Where we should get the config file and where stacks config
# directory is
STACK_CONFIG_DIR = "conf"
STACK_PKG_DIR = os.path.join(STACK_CONFIG_DIR, "pkgs")
STACK_PIP_DIR = os.path.join(STACK_CONFIG_DIR, "pips")
STACK_CONFIG_LOCATION = os.path.join(STACK_CONFIG_DIR, "stack.ini")
# These regex is how we match python platform output to a known constant
KNOWN_DISTROS = {
UBUNTU11: re.compile('Ubuntu(.*)oneiric', re.IGNORECASE),
RHEL6: re.compile('redhat-6\.(\d+)', re.IGNORECASE),
}
# The pip files that each component needs
PIP_MAP = {
NOVA:
[],
GLANCE:
[],
KEYSTONE:
[
os.path.join(STACK_PIP_DIR, 'keystone.json'),
],
HORIZON:
[
os.path.join(STACK_PIP_DIR, 'horizon.json'),
],
SWIFT:
[],
KEYSTONE_CLIENT:
[],
DB:
[],
RABBIT:
[],
QUANTUM:
[],
}
# The pkg files that each component needs
PKG_MAP = {
NOVA:
[
os.path.join(STACK_PKG_DIR, "general.json"),
os.path.join(STACK_PKG_DIR, "nova.json"),
],
QUANTUM:
[],
NOVA_CLIENT:
[
os.path.join(STACK_PKG_DIR, "general.json"),
os.path.join(STACK_PKG_DIR, "nova-client.json"),
],
GLANCE:
[
os.path.join(STACK_PKG_DIR, "general.json"),
os.path.join(STACK_PKG_DIR, 'glance.json'),
],
KEYSTONE:
[
os.path.join(STACK_PKG_DIR, "general.json"),
os.path.join(STACK_PKG_DIR, 'keystone.json'),
],
HORIZON:
[
os.path.join(STACK_PKG_DIR, "general.json"),
os.path.join(STACK_PKG_DIR, 'horizon.json'),
],
SWIFT:
[
os.path.join(STACK_PKG_DIR, "general.json"),
os.path.join(STACK_PKG_DIR, 'swift.json'),
],
KEYSTONE_CLIENT:
[
os.path.join(STACK_PKG_DIR, "keystone-client.json"),
],
DB:
[
os.path.join(STACK_PKG_DIR, 'db.json'),
],
RABBIT:
[
os.path.join(STACK_PKG_DIR, 'rabbitmq.json'),
],
OPENSTACK_X:
[
os.path.join(STACK_PKG_DIR, 'openstackx.json'),
],
}

19
devstack/date.py Normal file
View File

@@ -0,0 +1,19 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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 time import (localtime, strftime)
def rcf8222date():
return strftime("%a, %d %b %Y %H:%M:%S", localtime())

View File

@@ -17,25 +17,25 @@
from urlparse import urlparse
import re
#TODO fix these
from Shell import (execute, mkdirslist)
from Util import (MASTER_BRANCH)
from devstack import log as logging
from devstack import shell as sh
import Logger
LOG = Logger.getLogger("install.downloader")
LOG = logging.getLogger("devstack.downloader")
EXT_REG = re.compile(r"^(.*?)\.git\s*$", re.IGNORECASE)
# What the git master string is
GIT_MASTER_BRANCH = "master"
def _gitdownload(storewhere, uri, branch=None):
dirsmade = mkdirslist(storewhere)
dirsmade = sh.mkdirslist(storewhere)
LOG.info("Downloading from %s to %s" % (uri, storewhere))
cmd = ["git", "clone"] + [uri, storewhere]
execute(*cmd)
if(branch and branch != MASTER_BRANCH):
sh.execute(*cmd)
if(branch and branch != GIT_MASTER_BRANCH):
LOG.info("Adjusting git branch to %s" % (branch))
cmd = ['git', 'checkout'] + [branch]
execute(*cmd, cwd=storewhere)
sh.execute(*cmd, cwd=storewhere)
return dirsmade

View File

@@ -15,10 +15,10 @@
import os
import Logger
from devstack import log as logging
TRUE_VALUES = ['yes', 'true', 't', '1', 'on']
LOG = Logger.getLogger("install.environment")
LOG = logging.getLogger("devstack.environment")
def _str2bool(value_str):
@@ -27,13 +27,13 @@ def _str2bool(value_str):
return False
def get_environment():
def get():
return dict(os.environ)
def get_environment_key(key, default_value=None):
def get_key(key, default_value=None):
LOG.debug("Looking up environment variable \"%s\"" % (key))
value = get_environment().get(key)
value = get().get(key)
if(value == None):
LOG.debug("Could not find anything in environment variable \"%s\"" % (key))
value = default_value
@@ -42,8 +42,8 @@ def get_environment_key(key, default_value=None):
return value
def get_environment_bool(key, default_value=False):
value = get_environment_key(key, None)
def get_bool(key, default_value=False):
value = get_key(key, None)
if(value == None):
return default_value
return _str2bool(value)

View File

@@ -0,0 +1,14 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.

View File

@@ -75,8 +75,4 @@ def getLogger(name):
return logging.getLogger(name)
#this should happen first (and once)
INIT_LOGGING = False
if(not INIT_LOGGING):
setupLogging()
INIT_LOGGING = True

View File

@@ -14,18 +14,24 @@
# under the License.
from optparse import OptionParser
from optparse import IndentedHelpFormatter
import Util
from devstack import constants
from devstack import utils
from devstack import version
HELP_WIDTH = 80
def parse():
#version
version_str = "%prog v" + Util.VERSION_STR
parser = OptionParser(version=version_str)
version_str = "%prog v" + version.version_string()
help_formatter = IndentedHelpFormatter(width=HELP_WIDTH)
parser = OptionParser(version=version_str, formatter=help_formatter)
#non-boolean options
known_actions = sorted(Util.ACTIONS)
known_actions = sorted(constants.ACTIONS)
actions = "(" + ", ".join(known_actions) + ")"
parser.add_option("-a", "--action",
action="store",
@@ -42,7 +48,7 @@ def parse():
help="root DIR for new components or "\
"DIR with existing components (ACTION dependent)")
known_components = sorted(Util.COMPONENT_NAMES)
known_components = sorted(constants.COMPONENT_NAMES)
components = "(" + ", ".join(known_components) + ")"
parser.add_option("-c", "--component",
action="append",
@@ -84,5 +90,4 @@ def parse():
output['force'] = options.force
output['ignore_deps'] = options.ignore_deps
output['extras'] = args
return output

View File

@@ -13,20 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
from devstack import constants
from devstack import log as logging
from devstack import utils
"""
An abstraction that different packaging
frameworks (ie apt, yum) can inherit from
"""
import Logger
import Shell
#TODO fix these
from Util import (execute_template,
PRE_INSTALL, POST_INSTALL)
LOG = Logger.getLogger("install.packager")
LOG = logging.getLogger("devstack.packager")
class Packager():
@@ -43,16 +34,16 @@ class Packager():
pkgnames = sorted(pkgs.keys())
for name in pkgnames:
packageinfo = pkgs.get(name)
preinstallcmds = packageinfo.get(PRE_INSTALL)
preinstallcmds = packageinfo.get(constants.PRE_INSTALL)
if(preinstallcmds and len(preinstallcmds)):
LOG.info("Running pre-install commands for package %s." % (name))
execute_template(*preinstallcmds, params=installparams)
utils.execute_template(*preinstallcmds, params=installparams)
def post_install(self, pkgs, installparams=None):
pkgnames = sorted(pkgs.keys())
for name in pkgnames:
packageinfo = pkgs.get(name)
postinstallcmds = packageinfo.get(POST_INSTALL)
postinstallcmds = packageinfo.get(constants.POST_INSTALL)
if(postinstallcmds and len(postinstallcmds)):
LOG.info("Running post-install commands for package %s." % (name))
execute_template(*postinstallcmds, params=installparams)
utils.execute_template(*postinstallcmds, params=installparams)

View File

@@ -13,21 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
from tempfile import TemporaryFile
import os
import re
from tempfile import TemporaryFile
import time
import Packager
import Logger
from devstack import constants
from devstack import log as logging
from devstack import packager as pack
from devstack import shell as sh
from devstack import utils
#TODO fix these
from Util import (UBUNTU11, RHEL6)
from Util import param_replace
from Shell import execute
LOG = Logger.getLogger("install.package.apt")
LOG = logging.getLogger("devstack.packaging.apt")
#base apt commands
APT_GET = ['apt-get']
APT_PURGE = ["purge", "-y"]
APT_REMOVE = ["remove", "-y"]
@@ -44,21 +43,25 @@ ENV_ADDITIONS = {'DEBIAN_FRONTEND': 'noninteractive'}
VERSION_TEMPL = "%s=%s"
class AptPackager(Packager.Packager):
class AptPackager(pack.Packager):
def __init__(self, distro):
Packager.Packager.__init__(self, distro)
pack.Packager.__init__(self, distro)
def _form_cmd(self, name, version):
def _format_version(self, name, version):
return VERSION_TEMPL % (name, version)
def _format_pkg(self, name, version):
if(version and len(version)):
cmd = VERSION_TEMPL % (name, version)
cmd = self._format_version(name, version)
else:
cmd = name
return cmd
def _execute_apt(self, cmd, run_as_root, check_exit=True):
execute(*cmd, run_as_root=run_as_root,
check_exit_code=check_exit,
env_overrides=ENV_ADDITIONS)
def _execute_apt(self, cmd, **kargs):
sh.execute(*cmd, run_as_root=True,
check_exit_code=True,
env_overrides=ENV_ADDITIONS,
**kargs)
def remove_batch(self, pkgs):
pkgnames = sorted(pkgs.keys())
@@ -71,15 +74,14 @@ class AptPackager(Packager.Packager):
continue
if(self._pkg_remove_special(name, info)):
continue
full_cmd = self._form_cmd(name, info.get("version"))
if(full_cmd):
cmds.append(full_cmd)
pkg_full = self._format_pkg(name, info.get("version"))
cmds.append(pkg_full)
if(len(cmds)):
cmd = APT_GET + APT_DO_REMOVE + cmds
self._execute_apt(cmd, True)
self._execute_apt(cmd)
#clean them out
cmd = APT_GET + APT_AUTOREMOVE
self._execute_apt(cmd, True)
self._execute_apt(cmd)
def install_batch(self, pkgs):
pkgnames = sorted(pkgs.keys())
@@ -89,28 +91,26 @@ class AptPackager(Packager.Packager):
info = pkgs.get(name) or {}
if(self._pkg_install_special(name, info)):
continue
full_cmd = self._form_cmd(name, info.get("version"))
if(full_cmd):
cmds.append(full_cmd)
pkg_full = self._format_pkg(name, info.get("version"))
cmds.append(pkg_full)
#install them
if(len(cmds)):
cmd = APT_GET + APT_INSTALL + cmds
self._execute_apt(cmd, True)
self._execute_apt(cmd)
def _pkg_remove_special(self, name, pkginfo):
if(name == 'rabbitmq-server' and self.distro == UBUNTU11):
#https://bugs.launchpad.net/ubuntu/+source/rabbitmq-server/+bug/878597
#https://bugs.launchpad.net/ubuntu/+source/rabbitmq-server/+bug/878600
LOG.info("Handling special remove of %s" % (name))
full_cmd = self._form_cmd(name, pkginfo.get("version"))
if(full_cmd):
cmd = APT_GET + APT_REMOVE + [full_cmd]
self._execute_apt(cmd, True, True)
pkg_full = self._format_pkg(name, pkginfo.get("version"))
cmd = APT_GET + APT_REMOVE + [pkg_full]
self._execute_apt(cmd)
#probably useful to do this
time.sleep(1)
#purge
cmd = APT_GET + APT_PURGE + [full_cmd]
self._execute_apt(cmd, True)
cmd = APT_GET + APT_PURGE + [pkg_full]
self._execute_apt(cmd)
return True
return False
@@ -121,9 +121,8 @@ class AptPackager(Packager.Packager):
LOG.info("Handling special install of %s" % (name))
#this seems to be a temporary fix for that bug
with TemporaryFile() as f:
full_cmd = self._form_cmd(name, pkginfo.get("version"))
if(full_cmd):
cmd = APT_GET + APT_INSTALL + [full_cmd]
execute(*cmd, run_as_root=True, stdout_fh=f, stderr_fh=f, env_overrides=ENV_ADDITIONS)
pkg_full = self._format_pkg(name, pkginfo.get("version"))
cmd = APT_GET + APT_INSTALL + [pkg_full]
self._execute_apt(*cmd, stdout_fh=f, stderr_fh=f)
return True
return False

View File

@@ -13,46 +13,35 @@
# License for the specific language governing permissions and limitations
# under the License.
import Packager
import Logger
import Util
import Shell
from devstack import packager as pack
from devstack import shell as sh
from devstack import log as logging
#TODO fix these
from Shell import execute
from Util import param_replace
LOG = Logger.getLogger("install.package.yum")
LOG = logging.getLogger("devstack.packaging.yum")
YUM_CMD = ['yum']
YUM_INSTALL = ["install", "-y"]
class YumPackager(Packager.Packager):
class YumPackager(pack.Packager):
def __init__(self, distro):
Packager.Packager.__init__(self, distro)
pack.Packager.__init__(self, distro)
def _form_cmd(self, name, version):
def _format_pkg_name(self, name, version):
cmd = name
if(version and len(version)):
if(version != None and len(version)):
cmd = cmd + "-" + version
return cmd
def _do_cmd(self, base_cmd, pkgs):
pkgnames = pkgs.keys()
pkgnames.sort()
cmds = []
pkgnames = sorted(pkgs.keys())
cmds = list()
for name in pkgnames:
version = None
info = pkgs.get(name)
if(info):
version = info.get("version")
torun = self._form_cmd(name, version)
pkg_info = pkgs.get(name)
torun = self._format_pkg_name(name, pkg_info.get("version"))
cmds.append(torun)
if(len(cmds)):
cmd = YUM_CMD + base_cmd + cmds
LOG.debug("About to run:%s" % (cmd))
execute(*cmd, run_as_root=True)
sh.execute(*cmd, run_as_root=True)
def install_batch(self, pkgs):
LOG.info("install_batch called")
self._do_cmd(YUM_INSTALL, pkgs)

View File

@@ -13,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import Logger
#TODO fix these
from Shell import (execute)
from Exceptions import (ProcessExecutionError)
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
LOG = Logger.getLogger("install.pip")
LOG = logging.getLogger("devstack.pip")
INSTALL_CMD = ['pip', 'install']
UNINSTALL_CMD = ['pip', 'uninstall']
@@ -41,7 +40,7 @@ def install(pips):
if(len(actions)):
LOG.info("Installing python packages [%s]" % (", ".join(actions)))
cmd = INSTALL_CMD + actions
execute(*cmd, run_as_root=True)
sh.execute(*cmd, run_as_root=True)
def uninstall(pips):
@@ -55,10 +54,10 @@ def uninstall(pips):
skip_errors = pipinfo.get('skip_uninstall_errors', False)
try:
cmd = UNINSTALL_CMD + [name]
execute(*cmd, run_as_root=True)
except ProcessExecutionError, e:
sh.execute(*cmd, run_as_root=True)
except excp.ProcessExecutionError, e:
if(skip_errors):
LOG.warn("Ignoring execution error that occured when uninstalling %s" % (name))
LOG.warn("Ignoring execution error that occured when uninstalling %s!" % (name))
pass
else:
raise

View File

@@ -20,27 +20,23 @@ import signal
import errno
import time
import Runner
import Util
import Exceptions
import Trace
import Logger
import Shell
from devstack import exceptions as excp
from devstack import log as logging
from devstack import runner
from devstack import shell as sh
from devstack import trace as tr
from devstack import utils
#TODO fix these
from Exceptions import (StartException, StopException)
from Shell import (unlink, mkdir, joinpths, write_file,
load_file, isfile)
# Maximum for the number of available file descriptors (when not found)
MAXFD = 2048
MAX_KILL_TRY = 5
SLEEP_TIME = 1
LOG = Logger.getLogger("install.runners.foreground")
LOG = logging.getLogger("devstack.runners.foreground")
#trace constants
RUN = Runner.RUN_TYPE
RUN = runner.RUN_TYPE
RUN_TYPE = "FORK"
PID_FN = "PID_FN"
STDOUT_FN = "STDOUT_FN"
@@ -49,9 +45,9 @@ NAME = "NAME"
FORK_TEMPL = "%s.fork"
class ForegroundRunner(Runner.Runner):
class ForkRunner(runner.Runner):
def __init__(self):
Runner.Runner.__init__(self)
runner.Runner.__init__(self)
def _stop_pid(self, pid):
killed = False
@@ -76,7 +72,7 @@ class ForegroundRunner(Runner.Runner):
tracedir = kargs.get("trace_dir")
fn_name = FORK_TEMPL % (name)
(pidfile, stderr, stdout) = self._form_file_names(tracedir, fn_name)
tfname = Trace.trace_fn(tracedir, fn_name)
tfname = tr.trace_fn(tracedir, fn_name)
if(isfile(pidfile) and isfile(tfname)):
pid = int(load_file(pidfile).strip())
killed = self._stop_pid(pid)
@@ -158,8 +154,8 @@ class ForegroundRunner(Runner.Runner):
appdir = kargs.get("app_dir")
fn_name = FORK_TEMPL % (name)
(pidfile, stderrfn, stdoutfn) = self._form_file_names(tracedir, fn_name)
tracefn = Trace.touch_trace(tracedir, fn_name)
runtrace = Trace.Trace(tracefn)
tracefn = tr.touch_trace(tracedir, fn_name)
runtrace = tr.Trace(tracefn)
runtrace.trace(RUN, RUN_TYPE)
runtrace.trace(PID_FN, pidfile)
runtrace.trace(STDERR_FN, stderrfn)

View File

@@ -17,28 +17,27 @@ import time
import os
import re
import Runner
import Logger
from devstack import exceptions as excp
from devstack import log as logging
from devstack import runner
from devstack import shell as sh
from devstack import trace as tr
from devstack import utils
#TODO fix these
from Exceptions import (StartException, StopException)
from Util import (execute_template)
from Shell import (execute)
LOG = Logger.getLogger("install.screen")
LOG = logging.getLogger("install.screen")
SCREEN_MAKE = ['screen', '-d', '-m', '-S', '%NAME%', '-t', '%NAME%']
NAME_POSTFIX = ".devstack"
RUN_TYPE = "SCREEN"
class ScreenRunner(Runner.Runner):
class ScreenRunner(runner.Runner):
def __init__(self):
Runner.Runner.__init__(self)
runner.Runner.__init__(self)
def stop(self, name, *args, **kargs):
real_name = name + NAME_POSTFIX
list_cmd = ['screen', '-list']
(sysout, stderr) = execute(*list_cmd)
(sysout, stderr) = sh.execute(*list_cmd)
lines = sysout.splitlines()
entries = list()
lookfor = r"^(\d+\." + re.escape(real_name) + r")\s+(.*)$"
@@ -64,5 +63,5 @@ class ScreenRunner(Runner.Runner):
params['NAME'] = name + NAME_POSTFIX
runcmd = SCREEN_MAKE + [program] + list(args)
cmds = [{'cmd':runcmd}]
execute_template(*cmds, params=params, cwd=app_dir, **kargs)
utils.execute_template(*cmds, params=params, cwd=app_dir, **kargs)
return None

View File

@@ -22,16 +22,14 @@ import shutil
import subprocess
import sys
import Logger
#TODO fix these
from Exceptions import (ProcessExecutionError, FileException, BadParamException)
from Environment import (get_environment_bool, get_environment)
from devstack import log as logging
from devstack import exceptions as excp
from devstack import env
ROOT_HELPER = ["sudo"]
MKPW_CMD = ["openssl", 'rand', '-hex']
PASS_ASK_ENV = 'PASS_ASK'
LOG = Logger.getLogger("install.shell")
LOG = logging.getLogger("devstack.shell")
def execute(*cmd, **kwargs):
@@ -78,12 +76,13 @@ def execute(*cmd, **kwargs):
if('stdin_fh' in kwargs.keys()):
stdin_fh = kwargs.get('stdin_fh')
LOG.debug("Redirecting stdin to file handle: %s" % (stdin_fh))
process_input = None
if('stderr_fh' in kwargs.keys()):
stderr_fh = kwargs.get('stderr_fh')
LOG.debug("Redirecting stderr to file handle: %s" % (stderr_fh))
process_env = get_environment()
process_env = env.get()
LOG.debug("With environment: %s" % (process_env))
if(env_overrides and len(env_overrides)):
LOG.debug("With additional environment overrides: %s" % (env_overrides))
@@ -114,7 +113,7 @@ def execute(*cmd, **kwargs):
ecmd = cmd
if(not shell):
ecmd = ' '.join(cmd)
raise ProcessExecutionError(
raise excp.ProcessExecutionError(
exit_code=_returncode,
stdout=stdout,
stderr=stderr,
@@ -123,6 +122,10 @@ def execute(*cmd, **kwargs):
return result
def listdir(path):
return os.listdir(path)
def isfile(fn):
return os.path.isfile(fn)
@@ -138,7 +141,7 @@ def joinpths(*paths):
def _gen_password(pw_len):
if(pw_len <= 0):
msg = "Password length %s can not be less than or equal to zero" % (pw_len)
raise BadParamException(msg)
raise excp.BadParamException(msg)
LOG.debug("Generating you a pseudo-random password of byte length: %s" % (pw_len))
cmd = MKPW_CMD + [pw_len]
(stdout, stderr) = execute(*cmd)
@@ -154,7 +157,7 @@ def _prompt_password(prompt=None):
def password(prompt=None, pw_len=8):
rd = ""
ask_for_pw = get_environment_bool(PASS_ASK_ENV, True)
ask_for_pw = env.get_bool(PASS_ASK_ENV, True)
if(ask_for_pw):
rd = _prompt_password(prompt)
if(len(rd) == 0):
@@ -204,7 +207,7 @@ def touch_file(fn, die_if_there=True):
else:
if(die_if_there):
msg = "Can not touch file %s since it already exists" % (fn)
raise FileException(msg)
raise excp.FileException(msg)
def load_file(fn):
@@ -230,8 +233,30 @@ def deldir(path):
shutil.rmtree(path)
def prompt(prompt):
return raw_input(prompt)
def rmdir(path, quiet=True):
if(not isdir(path)):
return
try:
LOG.debug("Deleting directory \"%s\" with the cavet that we will fail if it's not empty." % (path))
os.rmdir(path)
LOG.debug("Deleted directory \"%s\"" % (path))
except OSError, e:
if(not quiet):
raise
else:
pass
def dirname(path):
return os.path.dirname(path)
def canon_path(path):
return os.path.realpath(path)
def prompt(prompt_str):
return raw_input(prompt_str)
def unlink(path, ignore_errors=True):

View File

@@ -14,15 +14,12 @@
# under the License.
import json
import os.path
#TODO fix these
from Exceptions import (NoTraceException)
from Util import (rcf8222date)
from Shell import (touch_file, append_file,
joinpths, load_file, mkdirslist,
isfile)
from devstack import exceptions as excp
from devstack import shell as sh
from devstack import date
#trace per line output and file extension formats
TRACE_FMT = "%s - %s\n"
TRACE_EXT = ".trace"
@@ -55,9 +52,9 @@ class Trace():
def trace(self, cmd, action=None):
if(action == None):
action = rcf8222date()
action = date.rcf8222date()
line = TRACE_FMT % (cmd, action)
append_file(self.tracefn, line)
sh.append_file(self.tracefn, line)
class TraceWriter():
@@ -71,7 +68,7 @@ class TraceWriter():
if(self.started):
return
else:
dirs = mkdirslist(self.root)
dirs = sh.mkdirslist(self.root)
self.fn = touch_trace(self.root, self.name)
self.tracer = Trace(self.fn)
self.tracer.trace(TRACE_VERSION, str(TRACE_VER))
@@ -227,12 +224,12 @@ class TraceReader():
def trace_fn(rootdir, name):
fullname = name + TRACE_EXT
return joinpths(rootdir, fullname)
return sh.joinpths(rootdir, fullname)
def touch_trace(rootdir, name):
tracefn = trace_fn(rootdir, name)
touch_file(tracefn)
sh.touch_file(tracefn)
return tracefn
@@ -248,16 +245,16 @@ def split_line(line):
def read(rootdir, name):
pth = trace_fn(rootdir, name)
contents = load_file(pth)
contents = sh.load_file(pth)
lines = contents.splitlines()
return lines
def parse_fn(fn):
if(not isfile(fn)):
if(not sh.isfile(fn)):
msg = "No trace found at filename %s" % (fn)
raise NoTraceException(msg)
contents = load_file(fn)
raise excp.NoTraceException(msg)
contents = sh.load_file(fn)
lines = contents.splitlines()
accum = list()
for line in lines:

View File

@@ -13,210 +13,30 @@
# License for the specific language governing permissions and limitations
# under the License.
from time import (localtime, strftime)
from termcolor import colored
import os
import platform
import re
import sys
import json
import netifaces
import operator
import os
import platform
import re
import string
import sys
import Exceptions
import Logger
import Shell
from termcolor import colored
#constant goodies
VERSION = 0x2
VERSION_STR = "%0.2f" % (VERSION)
DEVSTACK = 'DEVSTACK'
from devstack import constants
from devstack import exceptions as excp
from devstack import log as logging
from devstack import shell as sh
from devstack import version
#these also have meaning outside python
#ie in the pkg/pip listings so update there also!
UBUNTU11 = "ubuntu-oneiric"
RHEL6 = "rhel-6"
#GIT master
MASTER_BRANCH = "master"
#other constants
PRE_INSTALL = 'pre-install'
POST_INSTALL = 'post-install'
IPV4 = 'IPv4'
IPV6 = 'IPv6'
DEFAULT_NET_INTERFACE = 'eth0'
DEFAULT_NET_INTERFACE_IP_VERSION = IPV4
#this regex is used for parameter substitution
PARAM_SUB_REGEX = re.compile(r"%([\w\d]+?)%")
#component name mappings
NOVA = "nova"
NOVA_CLIENT = 'nova-client'
GLANCE = "glance"
QUANTUM = "quantum"
SWIFT = "swift"
HORIZON = "horizon"
KEYSTONE = "keystone"
KEYSTONE_CLIENT = 'keystone-client'
DB = "db"
RABBIT = "rabbit"
OPENSTACK_X = 'openstack-x'
COMPONENT_NAMES = [NOVA, NOVA_CLIENT,
GLANCE, QUANTUM,
SWIFT, HORIZON,
KEYSTONE, KEYSTONE_CLIENT,
OPENSTACK_X,
DB, RABBIT]
#ordering of install (lower priority means earlier)
NAMES_PRIORITY = {
DB: 1,
RABBIT: 2,
KEYSTONE: 3,
GLANCE: 4,
QUANTUM: 4,
SWIFT: 4,
NOVA: 5,
KEYSTONE_CLIENT: 6,
NOVA_CLIENT: 6,
OPENSTACK_X: 6,
HORIZON: 10,
}
#when a component is asked for it may
#need another component, that dependency
#map is listed here...
COMPONENT_DEPENDENCIES = {
DB: [],
KEYSTONE_CLIENT: [],
RABBIT: [],
GLANCE: [KEYSTONE, DB],
KEYSTONE: [DB],
NOVA: [KEYSTONE, GLANCE, DB, RABBIT],
SWIFT: [],
HORIZON: [KEYSTONE_CLIENT, GLANCE, NOVA_CLIENT, OPENSTACK_X],
QUANTUM: [],
}
#program
#actions
INSTALL = "install"
UNINSTALL = "uninstall"
START = "start"
STOP = "stop"
ACTIONS = [INSTALL, UNINSTALL, START, STOP]
#this is used to map an action to a useful string for
#the welcome display...
WELCOME_MAP = {
INSTALL: "Installer",
UNINSTALL: "Uninstaller",
START: "Runner",
STOP: "Stopper",
}
#where we should get the config file...
STACK_CONFIG_DIR = "conf"
STACK_CFG_LOC = Shell.joinpths(STACK_CONFIG_DIR, "stack.ini")
#default subdirs of a components dir (valid unless overriden)
TRACE_DIR = "traces"
APP_DIR = "app"
CONFIG_DIR = "config"
#this regex is how we match python platform output to
#a known constant
KNOWN_OS = {
UBUNTU11: re.compile('Ubuntu(.*)oneiric', re.IGNORECASE),
RHEL6: re.compile('redhat-6\.(\d+)', re.IGNORECASE),
}
#the pip files that each component
#needs
PIP_MAP = {
NOVA:
[],
GLANCE:
[],
KEYSTONE:
[
Shell.joinpths(STACK_CONFIG_DIR, "pips", 'keystone.json'),
],
HORIZON:
[
Shell.joinpths(STACK_CONFIG_DIR, "pips", 'horizon.json'),
],
SWIFT:
[],
KEYSTONE_CLIENT:
[],
DB:
[],
RABBIT:
[],
}
#the pkg files that each component
#needs
PKG_MAP = {
NOVA:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "nova.json"),
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "general.json"),
],
NOVA_CLIENT:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "nova-client.json"),
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "general.json"),
],
GLANCE:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "general.json"),
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'glance.json'),
],
KEYSTONE:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "general.json"),
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'keystone.json'),
],
HORIZON:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "general.json"),
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'horizon.json'),
],
SWIFT:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "general.json"),
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'swift.json'),
],
KEYSTONE_CLIENT:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", "keystone-client.json"),
],
DB:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'db.json'),
],
RABBIT:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'rabbitmq.json'),
],
OPENSTACK_X:
[
Shell.joinpths(STACK_CONFIG_DIR, "pkgs", 'openstackx.json'),
],
}
LOG = Logger.getLogger("install.util")
LOG = logging.getLogger("devstack.util")
def get_dependencies(component):
deps = COMPONENT_DEPENDENCIES.get(component)
if(deps == None):
return list()
return list(deps)
deps = constants.COMPONENT_DEPENDENCIES.get(component, list())
return sorted(deps)
def resolve_dependencies(components):
@@ -255,7 +75,7 @@ def execute_template(*cmds, **kargs):
stdin_full.append(piece)
stdin = joinlinesep(*stdin_full)
root_run = cmdinfo.get('run_as_root', False)
Shell.execute(*cmd_to_run, run_as_root=root_run, process_input=stdin, **kargs)
sh.execute(*cmd_to_run, run_as_root=root_run, process_input=stdin, **kargs)
def fetch_dependencies(component, add=False):
@@ -273,8 +93,9 @@ def fetch_dependencies(component, add=False):
def prioritize_components(components):
#get the right component order (by priority)
mporder = dict()
priorities = constants.COMPONENT_NAMES_PRIORITY
for c in components:
priority = NAMES_PRIORITY.get(c)
priority = priorities.get(c)
if(priority == None):
priority = sys.maxint
mporder[c] = priority
@@ -286,15 +107,15 @@ def prioritize_components(components):
def component_paths(root, component_name):
component_root = Shell.joinpths(root, component_name)
tracedir = Shell.joinpths(component_root, TRACE_DIR)
appdir = Shell.joinpths(component_root, APP_DIR)
cfgdir = Shell.joinpths(component_root, CONFIG_DIR)
component_root = sh.joinpths(root, component_name)
tracedir = sh.joinpths(component_root, constants.COMPONENT_TRACE_DIR)
appdir = sh.joinpths(component_root, constants.COMPONENT_APP_DIR)
cfgdir = sh.joinpths(component_root, constants.COMPONENT_CONFIG_DIR)
return (component_root, tracedir, appdir, cfgdir)
def load_json(fn):
data = Shell.load_file(fn)
data = sh.load_file(fn)
lines = data.splitlines()
new_lines = list()
for line in lines:
@@ -313,14 +134,14 @@ def get_host_ip(cfg=None):
ip = cfg_ip
if(ip == None):
interfaces = get_interfaces()
def_info = interfaces.get(DEFAULT_NET_INTERFACE)
def_info = interfaces.get(constants.DEFAULT_NET_INTERFACE)
if(def_info):
ipinfo = def_info.get(DEFAULT_NET_INTERFACE_IP_VERSION)
ipinfo = def_info.get(constants.DEFAULT_NET_INTERFACE_IP_VERSION)
if(ipinfo):
ip = ipinfo.get('addr')
if(ip == None):
msg = "Your host does not have an ip address!"
raise Exceptions.NoIpException(msg)
raise excp.NoIpException(msg)
LOG.debug("Determined host ip to be: \"%s\"" % (ip))
return ip
@@ -333,20 +154,25 @@ def get_interfaces():
ip6 = interface_addresses.get(netifaces.AF_INET6)
if(ip6 and len(ip6)):
#just take the first
interface_info[IPV6] = ip6[0]
interface_info[constants.IPV6] = ip6[0]
ip4 = interface_addresses.get(netifaces.AF_INET)
if(ip4 and len(ip4)):
#just take the first
interface_info[IPV4] = ip4[0]
interface_info[constants.IPV4] = ip4[0]
#there are others but this is good for now
interfaces[intfc] = interface_info
return interfaces
def determine_os():
found_os = None
def determine_distro():
plt = platform.platform()
for (known_os, pattern) in KNOWN_OS.items():
#ensure its a linux distro
(distname, version, id) = platform.linux_distribution()
if(not distname):
return (None, plt)
#attempt to match it to our platforms
found_os = None
for (known_os, pattern) in constants.KNOWN_DISTROS.items():
if(pattern.search(plt)):
found_os = known_os
break
@@ -356,7 +182,7 @@ def determine_os():
def get_pip_list(distro, component):
LOG.info("Getting pip packages for distro %s and component %s." % (distro, component))
all_pkgs = dict()
fns = PIP_MAP.get(component)
fns = constants.PIP_MAP.get(component)
if(fns == None):
return all_pkgs
#load + merge them
@@ -375,7 +201,7 @@ def get_pip_list(distro, component):
def get_pkg_list(distro, component):
LOG.info("Getting packages for distro %s and component %s." % (distro, component))
all_pkgs = dict()
fns = PKG_MAP.get(component)
fns = constants.PKG_MAP.get(component)
if(fns == None):
return all_pkgs
#load + merge them
@@ -391,7 +217,7 @@ def get_pkg_list(distro, component):
for (infokey, infovalue) in pkginfo.items():
#this is expected to be a list of cmd actions
#so merge that accordingly
if(infokey == PRE_INSTALL or infokey == POST_INSTALL):
if(infokey == constants.PRE_INSTALL or infokey == constants.POST_INSTALL):
oldinstalllist = oldpkginfo.get(infokey) or []
infovalue = oldinstalllist + infovalue
newpkginfo[infokey] = infovalue
@@ -427,7 +253,7 @@ def param_replace(text, replacements, ignore_missing=False):
v = org
elif(v == None and not ignore_missing):
msg = "No replacement found for parameter %s" % (org)
raise Exceptions.NoReplacementException(msg)
raise excp.NoReplacementException(msg)
else:
LOG.debug("Replacing [%s] with [%s]" % (org, str(v)))
return str(v)
@@ -435,9 +261,11 @@ def param_replace(text, replacements, ignore_missing=False):
return PARAM_SUB_REGEX.sub(replacer, text)
def welcome(program_action):
formatted_action = WELCOME_MAP.get(program_action)
lower = "!%s v%s!" % (formatted_action.upper(), VERSION)
formatted_action = constants.WELCOME_MAP.get(program_action, "")
ver_str = version.version_string()
lower = "!%s %s!" % (formatted_action.upper(), ver_str)
welcome = r'''
___ ____ _____ _ _ ____ _____ _ ____ _ __
/ _ \| _ \| ____| \ | / ___|_ _|/ \ / ___| |/ /
@@ -446,15 +274,15 @@ def welcome(program_action):
\___/|_| |_____|_| \_|____/ |_/_/ \_\____|_|\_\
'''
#this seems needed, weird...
welcome = " " + welcome.strip()
lower_out = (" " * 17) + colored(DEVSTACK, 'green') + ": " + colored(lower, 'blue')
max_len = 0
for line in welcome.splitlines():
if(len(line) > max_len):
max_len = len(line)
lower_out = colored(constants.PROG_NICE_NAME, 'green') + \
": " + colored(lower, 'blue')
center_len = (max_len + max_len/3)
lower_out = string.center(lower_out, center_len)
msg = welcome + os.linesep + lower_out
print(msg)
def rcf8222date():
return strftime("%a, %d %b %Y %H:%M:%S", localtime())
def fs_safe_date():
return strftime("%m_%d_%G-%H-%M-%S", localtime())

38
devstack/version.py Normal file
View File

@@ -0,0 +1,38 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# 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.
DEVSTACK = 'DEVSTACK'
DEVSTACK_VERSION = ['2012', '1']
YEAR, COUNT = DEVSTACK_VERSION
FINAL = False # May never be final ;-)
def canonical_version_string():
return '.'.join([YEAR, COUNT])
def version_string():
if FINAL:
return canonical_version_string()
else:
return '%s-dev' % (canonical_version_string(),)
def vcs_version_string():
return 'LOCALBRANCH:LOCALREVISION'
def version_string_with_vcs():
return '%s-%s' % (canonical_version_string(), vcs_version_string())

255
stack
View File

@@ -15,123 +15,38 @@
import os
import os.path
import sys
import re
import sys
#TODO is this needed?
sys.path.append("devstack")
# This needs to happen immediately
from devstack import log as logging
logging.setupLogging()
import Logger
import Options
from devstack import actions
from devstack import cfg
from devstack import constants
from devstack import date
from devstack import exceptions as excp
from devstack import opts
from devstack import shell as sh
from devstack import utils
from devstack.packaging import apt
from devstack.packaging import yum
#TODO fix these
from Util import (welcome, rcf8222date, determine_os,
prioritize_components, resolve_dependencies,
get_dependencies)
from Util import (NOVA, GLANCE, QUANTUM, SWIFT, KEYSTONE,
HORIZON, DB, RABBIT, KEYSTONE_CLIENT,
NOVA_CLIENT, OPENSTACK_X)
from Util import(INSTALL, UNINSTALL, START, STOP,
ACTIONS, COMPONENT_NAMES, NAMES_PRIORITY,
UBUNTU11, RHEL6,
STACK_CFG_LOC, DEVSTACK)
from Shell import (mkdir, joinpths, unlink)
from Exceptions import (NoTraceException)
LOG = logging.getLogger("devstack")
import Glance
import Horizon
import Keystone
import Nova
import Quantum
import Config
import Swift
import Db
import Rabbit
import Config
import KeystoneClient
import NovaClient
import OpenstackX
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,
NOVA_CLIENT: NovaClient.NovaClientInstaller,
OPENSTACK_X: OpenstackX.OpenstackXInstaller,
},
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,
NOVA_CLIENT: NovaClient.NovaClientUninstaller,
OPENSTACK_X: OpenstackX.OpenstackXUninstaller,
},
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,
NOVA_CLIENT: NovaClient.NovaClientRuntime,
OPENSTACK_X: OpenstackX.OpenstackXRuntime,
},
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,
NOVA_CLIENT: NovaClient.NovaClientRuntime,
OPENSTACK_X: OpenstackX.OpenstackXRuntime,
},
PKGR_MAP = {
constants.UBUNTU11: apt.AptPackager,
constants.RHEL6: yum.YumPackager,
}
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 get_config():
cfg_fn = sh.canon_path(constants.STACK_CONFIG_LOCATION)
LOG.info("Loading config from [%s]" % (cfg_fn))
config_instance = cfg.EnvConfigParser()
config_instance.read(cfg_fn)
return config_instance
def print_cfgs(cfg, action):
@@ -170,24 +85,34 @@ def print_cfgs(cfg, action):
map_print(db_dsns)
def runner(action_name, component_order, components_info, 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)
def pre_run_components(action_name, **kargs):
if(action_name == constants.INSTALL):
root_dir = kargs.get("root_dir")
if(root_dir):
sh.mkdir(root_dir)
def post_run_components(action_name, **kargs):
if(action_name == constants.UNINSTALL):
root_dir = kargs.get("root_dir")
if(root_dir):
sh.rmdir(root_dir)
def run_components(action_name, component_order, components_info, distro, root_dir, program_args):
pkg_manager = PKGR_MAP.get(distro)(distro)
config = get_config()
pre_run_components(action_name, root_dir=root_dir, pkg=pkg_manager, cfg=config)
LOG.info("Will %s [%s] (in that order) using root directory \"%s\"" % (action_name, ", ".join(component_order), root_dir))
results = list()
class_lookup = ACTION_CLASSES.get(action_name)
force = program_args.get('force', False)
for c in component_order:
klass = actions.get_action_cls(action_name, c)
component_info = components_info.get(c) or list()
klass = class_lookup.get(c)
instance = klass(components=set(component_order), distro=distro,
pkg=pkg_manager, cfg=config, root=root_dir,
component_info=component_info)
if(action_name == INSTALL):
if(action_name == constants.INSTALL):
LOG.info("Downloading %s." % (c))
am_downloaded = instance.download()
LOG.info("Performed %s downloads." % (str(am_downloaded)))
@@ -205,7 +130,7 @@ def runner(action_name, component_order, components_info, distro, root_dir, prog
results.append(trace)
else:
LOG.info("Finished install of %s" % (c))
elif(action_name == STOP):
elif(action_name == constants.STOP):
try:
LOG.info("Stopping %s." % (c))
stop_am = instance.stop()
@@ -216,7 +141,7 @@ def runner(action_name, component_order, components_info, distro, root_dir, prog
LOG.info("Passing on stopping %s since no trace file was found." % (c))
else:
raise
elif(action_name == START):
elif(action_name == constants.START):
LOG.info("Starting %s." % (c))
start_info = instance.start()
if(type(start_info) == list):
@@ -225,45 +150,34 @@ def runner(action_name, component_order, components_info, distro, root_dir, prog
elif(type(start_info) == int):
LOG.info("Started %s applications." % (str(start_info)))
LOG.info("Finished start of %s." % (c))
elif(action_name == UNINSTALL):
elif(action_name == constants.UNINSTALL):
try:
LOG.info("Unconfiguring %s." % (c))
instance.unconfigure()
LOG.info("Uninstalling %s." % (c))
instance.uninstall()
except NoTraceException, e:
except excp.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
#any post run actions go now
post_run_components(action_name, root_dir=root_dir)
return results
def check_root(action, rootdir):
if(rootdir == None or len(rootdir) == 0):
return False
if(action == INSTALL):
root_there = False
if(os.path.isdir(rootdir)):
sublisting = os.listdir(rootdir)
if(action == constants.INSTALL):
if(sh.isdir(rootdir)):
sublisting = sh.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
@@ -271,16 +185,16 @@ def parse_action(action):
if(action == None):
return None
action = action.strip().lower()
if(not (action in ACTIONS)):
if(not (action in constants.ACTIONS)):
return None
return action
def parse_components(components, assume_all=False):
#none provided
#none provided, init it
if(components == None):
components = list()
#
#this regex is used to extract a components options (if any) and its name
EXT_COMPONENT = re.compile(r"^\s*([\w-]+)(?:\((.*)\))?\s*$")
adjusted_components = dict()
for c in components:
@@ -288,8 +202,9 @@ def parse_components(components, assume_all=False):
if(mtch):
component_name = mtch.group(1)
component_name = component_name.lower().strip()
if(component_name not in COMPONENT_NAMES):
continue
if(component_name not in constants.COMPONENT_NAMES):
LOG.warn("Unknown component named %s" % (c))
else:
component_opts = mtch.group(2)
components_opts_cleaned = list()
if(component_opts == None or len(component_opts) == 0):
@@ -301,11 +216,13 @@ def parse_components(components, assume_all=False):
if(len(cleaned_opt)):
components_opts_cleaned.append(cleaned_opt)
adjusted_components[component_name] = components_opts_cleaned
#should we adjust them??
else:
LOG.warn("Unparseable component %s" % (c))
#should we adjust them to be all the components?
if(len(adjusted_components) == 0):
all_components = dict()
if(assume_all):
for c in (COMPONENT_NAMES):
for c in constants.COMPONENT_NAMES:
all_components[c] = list()
adjusted_components = all_components
return adjusted_components
@@ -316,6 +233,7 @@ def check_python():
major = py_version[0]
minor = py_version[1]
if(major < 2 or (major == 2 and minor < 6)):
LOG.error("Your python version is to old, please upgrade to >= 2.6!")
return False
if(major >= 3):
LOG.warn("%s has not been tested in python %s, use at your own risk!" % (DEVSTACK, major))
@@ -330,17 +248,17 @@ def run_list_only(prog, args):
left_show = list(components)
while(len(left_show) != 0):
c = left_show.pop()
deps = get_dependencies(c)
cname = ""
if(len(deps) >= 1):
cname = "component"
if(cname > 1):
cname += "s"
cname += ":"
if(len(deps) == 0):
cname = "no components."
LOG.info("%s depends on %s" % (c, cname))
if(len(deps)):
deps = utils.get_dependencies(c)
dep_str = ""
dep_len = len(deps)
if(dep_len >= 1):
dep_str = "component"
if(dep_len > 1):
dep_str += "s"
dep_str += ":"
elif(dep_len == 0):
dep_str = "no components."
LOG.info("%s depends on %s" % (c, dep_str))
for d in deps:
LOG.info("\t%s" % (d))
shown.add(c)
@@ -369,27 +287,26 @@ def run_action(prog, args):
LOG.info("Perhaps you should try %s --help" % (prog))
return False
#ensure os/distro is known
(install_os, plt) = determine_os()
if(install_os == None):
LOG.error("Unsupported operating system/distro: %s" % (plt))
(distro, platform) = utils.determine_distro()
if(distro == None):
LOG.error("Unsupported platform: %s" % (platform))
return False
#start it
welcome(action)
utils.welcome(action)
#need to figure out dependencies for components (if any)
if(not ignore_deps):
new_components = resolve_dependencies(components.keys())
new_components = utils.resolve_dependencies(components.keys())
component_diff = new_components.difference(components.keys())
if(len(component_diff)):
LOG.info("Having to activate dependent components: [%s]" % (", ".join(component_diff)))
#TBD - probably need to do this better
for new_component in component_diff:
components[new_component] = list()
#get the right component order (by priority)
component_order = prioritize_components(components.keys())
component_order = utils.prioritize_components(components.keys())
#now do it!
LOG.info("Starting action [%s] on %s for operating system/distro [%s]" % (action, rcf8222date(), install_os))
resultList = runner(action, component_order, components, install_os, rootdir, args)
LOG.info("Finished action [%s] on %s" % (action, rcf8222date()))
LOG.info("Starting action [%s] on %s for distro [%s]" % (action, date.rcf8222date(), distro))
resultList = run_components(action, component_order, components, distro, rootdir, args)
LOG.info("Finished action [%s] on %s" % (action, date.rcf8222date()))
if(resultList and len(resultList)):
msg = "Check [%s] for traces of what happened." % (", ".join(resultList))
LOG.info(msg)
@@ -398,13 +315,13 @@ def run_action(prog, args):
def main():
if(not check_python()):
LOG.error("Your python version is to old, please upgrade to >= 2.6!")
return 1
#parse and get it done!
args = Options.parse()
args = opts.parse()
me = os.path.basename(sys.argv[0])
#figure out what to do
only_list_deps = args.pop('list_deps', False)
#now do it
rc_ok = False
if(only_list_deps):
rc_ok = run_list_only(me, args)