Getting the user and group stuff working for horizon.

This commit is contained in:
Joshua Harlow 2012-01-25 13:06:19 -08:00
parent 1a48517931
commit b70908db4d
7 changed files with 148 additions and 23 deletions

View File

@ -1,8 +1,13 @@
<VirtualHost *:80>
<VirtualHost *:%HORIZON_PORT%>
#From commit 30439a6dc4
#With adjustments to make APACHE_RUN_GROUP a param
#and to make HORIZON_PORT a param
WSGIScriptAlias / %HORIZON_DIR%/openstack-dashboard/dashboard/wsgi/django.wsgi
WSGIDaemonProcess horizon user=%USER% group=%USER% processes=3 threads=10
WSGIDaemonProcess horizon user=%USER% group=%GROUP% processes=3 threads=10
SetEnv APACHE_RUN_USER %USER%
SetEnv APACHE_RUN_GROUP %USER%
SetEnv APACHE_RUN_GROUP %GROUP%
WSGIProcessGroup horizon
DocumentRoot %HORIZON_DIR%/.blackhole/
@ -24,5 +29,6 @@
ErrorLog /var/log/apache2/error.log
LogLevel warn
CustomLog /var/log/apache2/access.log combined
</VirtualHost>

View File

@ -1,6 +1,7 @@
# Based off of horizon_settings.py from commit 30439a6dc4
# With a change to allow OPENSTACK_HOST to come in from
# the new script instead of being fixed.
# the new script instead of being fixed. Also
# QUANTUM_ENABLED was made a param.
import os
@ -54,7 +55,7 @@ OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"
SWIFT_PAGINATE_LIMIT = 100
# Configure quantum connection details for networking
QUANTUM_ENABLED = False
QUANTUM_ENABLED = %QUANTUM_ENABLED%
QUANTUM_URL = '%s' % OPENSTACK_HOST
QUANTUM_PORT = '9696'
QUANTUM_TENANT = '1234'

View File

@ -2,6 +2,8 @@
# From commit 30439a6dc4
# Order actually matters in this file so be careful!
# This was added (so that it dies on errors)
set -o errexit

View File

@ -218,14 +218,29 @@ quantum_branch = master
[quantum]
# Where your quantum host is at
q_host = ${Q_HOST:-$(host:ip)}
# Which port your quantum host is at
q_port = ${Q_PORT:-9696}
# Which type of quantum plugin you will be using
q_plugin = ${Q_PLUGIN:-openvswitch}
[horizon]
# What user will apache be serving from
apache_user = ${APACHE_USER:-root}
#
# Root will typically not work (so this is here to fail)
# sudo adduser <username> admin will be what you want to set this up.
# I typically use "sudo adduser horizon admin"
apache_user = ${APACHE_USER:-horizon}
# This is the group of the previous user (adjust as needed)
apache_group = ${APACHE_GROUP:-horizon}
# Port horizon should run on
port = ${HORIZON_PORT:-80}
[ci]

View File

@ -53,6 +53,8 @@ DB_ACTIONS = {
#used as a generic error message
BASE_ERROR = 'Currently we do not know how to %s for database type [%s]'
#used to make params for booting when started (not always take advantage of...)
BOOLEAN_OUTPUT = {True: 'true', False: 'false'}
class DBUninstaller(comp.PkgUninstallComponent):
def __init__(self, *args, **kargs):
@ -69,7 +71,7 @@ class DBInstaller(comp.PkgInstallComponent):
#in pre-install and post-install sections
out = dict()
out['PASSWORD'] = self.cfg.get("passwords", "sql")
out['BOOT_START'] = str(True).lower()
out['BOOT_START'] = "%s" % BOOLEAN_OUTPUT.get(True)
out['USER'] = self.cfg.get("db", "sql_user")
host_ip = self.cfg.get('host', 'ip')
out['SERVICE_HOST'] = host_ip

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
from devstack import component as comp
from devstack import log as logging
@ -38,6 +39,12 @@ BLACKHOLE_DIR = '.blackhole'
#hopefully this will be distro independent ??
APACHE_RESTART_CMD = ['service', 'apache2', 'restart']
APACHE_START_CMD = ['service', 'apache2', 'start']
APACHE_STOP_CMD = ['service', 'apache2', 'stop']
APACHE_STATUS_CMD = ['service', 'apache2', 'status']
#users which apache may not like starting as
BAD_APACHE_USERS = ['root']
LOG = logging.getLogger("devstack.components.horizon")
@ -92,6 +99,7 @@ class HorizonInstaller(comp.PythonInstallComponent):
#create an empty directory that apache uses as docroot
black_dir = sh.joinpths(self.appdir, BLACKHOLE_DIR)
self.tracewriter.make_dir(black_dir)
return black_dir
def _sync_db(self):
#Initialize the horizon database (it stores sessions and notices shown to users).
@ -111,27 +119,47 @@ class HorizonInstaller(comp.PythonInstallComponent):
self.tracewriter.touch_file(sh.joinpths(quantum_dir, '__init__.py'))
self.tracewriter.touch_file(sh.joinpths(quantum_dir, 'client.py'))
def _ensure_db_access(self):
# ../openstack-dashboard/local needs to be writeable by the runtime user
# since currently its storing the sql-lite databases there (TODO fix that)
path = sh.joinpths(self.dash_dir, 'local')
if(sh.isdir(path)):
(user, group) = self._get_apache_user_group()
LOG.info("Changing ownership (recursively) of %s so that it can be used by %s - %s",
path, user, group)
uid = sh.getuid(user)
gid = sh.getgid(group)
sh.chown_r(path, uid, gid)
def post_install(self):
parent_result = comp.PythonInstallComponent.post_install(self)
self._fake_quantum()
self._sync_db()
self._setup_blackhole()
self._ensure_db_access()
return parent_result
def _get_apache_user(self):
#TODO will this be the right user?
def _get_apache_user_group(self):
user = self.cfg.get('horizon', 'apache_user')
if(not user):
user = sh.getuser()
return user
if(user in BAD_APACHE_USERS):
LOG.warn("You may want to adjust your configuration, user=%s will typically not work with apache", user)
group = self.cfg.get('horizon', 'apache_group')
if(not group):
group = sh.getgroupname()
return (user, group)
def _get_param_map(self, config_fn):
#this dict will be used to fill in the configuration
#params with actual values
mp = dict()
if(config_fn == HORIZON_APACHE_CONF):
mp['USER'] = self._get_apache_user()
(user, group) = self._get_apache_user_group()
mp['USER'] = user
mp['GROUP'] = group
mp['HORIZON_DIR'] = self.appdir
mp['HORIZON_PORT'] = self.cfg.get('horizon', 'port')
else:
#Enable quantum in dashboard, if requested
mp['QUANTUM_ENABLED'] = "%s" % (settings.QUANTUM in self.instances)
@ -142,3 +170,39 @@ class HorizonInstaller(comp.PythonInstallComponent):
class HorizonRuntime(comp.EmptyRuntime):
def __init__(self, *args, **kargs):
comp.EmptyRuntime.__init__(self, TYPE, *args, **kargs)
def start(self):
curr_status = self.status()
if(curr_status == comp.STATUS_STARTED):
#restart it ?
return self.restart()
else:
sh.execute(*APACHE_START_CMD,
run_as_root=True)
return 1
def restart(self):
curr_status = self.status()
if(curr_status == comp.STATUS_STARTED):
sh.execute(*APACHE_RESTART_CMD,
run_as_root=True)
return 1
return 0
def stop(self):
curr_status = self.status()
if(curr_status == comp.STATUS_STARTED):
sh.execute(*APACHE_STOP_CMD,
run_as_root=True)
return 1
return 0
def status(self):
(sysout, _) = sh.execute(*APACHE_STATUS_CMD,
check_exit_code=False)
if(sysout.find("is running") != -1):
return comp.STATUS_STARTED
elif(sysout.find("NOT running") != -1):
return comp.STATUS_STOPPED
else:
return comp.STATUS_UNKNOWN

View File

@ -14,8 +14,10 @@
# under the License.
import getpass
import grp
import os
import os.path
import pwd
import shutil
import subprocess
@ -49,11 +51,14 @@ def execute(*cmd, **kwargs):
cmd = ROOT_HELPER + list(cmd)
cmd = [str(c) for c in cmd]
execute_cmd = None
str_cmd = " ".join(cmd)
if(shell):
cmd = " ".join(cmd)
LOG.debug('Running shell cmd: [%s]' % (cmd))
execute_cmd = str_cmd.strip()
LOG.debug('Running shell cmd: [%s]' % (str_cmd))
else:
LOG.debug('Running cmd: [%s]' % (' '.join(cmd)))
execute_cmd = cmd
LOG.debug('Running cmd: [%s]' % (' '.join(str_cmd)))
if(process_input != None):
LOG.debug('With stdin: %s' % (process_input))
@ -86,7 +91,7 @@ def execute(*cmd, **kwargs):
for (k, v) in env_overrides.items():
process_env[k] = str(v)
obj = subprocess.Popen(cmd,
obj = subprocess.Popen(execute_cmd,
stdin=stdin_fh,
stdout=stdout_fh,
stderr=stderr_fh,
@ -103,20 +108,23 @@ def execute(*cmd, **kwargs):
if 'stdin_fh' not in kwargs.keys():
obj.stdin.close()
_returncode = obj.returncode
LOG.debug('Cmd result had exit code: %s' % _returncode)
if((not ignore_exit_code) and (_returncode not in check_exit_code)):
rc = obj.returncode
LOG.debug('Cmd result had exit code: %s' % rc)
if((not ignore_exit_code) and (rc not in check_exit_code)):
(stdout, stderr) = result
ecmd = cmd
if(not shell):
ecmd = ' '.join(cmd)
raise excp.ProcessExecutionError(
exit_code=_returncode,
exit_code=rc,
stdout=stdout,
stderr=stderr,
cmd=ecmd)
cmd=str_cmd)
else:
#log it anyway
if(rc not in check_exit_code):
(stdout, stderr) = result
LOG.debug("A failure may of just happened when running command \"%s\" [%s] (%s, %s)", str_cmd,
rc, stdout.strip(), stderr.strip())
return result
@ -153,6 +161,16 @@ def _prompt_password(prompt_=None):
return getpass.getpass()
def chown_r(path, uid, gid):
if(isdir(path)):
for root, dirs, files in os.walk(path):
os.chown(root, uid, gid)
for d in dirs:
os.chown(joinpths(root, d), uid, gid)
for f in files:
os.chown(joinpths(root, f), uid, gid)
def password(prompt_=None, pw_len=8):
rd = ""
ask_for_pw = env.get_bool(PASS_ASK_ENV, True)
@ -271,6 +289,23 @@ def getuser():
return getpass.getuser()
def getuid(username):
uinfo = pwd.getpwnam(username)
return uinfo.pw_gid
def getgid(groupname):
grp_info = grp.getgrnam(groupname)
return grp_info.gr_gid
def getgroupname(gid=None):
if(gid is None):
gid = os.getgid()
gid_info = grp.getgrgid(gid)
return gid_info.gr_name
def unlink(path, ignore_errors=True):
try:
LOG.debug("Unlinking (removing) %s" % (path))