Updates for rhel6 work.

This commit is contained in:
Joshua Harlow 2012-01-31 16:07:40 -08:00
parent 92a7327574
commit 1df3eae3fa
18 changed files with 378 additions and 156 deletions

15
conf/pips/glance.json Normal file
View File

@ -0,0 +1,15 @@
# This is a extended json package definition file
# We allow simple comments (lines starting with a hash symbol)
{
"ubuntu-oneiric": {
},
"rhel-6": {
"SQLAlchemy": {
"version": "0.7.5"
},
#the base is 2.0, need to upgrade
"pycrypto": {
"version": "2.3"
}
}
}

View File

@ -3,15 +3,16 @@
{ {
"ubuntu-oneiric": { "ubuntu-oneiric": {
"django-nose-selenium": { "django-nose-selenium": {
"version": "0.7.3", "version": "0.7.3"
#this seems broke on uninstall so skip errors on uinstall
"skip_uninstall_errors": true
}, },
"pycrypto": { "pycrypto": {
"version": "2.3", "version": "2.3"
#this seems broke on uninstall so skip errors on uinstall
"skip_uninstall_errors": true
} }
}, },
"rhel-6": {} "rhel-6": {
#the base is 2.0, need to upgrade
"pycrypto": {
"version": "2.3"
}
}
} }

View File

@ -3,10 +3,19 @@
{ {
"ubuntu-oneiric": { "ubuntu-oneiric": {
"passlib": { "passlib": {
"version": "1.5.3", "version": "1.5.3"
#this seems broke on uninstall so skip errors on uinstall
"skip_uninstall_errors": true
} }
}, },
"rhel-6": {} "rhel-6": {
"SQLAlchemy": {
"version": "0.7.5"
},
"sqlalchemy-migrate": {
"version": "0.7.2"
},
#the base is 2.0, need to upgrade
"pycrypto": {
"version": "2.3"
}
}
} }

View File

@ -22,7 +22,7 @@
"removable": true, "removable": true,
"pre-install": [ "pre-install": [
{ {
# This apparently is a action needed for ubuntu/debian to not prompt for passwords... # This apparently is a action needed for ubuntu/debian to set the password to something known....
"run_as_root": true, "run_as_root": true,
"cmd": [ "cmd": [
"debconf-set-selections" "debconf-set-selections"

View File

@ -196,14 +196,19 @@
"version": "0.6.10*", "version": "0.6.10*",
"removable": false "removable": false
}, },
# Requires EPEL
"python-distutils-extra": {
"version": "2.29*",
"removable": false
},
"python-dev": { "python-dev": {
"version": "2.6*", "version": "2.6*",
"removable": false "removable": false
}, },
# For testing # For testing
"python-nose": { # Requires EPEL
# This version seems way old "python-nose1.1": {
"version": "0.10*", "version": "1.1*",
"removable": true "removable": true
}, },
# For testing # For testing

View File

@ -21,6 +21,10 @@
"version": "1.1*", "version": "1.1*",
"removable": true "removable": true
}, },
"python-prettytable": {
"version": "0.5*",
"removable": true
},
"python-mysqldb": { "python-mysqldb": {
"version": "1.2*", "version": "1.2*",
"removable": true "removable": true
@ -37,12 +41,64 @@
"version": "0.6*", "version": "0.6*",
"removable": true "removable": true
}, },
"python-dateutil": {
"version": "1.4*",
"removable": true
},
"python-httplib2": { "python-httplib2": {
"version": "0.7.1*", "version": "0.7.1*",
"removable": true "removable": true
} }
}, },
"rhel-6": { "rhel-6": {
# TBD # Requires EPEL
"python-eventlet": {
"version": "0.9*",
"removable": true
},
"python-routes": {
"version": "1.10*",
"removable": true
},
# Requires EPEL
"python-greenlet": {
"version": "0.3.1*",
"removable": true
},
# Requires EPEL
"python-argparse": {
"version": "1.2*",
"removable": true
},
"MySQL-python": {
"version": "1.2*",
"removable": true
},
"python-dateutil": {
"version": "1.4*",
"removable": true
},
"python-pastedeploy": {
# This might be way to old :(
"version": "1.3.3*",
"removable": true
},
# Requires EPEL
"python-prettytable": {
"version": "0.5*",
"removable": true
},
# Requires EPEL
"python-xattr": {
# This might be way to old :(
"version": "0.5*",
"removable": true
},
# Requires EPEL
"python-httplib2": {
# This might be way to old :(
"version": "0.4*",
"removable": true
}
} }
} }

View File

@ -55,12 +55,14 @@
}, },
"python-greenlet": { "python-greenlet": {
"version": "0.3*", "version": "0.3*",
"allowed": ">=", "removable": true
},
"python-argparse": {
"version": "1.1*",
"removable": true "removable": true
}, },
"python-routes": { "python-routes": {
"version": "1.12*", "version": "1.12*",
"allowed": ">=",
"removable": true "removable": true
}, },
"libldap2-dev": { "libldap2-dev": {
@ -71,13 +73,89 @@
"libsasl2-dev": { "libsasl2-dev": {
"version": "2.1*", "version": "2.1*",
"removable": true "removable": true
},
"python-migrate": {
"version": "0.7*",
"removable": true
} }
}, },
"rhel-6": { "rhel-6": {
# TBD # Requires EPEL
"python-eventlet": {
"version": "0.9*",
"removable": true
},
"python-lxml": {
# Trashes IPA client, which is probably bad
"version": "2.2*",
"removable": true
},
"python-pastescript": {
"version": "1.7*",
"removable": true
},
# Requires EPEL
"python-prettytable": {
"version": "0.5*",
"removable": true
},
"MySQL-python": {
"version": "1.2*",
"removable": true
},
"python-paste-deploy": {
# This might be way to old :(
"version": "1.3.3*",
"removable": true
},
"python-paste": {
"version": "1.7.4*",
"removable": true
},
"sqlite": {
"version": "3.6*",
# Trashes alot of the base os (so we don't allow it to be removed)
"removable": false
},
# Requires EPEL
"python-sqlite2": {
# This might be way to old :(
"version": "2.3*",
"removable": true
},
# Requires EPEL
"python-webob1.0": {
"version": "1.0*",
"removable": true
},
# Requires EPEL
"python-argparse": {
"version": "1.2*",
"removable": true
},
# Requires EPEL
"python-greenlet": {
"version": "0.3.1*",
"removable": true
},
"python-routes": {
"version": "1.10*",
"removable": true
},
# Requires EPEL
"python-passlib": {
"version": "1.5*",
"removable": true
},
# Is this right??
# This is for libldap2
"openldap": {
# Trashes alot of the base os (so we don't allow it to be removed)
"removable": false,
"version": "2.4*"
},
# Is this right??
# This is for libsasl2
"cyrus-sasl-lib": {
# Trashes alot of the base os (so we don't allow it to be removed)
"version": "2.1*",
"removable": false
}
} }
} }

View File

@ -181,7 +181,7 @@ class PythonInstallComponent(PkgInstallComponent):
pips = self._get_pips() pips = self._get_pips()
if pips: if pips:
LOG.info("Setting up %s pips (%s)" % (len(pips), ", ".join(pips.keys()))) LOG.info("Setting up %s pips (%s)" % (len(pips), ", ".join(pips.keys())))
pip.install(pips) pip.install(pips, self.distro)
for name in pips.keys(): for name in pips.keys():
self.tracewriter.pip_install(name, pips.get(name)) self.tracewriter.pip_install(name, pips.get(name))
@ -293,7 +293,7 @@ class PythonUninstallComponent(PkgUninstallComponent):
pips = self.tracereader.pips_installed() pips = self.tracereader.pips_installed()
if pips: if pips:
LOG.info("Uninstalling %s pips" % (len(pips))) LOG.info("Uninstalling %s pips" % (len(pips)))
pip.uninstall(pips) pip.uninstall(pips, self.distro)
def _uninstall_python(self): def _uninstall_python(self):
pylisting = self.tracereader.py_listing() pylisting = self.tracereader.py_listing()

View File

@ -22,6 +22,8 @@ from devstack import shell as sh
from devstack import trace as tr from devstack import trace as tr
from devstack import utils from devstack import utils
import time
LOG = logging.getLogger("devstack.components.db") LOG = logging.getLogger("devstack.components.db")
#id #id
@ -29,6 +31,7 @@ TYPE = settings.DB
#used for special setups #used for special setups
MYSQL = 'mysql' MYSQL = 'mysql'
START_WAIT_TIME = 10
DB_ACTIONS = { DB_ACTIONS = {
MYSQL: { MYSQL: {
# Of course these aren't distro independent... # Of course these aren't distro independent...
@ -37,37 +40,37 @@ DB_ACTIONS = {
'start': ["service", "mysql", 'start'], 'start': ["service", "mysql", 'start'],
'stop': ["service", 'mysql', "stop"], 'stop': ["service", 'mysql', "stop"],
'status': ["service", 'mysql', "status"], 'status': ["service", 'mysql', "status"],
'restart': ["service", 'mysql', "status"], 'restart': ["service", 'mysql', "restart"],
}, },
settings.RHEL6: { settings.RHEL6: {
'start': ["service", "mysqld", 'start'], 'start': ["service", "mysqld", 'start'],
'stop': ["service", 'mysqld', "stop"], 'stop': ["service", 'mysqld', "stop"],
'status': ["service", 'mysqld', "status"], 'status': ["service", 'mysqld', "status"],
'restart': ["service", 'mysqld', "status"], 'restart': ["service", 'mysqld', "restart"],
}, },
}, },
# #modification commands
'setpwd': ['mysqladmin', '--user=%USER%', 'password', '%NEW_PASSWORD%', 'set_pwd': ['mysql', '-u', '%USER%', '--password=%OLD_PASSWORD%', '-e', ("\"USE mysql; UPDATE user SET "
'--password=%PASSWORD%'], " password=PASSWORD('%NEW_PASSWORD%') WHERE User='%USER%'; FLUSH privileges;\"")],
'create_db': ['mysql', '--user=%USER%', '--password=%PASSWORD%', 'create_db': ['mysql', '--user=%USER%', '--password=%PASSWORD%',
'-e', 'CREATE DATABASE %DB%;'], '-e', 'CREATE DATABASE %DB%;'],
'drop_db': ['mysql', '--user=%USER%', '--password=%PASSWORD%', 'drop_db': ['mysql', '--user=%USER%', '--password=%PASSWORD%',
'-e', 'DROP DATABASE IF EXISTS %DB%;'], '-e', 'DROP DATABASE IF EXISTS %DB%;'],
'grant_all': [ 'grant_all': ["mysql", "--user=%USER%", "--password=%PASSWORD%",
"mysql", ("-e \"GRANT ALL PRIVILEGES ON *.* TO '%USER%'@'%' "
"--user=%USER%", "identified by '%PASSWORD%'; flush privileges;\"")],
"--password=%PASSWORD%",
("-e \"GRANT ALL PRIVILEGES ON *.* TO '%USER%'@'%' "
"identified by '%PASSWORD%';\""),
],
# we could do this in python directly, but executing allows us to
# not have to sudo the whole program
'host_adjust': ['perl', '-p', '-i', '-e', "'s/127.0.0.1/0.0.0.0/g'",
'/etc/mysql/my.cnf'],
}, },
} }
#annoying adjustments
RHEL_FIX_GRANTS = ['perl', '-p', '-i', '-e', "'s/^skip-grant-tables/#skip-grant-tables/g'", '/etc/my.cnf']
UBUNTU_HOST_ADJUST = ['perl', '-p', '-i', '-e', "'s/127.0.0.1/0.0.0.0/g'", '/etc/mysql/my.cnf']
#need to reset pw (this is the prompt)
RESET_PW = "Please enter your current mysql password for user \"%s\" so we can reset it for next time (blank allowed): "
RESET_BASE_PW = ''
#links about how to reset if it fails
SQL_RESET_PW_LINKS = ['https://help.ubuntu.com/community/MysqlPasswordReset', 'http://crashmag.net/resetting-the-root-password-for-mysql-running-on-rhel-or-centos'] SQL_RESET_PW_LINKS = ['https://help.ubuntu.com/community/MysqlPasswordReset', 'http://crashmag.net/resetting-the-root-password-for-mysql-running-on-rhel-or-centos']
#used as a generic error message #used as a generic error message
@ -88,38 +91,28 @@ class DBUninstaller(comp.PkgUninstallComponent):
def pre_uninstall(self): def pre_uninstall(self):
dbtype = self.cfg.get("db", "type") dbtype = self.cfg.get("db", "type")
dbactions = DB_ACTIONS.get(dbtype) dbactions = DB_ACTIONS.get(dbtype)
try:
self.runtime.start()
except IOError:
LOG.warn("Could not start your database.")
# set pwd
try: try:
if dbactions and dbtype == MYSQL: if dbactions and dbtype == MYSQL:
LOG.info(("Attempting to reset your mysql password so" LOG.info(("Attempting to reset your mysql password so"
" that we can set it the next time you install.")) " that we can set it the next time you install."))
pwd_cmd = dbactions.get('setpwd') pwd_cmd = dbactions.get('set_pwd')
if pwd_cmd: if pwd_cmd:
LOG.info("Ensuring your database is started before we operate on it.")
self.runtime.restart()
user = self.cfg.get("db", "sql_user")
pw_prompt = RESET_PW % (user)
old_pw = sh.prompt_password(pw_prompt)
params = { params = {
'PASSWORD': self.cfg.get("passwords", "sql"), 'OLD_PASSWORD': old_pw,
'USER': self.cfg.get("db", "sql_user"), 'NEW_PASSWORD': RESET_BASE_PW,
'NEW_PASSWORD': '' 'USER': user,
} }
cmds = [{ cmds = [{'cmd': pwd_cmd}]
'cmd': pwd_cmd, utils.execute_template(*cmds, params=params, shell=True)
'run_as_root': True,
}]
utils.execute_template(*cmds, params=params)
except IOError: except IOError:
LOG.warn(("Could not reset mysql password. You might have to manually " LOG.warn(("Could not reset the database password. You might have to manually "
"reset mysql before the next install")) "reset the password to \"%s\" before the next install") % (RESET_BASE_PW), exc_info=True)
LOG.info("To aid in this check out: %s", " or ".join(SQL_RESET_PW_LINKS)) LOG.info("To aid in this check out: [%s]", " or ".join(SQL_RESET_PW_LINKS))
try:
self.runtime.stop()
except IOError:
LOG.warn("Could not stop your database.")
class DBInstaller(comp.PkgInstallComponent): class DBInstaller(comp.PkgInstallComponent):
@ -140,6 +133,15 @@ class DBInstaller(comp.PkgInstallComponent):
} }
return out return out
def _configure_db_confs(self):
dbtype = self.cfg.get("db", "type")
if self.distro == settings.RHEL6 and dbtype == MYSQL:
LOG.info("Fixing up rhel 6 mysql configs")
sh.execute(*RHEL_FIX_GRANTS, run_as_root=True)
elif self.distro == settings.UBUNTU11 and dbtype == MYSQL:
LOG.info("Fixing up ubuntu 11 mysql configs")
sh.execute(*UBUNTU_HOST_ADJUST, run_as_root=True)
def _get_pkgs(self): def _get_pkgs(self):
pkgs = comp.PkgInstallComponent._get_pkgs(self) pkgs = comp.PkgInstallComponent._get_pkgs(self)
for fn in REQ_PKGS: for fn in REQ_PKGS:
@ -150,53 +152,53 @@ class DBInstaller(comp.PkgInstallComponent):
def post_install(self): def post_install(self):
parent_result = comp.PkgInstallComponent.post_install(self) parent_result = comp.PkgInstallComponent.post_install(self)
#fix up the db configs
self._configure_db_confs()
#extra actions to ensure we are granted access #extra actions to ensure we are granted access
dbtype = self.cfg.get("db", "type") dbtype = self.cfg.get("db", "type")
dbactions = DB_ACTIONS.get(dbtype) dbactions = DB_ACTIONS.get(dbtype)
self.runtime.start()
# set pwd #set your password
try: try:
if dbactions and dbtype == MYSQL: if dbactions and dbtype == MYSQL:
LOG.info(("Attempting to set your mysql password " LOG.info(("Attempting to set your mysql password"
" just incase it wasn't set previously")) " just incase it wasn't set previously."))
pwd_cmd = dbactions.get('setpwd') pwd_cmd = dbactions.get('set_pwd')
if pwd_cmd: if pwd_cmd:
LOG.info("Ensuring mysql is started.")
self.runtime.restart()
params = { params = {
'NEW_PASSWORD': self.cfg.get("passwords", "sql"), 'NEW_PASSWORD': self.cfg.get("passwords", "sql"),
'PASSWORD': '', 'USER': self.cfg.get("db", "sql_user"),
'USER': self.cfg.get("db", "sql_user") 'OLD_PASSWORD': RESET_BASE_PW,
} }
cmds = [{ cmds = [{'cmd': pwd_cmd}]
'cmd': pwd_cmd, utils.execute_template(*cmds, params=params, shell=True)
'run_as_root': True,
}]
utils.execute_template(*cmds, params=params)
except IOError: except IOError:
LOG.warn(("Couldn't set your password. It might have already been " LOG.warn(("Couldn't set your password. It might have already been "
"set by a previous process.")) "set by a previous process."), exc_info=True)
if dbactions and dbactions.get('grant_all'): #ensure access granted
#update the DB to give user 'USER'@'%' full control of the all databases: if dbactions:
grant_cmd = dbactions.get('grant_all') grant_cmd = dbactions.get('grant_all')
params = self._get_param_map(None) if grant_cmd:
cmds = list() user = self.cfg.get("db", "sql_user")
cmds.append({ LOG.info("Updating the DB to give user '%s' full control of all databases." % (user))
'cmd': grant_cmd, LOG.info("Ensuring your database is started.")
'run_as_root': False, self.runtime.restart()
}) params = {
#shell seems to be needed here 'PASSWORD': self.cfg.get("passwords", "sql"),
#since python escapes this to much... 'USER': user,
utils.execute_template(*cmds, params=params, shell=True) }
cmds = list()
cmds.append({
'cmd': grant_cmd,
})
#shell seems to be needed here
#since python escapes this to much...
utils.execute_template(*cmds, params=params, shell=True)
#special mysql actions
if dbactions and dbtype == MYSQL:
cmd = dbactions.get('host_adjust')
if cmd:
sh.execute(*cmd, run_as_root=True, shell=True)
#restart it to make sure all good
self.runtime.restart()
return parent_result return parent_result
@ -225,6 +227,8 @@ class DBRuntime(comp.EmptyRuntime):
if self.status() == comp.STATUS_STOPPED: if self.status() == comp.STATUS_STOPPED:
startcmd = self._get_run_actions('start', excp.StartException) startcmd = self._get_run_actions('start', excp.StartException)
sh.execute(*startcmd, run_as_root=True) sh.execute(*startcmd, run_as_root=True)
LOG.info("Please wait %s seconds while it comes up" % START_WAIT_TIME)
time.sleep(START_WAIT_TIME)
return 1 return 1
else: else:
return 0 return 0
@ -240,14 +244,17 @@ class DBRuntime(comp.EmptyRuntime):
def restart(self): def restart(self):
restartcmd = self._get_run_actions('restart', excp.RestartException) restartcmd = self._get_run_actions('restart', excp.RestartException)
sh.execute(*restartcmd, run_as_root=True) sh.execute(*restartcmd, run_as_root=True)
#this seems needed?
LOG.info("Please wait %s seconds while it comes up" % START_WAIT_TIME)
time.sleep(START_WAIT_TIME)
return 1 return 1
def status(self): def status(self):
statuscmd = self._get_run_actions('status', excp.StatusException) statuscmd = self._get_run_actions('status', excp.StatusException)
(sysout, _) = sh.execute(*statuscmd, check_exit_code=False) (sysout, _) = sh.execute(*statuscmd, check_exit_code=False)
if sysout.find("start/running") != -1: if sysout.find("running") != -1:
return comp.STATUS_STARTED return comp.STATUS_STARTED
elif sysout.find("stop/waiting") != -1: elif sysout.find("stop") != -1:
return comp.STATUS_STOPPED return comp.STATUS_STOPPED
else: else:
return comp.STATUS_UNKNOWN return comp.STATUS_UNKNOWN

View File

@ -51,6 +51,7 @@ DB_NAME = "glance"
#special subcomponents/options that are used in starting to know that images should be uploaded #special subcomponents/options that are used in starting to know that images should be uploaded
NO_IMG_START = "no-image-upload" NO_IMG_START = "no-image-upload"
WAIT_ONLINE_TO = 5
#what to start #what to start
APP_OPTIONS = { APP_OPTIONS = {
@ -71,6 +72,9 @@ BIN_DIR = 'bin'
#the pkg json files glance requires for installation #the pkg json files glance requires for installation
REQ_PKGS = ['general.json', 'glance.json'] REQ_PKGS = ['general.json', 'glance.json']
#pip files that glance requires
REQ_PIPS = ['glance.json']
class GlanceUninstaller(comp.PythonUninstallComponent): class GlanceUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
@ -97,6 +101,13 @@ class GlanceInstaller(comp.PythonInstallComponent):
#these are the config files we will be adjusting #these are the config files we will be adjusting
return list(CONFIGS) return list(CONFIGS)
def _get_pips(self):
pips = comp.PythonInstallComponent._get_pips(self)
for fn in REQ_PIPS:
full_name = sh.joinpths(settings.STACK_PIP_DIR, fn)
pips = utils.extract_pip_list([full_name], self.distro, pips)
return pips
def _get_pkgs(self): def _get_pkgs(self):
pkgs = comp.PythonInstallComponent._get_pkgs(self) pkgs = comp.PythonInstallComponent._get_pkgs(self)
for fn in REQ_PKGS: for fn in REQ_PKGS:
@ -205,7 +216,7 @@ class GlanceRuntime(comp.PythonRuntime):
if NO_IMG_START not in self.component_opts: if NO_IMG_START not in self.component_opts:
#install any images that need activating... #install any images that need activating...
# TODO: make this less cheesy - need to wait till glance goes online # TODO: make this less cheesy - need to wait till glance goes online
time.sleep(1) time.sleep(WAIT_ONLINE_TO)
creator.ImageCreationService(self.cfg).install() creator.ImageCreationService(self.cfg).install()

View File

@ -59,7 +59,7 @@ APP_OPTIONS = {
#the pkg json files keystone requires for installation #the pkg json files keystone requires for installation
REQ_PKGS = ['general.json', 'keystone.json'] REQ_PKGS = ['general.json', 'keystone.json']
#pip files that horizon requires #pip files that keystone requires
REQ_PIPS = ['keystone.json'] REQ_PIPS = ['keystone.json']

View File

@ -108,7 +108,9 @@ class Image(object):
params = {'TOKEN': self.token, 'IMAGE_NAME': self.image_name} params = {'TOKEN': self.token, 'IMAGE_NAME': self.image_name}
cmd = {'cmd': Image.KERNEL_FORMAT} cmd = {'cmd': Image.KERNEL_FORMAT}
with open(self.kernel) as file_: with open(self.kernel) as file_:
res = utils.execute_template(cmd, params=params, stdin_fh=file_) res = utils.execute_template(cmd,
params=params, stdin_fh=file_,
close_stdin=True)
self.kernel_id = res[0][0].split(':')[1].strip() self.kernel_id = res[0][0].split(':')[1].strip()
if self.initrd: if self.initrd:
@ -116,7 +118,8 @@ class Image(object):
params = {'TOKEN': self.token, 'IMAGE_NAME': self.image_name} params = {'TOKEN': self.token, 'IMAGE_NAME': self.image_name}
cmd = {'cmd': Image.INITRD_FORMAT} cmd = {'cmd': Image.INITRD_FORMAT}
with open(self.initrd) as file_: with open(self.initrd) as file_:
res = utils.execute_template(cmd, params=params, stdin_fh=file_) res = utils.execute_template(cmd, params=params,
stdin_fh=file_, close_stdin=True)
self.initrd_id = res[0][0].split(':')[1].strip() self.initrd_id = res[0][0].split(':')[1].strip()
LOG.info('Adding image %s to glance', self.image_name) LOG.info('Adding image %s to glance', self.image_name)
@ -124,7 +127,8 @@ class Image(object):
'KERNEL_ID': self.kernel_id, 'INITRD_ID': self.initrd_id} 'KERNEL_ID': self.kernel_id, 'INITRD_ID': self.initrd_id}
cmd = {'cmd': Image.IMAGE_FORMAT} cmd = {'cmd': Image.IMAGE_FORMAT}
with open(self.image) as file_: with open(self.image) as file_:
utils.execute_template(cmd, params=params, stdin_fh=file_) utils.execute_template(cmd, params=params,
stdin_fh=file_, close_stdin=True)
def _cleanup(self): def _cleanup(self):
if self.tmp_folder: if self.tmp_folder:

View File

@ -16,6 +16,7 @@
from devstack import log as logging from devstack import log as logging
from devstack import packager as pack from devstack import packager as pack
from devstack import settings
from devstack import shell as sh from devstack import shell as sh
LOG = logging.getLogger("devstack.packaging.yum") LOG = logging.getLogger("devstack.packaging.yum")
@ -47,9 +48,32 @@ class YumPackager(pack.Packager):
**kargs) **kargs)
def _remove_special(self, pkgname, pkginfo): def _remove_special(self, pkgname, pkginfo):
if pkgname == 'python-webob1.0' and self.distro == settings.RHEL6:
self._remove_webob_rhel()
return False return False
def _remove_webob_rhel(self):
if sh.isdir('/usr/lib/python2.6/site-packages/webob'):
#remove the link we made
rm_cmd = ['rm', '/usr/lib/python2.6/site-packages/webob']
sh.execute(*rm_cmd, run_as_root=True)
def _install_webob_rhel(self, pkgname, pkginfo):
full_pkg_name = self._format_pkg_name(pkgname, pkginfo.get("version"))
install_cmd = YUM_CMD + YUM_INSTALL + [full_pkg_name]
self._execute_yum(install_cmd)
#need to fix its link...
if not sh.isdir('/usr/lib/python2.6/site-packages/webob'):
#TODO: this needs to be a bug against that epel pkg
link_cmd = ['ln', '-s',
'/usr/lib/python2.6/site-packages/WebOb-1.0.8-py2.6.egg/webob/',
'/usr/lib/python2.6/site-packages/webob']
sh.execute(*link_cmd, run_as_root=True)
return True
def _install_special(self, pkgname, pkginfo): def _install_special(self, pkgname, pkginfo):
if pkgname == 'python-webob1.0' and self.distro == settings.RHEL6:
return self._install_webob_rhel(pkgname, pkginfo)
return False return False
def install_batch(self, pkgs): def install_batch(self, pkgs):

View File

@ -18,16 +18,24 @@
from devstack import exceptions as excp from devstack import exceptions as excp
from devstack import log as logging from devstack import log as logging
from devstack import shell as sh from devstack import shell as sh
from devstack import settings
LOG = logging.getLogger("devstack.pip") LOG = logging.getLogger("devstack.pip")
INSTALL_CMD = ['pip', 'install']
UNINSTALL_CMD = ['pip', 'uninstall'] PIP_UNINSTALL_CMD_OPTS = ['-y', '-q']
PIP_INSTALL_CMD_OPTS = ['-q']
def install(pips): def _cmd_name(distro):
if not pips: #of course u know they have to change the name...
return if distro == settings.RHEL6:
return 'pip-python'
else:
return 'pip'
def install(pips, distro):
actions = list() actions = list()
pipnames = sorted(pips.keys()) pipnames = sorted(pips.keys())
for name in pipnames: for name in pipnames:
@ -40,20 +48,20 @@ def install(pips):
actions.append(pipfull) actions.append(pipfull)
if actions: if actions:
LOG.info("Installing python packages [%s]" % (", ".join(actions))) LOG.info("Installing python packages [%s]" % (", ".join(actions)))
cmd = INSTALL_CMD + actions root_cmd = _cmd_name(distro)
cmd = [root_cmd, 'install'] + PIP_INSTALL_CMD_OPTS + actions
sh.execute(*cmd, run_as_root=True) sh.execute(*cmd, run_as_root=True)
def uninstall(pips): def uninstall(pips, distro):
if not pips:
return
pipnames = sorted(pips.keys()) pipnames = sorted(pips.keys())
LOG.info("Uninstalling python packages [%s]" % (", ".join(pipnames))) LOG.info("Uninstalling python packages [%s]" % (", ".join(pipnames)))
for name in pipnames: for name in pipnames:
pipinfo = pips.get(name, dict()) pipinfo = pips.get(name, dict())
skip_errors = pipinfo.get('skip_uninstall_errors', False) skip_errors = pipinfo.get('skip_uninstall_errors', True)
try: try:
cmd = UNINSTALL_CMD + [name] root_cmd = _cmd_name(distro)
cmd = [root_cmd, 'uninstall'] + PIP_UNINSTALL_CMD_OPTS + [name]
sh.execute(*cmd, run_as_root=True) sh.execute(*cmd, run_as_root=True)
except excp.ProcessExecutionError: except excp.ProcessExecutionError:
if skip_errors: if skip_errors:

View File

@ -48,6 +48,9 @@ _WELCOME_MAP = {
# For actions in this list we will reverse the component order # For actions in this list we will reverse the component order
_REVERSE_ACTIONS = [settings.UNINSTALL, settings.STOP] _REVERSE_ACTIONS = [settings.UNINSTALL, settings.STOP]
# These will not automatically stop when uninstalled since it seems to break there password reset.
_NO_AUTO_STOP = [settings.DB, settings.RABBIT]
def _clean_action(action): def _clean_action(action):
if action is None: if action is None:
@ -237,16 +240,17 @@ def _run_components(action_name, component_order, components, distro, root_dir,
else: else:
results.append(str(start_result)) results.append(str(start_result))
elif action_name == settings.UNINSTALL: elif action_name == settings.UNINSTALL:
# always stop first. doesn't hurt if already stopped - but makes if component not in _NO_AUTO_STOP:
# sure that there are no lingering processes if not # always stop first. doesn't hurt if already stopped - but makes
stop_cls = common.get_action_cls(settings.STOP, component) # sure that there are no lingering processes if not
stop_instance = stop_cls(instances=stop_instances, stop_cls = common.get_action_cls(settings.STOP, component)
distro=distro, stop_instance = stop_cls(instances=stop_instances,
packager=pkg_manager, distro=distro,
config=config, packager=pkg_manager,
root=root_dir, config=config,
opts=components.get(component, list())) root=root_dir,
_stop(component, stop_instance, program_args.get('force', False)) opts=components.get(component, list()))
_stop(component, stop_instance, program_args.get('force', False))
_uninstall(component, instance, program_args.get('force', False)) _uninstall(component, instance, program_args.get('force', False))
#display any configs touched... #display any configs touched...
_print_cfgs(config, action_name) _print_cfgs(config, action_name)

View File

@ -14,14 +14,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import operator import os
import os.path
import re import re
import sys
from devstack import log as logging
LOG = logging.getLogger("devstack.settings")
# These also have meaning outside python, # These also have meaning outside python,
# ie in the pkg/pip listings so update there also! # ie in the pkg/pip listings so update there also!

View File

@ -38,6 +38,7 @@ def execute(*cmd, **kwargs):
check_exit_code = kwargs.pop('check_exit_code', [0]) check_exit_code = kwargs.pop('check_exit_code', [0])
cwd = kwargs.pop('cwd', None) cwd = kwargs.pop('cwd', None)
env_overrides = kwargs.pop('env_overrides', None) env_overrides = kwargs.pop('env_overrides', None)
close_stdin = kwargs.pop('close_stdin', False)
ignore_exit_code = False ignore_exit_code = False
if isinstance(check_exit_code, bool): if isinstance(check_exit_code, bool):
@ -48,18 +49,22 @@ def execute(*cmd, **kwargs):
run_as_root = kwargs.pop('run_as_root', False) run_as_root = kwargs.pop('run_as_root', False)
shell = kwargs.pop('shell', False) shell = kwargs.pop('shell', False)
if run_as_root:
cmd = ROOT_HELPER + list(cmd)
cmd = [str(c) for c in cmd] execute_cmd = list()
execute_cmd = None if run_as_root:
str_cmd = " ".join(cmd) execute_cmd.extend(ROOT_HELPER)
for c in cmd:
execute_cmd.append(str(c))
str_cmd = " ".join(execute_cmd)
if shell: if shell:
execute_cmd = str_cmd.strip() execute_cmd = str_cmd.strip()
LOG.debug('Running shell cmd: [%s]' % (str_cmd))
if not shell:
LOG.debug('Running cmd: %s' % (execute_cmd))
else: else:
execute_cmd = cmd LOG.debug('Running shell cmd: %s' % (execute_cmd))
LOG.debug('Running cmd: [%s]' % (str_cmd))
if process_input is not None: if process_input is not None:
LOG.debug('With stdin: %s' % (process_input)) LOG.debug('With stdin: %s' % (process_input))
@ -85,9 +90,9 @@ def execute(*cmd, **kwargs):
stderr_fh = kwargs.get('stderr_fh') stderr_fh = kwargs.get('stderr_fh')
LOG.debug("Redirecting stderr to file handle: %s" % (stderr_fh)) LOG.debug("Redirecting stderr to file handle: %s" % (stderr_fh))
process_env = env.get() process_env = None
LOG.debug("With environment: %s" % (process_env))
if env_overrides and len(env_overrides): if env_overrides and len(env_overrides):
process_env = env.get()
LOG.debug("With additional environment overrides: %s" % (env_overrides)) LOG.debug("With additional environment overrides: %s" % (env_overrides))
for (k, v) in env_overrides.items(): for (k, v) in env_overrides.items():
process_env[k] = str(v) process_env[k] = str(v)
@ -107,7 +112,8 @@ def execute(*cmd, **kwargs):
else: else:
result = obj.communicate() result = obj.communicate()
if 'stdin_fh' not in kwargs.keys(): if (stdin_fh != subprocess.PIPE
and obj.stdin and close_stdin):
obj.stdin.close() obj.stdin.close()
rc = obj.returncode rc = obj.returncode
@ -155,11 +161,12 @@ def _gen_password(pw_len):
return stdout.strip() return stdout.strip()
def _prompt_password(prompt_=None): def prompt_password(pw_prompt=None):
if prompt_: if pw_prompt:
return getpass.getpass(prompt_) rc = getpass.getpass(pw_prompt)
else: else:
return getpass.getpass() rc = getpass.getpass()
return rc.strip()
def chown_r(path, uid, gid): def chown_r(path, uid, gid):
@ -181,7 +188,7 @@ def password(prompt_=None, pw_len=8):
rd = "" rd = ""
ask_for_pw = env.get_bool(PASS_ASK_ENV, True) ask_for_pw = env.get_bool(PASS_ASK_ENV, True)
if ask_for_pw: if ask_for_pw:
rd = _prompt_password(prompt_) rd = prompt_password(prompt_)
if not rd: if not rd:
return _gen_password(pw_len) return _gen_password(pw_len)
else: else:

View File

@ -34,6 +34,7 @@ from devstack import version
PARAM_SUB_REGEX = re.compile(r"%([\w\d]+?)%") PARAM_SUB_REGEX = re.compile(r"%([\w\d]+?)%")
EXT_COMPONENT = re.compile(r"^\s*([\w-]+)(?:\((.*)\))?\s*$") EXT_COMPONENT = re.compile(r"^\s*([\w-]+)(?:\((.*)\))?\s*$")
MONTY_PYTHON_TEXT_RE = re.compile("([a-z0-9A-Z!.,'\"]+)")
LOG = logging.getLogger("devstack.util") LOG = logging.getLogger("devstack.util")
TEMPLATE_EXT = ".tpl" TEMPLATE_EXT = ".tpl"
@ -358,14 +359,12 @@ def color_text(text, color, bold=False):
def _color_blob(text, text_color): def _color_blob(text, text_color):
special_chars = ['!', '.', ',', "'"]
colored_msg = "" def replacer(match):
for ch in text: contents = match.group(1)
if ch.isalpha() or ch.isdigit() or ch in special_chars: return color_text(contents, text_color)
colored_msg += color_text(ch, text_color)
else: return MONTY_PYTHON_TEXT_RE.sub(replacer, text)
colored_msg += ch
return colored_msg
def _goodbye_header(worked): def _goodbye_header(worked):