Run cinder-api under mod_wsgi with apache2

This change aligns with the Ocata cinder package, which has
moved the cinder-api to run under mod_wsgi with apache2.

Change-Id: I0ce782cdee1f9ab7cc721f346ddfb87067cdc9e7
This commit is contained in:
Corey Bryant 2017-01-09 19:48:42 +00:00
parent c0ca6c8547
commit 3d2b097330
9 changed files with 157 additions and 10 deletions

View File

@ -14,6 +14,7 @@
import glob import glob
import json import json
import math
import os import os
import re import re
import time import time
@ -90,6 +91,8 @@ from charmhelpers.contrib.network.ip import (
from charmhelpers.contrib.openstack.utils import ( from charmhelpers.contrib.openstack.utils import (
config_flags_parser, config_flags_parser,
get_host_ip, get_host_ip,
git_determine_usr_bin,
git_determine_python_path,
enable_memcache, enable_memcache,
) )
from charmhelpers.core.unitdata import kv from charmhelpers.core.unitdata import kv
@ -1208,6 +1211,43 @@ class WorkerConfigContext(OSContextGenerator):
return ctxt return ctxt
class WSGIWorkerConfigContext(WorkerConfigContext):
def __init__(self, name=None, script=None, admin_script=None,
public_script=None, process_weight=1.00,
admin_process_weight=0.75, public_process_weight=0.25):
self.service_name = name
self.user = name
self.group = name
self.script = script
self.admin_script = admin_script
self.public_script = public_script
self.process_weight = process_weight
self.admin_process_weight = admin_process_weight
self.public_process_weight = public_process_weight
def __call__(self):
multiplier = config('worker-multiplier') or 1
total_processes = self.num_cpus * multiplier
ctxt = {
"service_name": self.service_name,
"user": self.user,
"group": self.group,
"script": self.script,
"admin_script": self.admin_script,
"public_script": self.public_script,
"processes": int(math.ceil(self.process_weight * total_processes)),
"admin_processes": int(math.ceil(self.admin_process_weight *
total_processes)),
"public_processes": int(math.ceil(self.public_process_weight *
total_processes)),
"threads": 1,
"usr_bin": git_determine_usr_bin(),
"python_path": git_determine_python_path(),
}
return ctxt
class ZeroMQContext(OSContextGenerator): class ZeroMQContext(OSContextGenerator):
interfaces = ['zeromq-configuration'] interfaces = ['zeromq-configuration']
@ -1521,9 +1561,18 @@ class MemcacheContext(OSContextGenerator):
This context provides options for configuring a local memcache client and This context provides options for configuring a local memcache client and
server server
""" """
def __init__(self, package=None):
"""
@param package: Package to examine to extrapolate OpenStack release.
Used when charms have no openstack-origin config
option (ie subordinates)
"""
self.package = package
def __call__(self): def __call__(self):
ctxt = {} ctxt = {}
ctxt['use_memcache'] = enable_memcache(config('openstack-origin')) ctxt['use_memcache'] = enable_memcache(package=self.package)
if ctxt['use_memcache']: if ctxt['use_memcache']:
# Trusty version of memcached does not support ::1 as a listen # Trusty version of memcached does not support ::1 as a listen
# address so use host file entry instead # address so use host file entry instead

View File

@ -1119,6 +1119,35 @@ def git_generate_systemd_init_files(templates_dir):
shutil.copyfile(service_source, service_dest) shutil.copyfile(service_source, service_dest)
def git_determine_usr_bin():
"""Return the /usr/bin path for Apache2 config.
The /usr/bin path will be located in the virtualenv if the charm
is configured to deploy from source.
"""
if git_install_requested():
projects_yaml = config('openstack-origin-git')
projects_yaml = git_default_repos(projects_yaml)
return os.path.join(git_pip_venv_dir(projects_yaml), 'bin')
else:
return '/usr/bin'
def git_determine_python_path():
"""Return the python-path for Apache2 config.
Returns 'None' unless the charm is configured to deploy from source,
in which case the path of the virtualenv's site-packages is returned.
"""
if git_install_requested():
projects_yaml = config('openstack-origin-git')
projects_yaml = git_default_repos(projects_yaml)
return os.path.join(git_pip_venv_dir(projects_yaml),
'lib/python2.7/site-packages')
else:
return None
def os_workload_status(configs, required_interfaces, charm_func=None): def os_workload_status(configs, required_interfaces, charm_func=None):
""" """
Decorator to set workload status based on complete contexts Decorator to set workload status based on complete contexts
@ -1927,16 +1956,24 @@ def os_application_version_set(package):
application_version_set(application_version) application_version_set(application_version)
def enable_memcache(source=None, release=None): def enable_memcache(source=None, release=None, package=None):
"""Determine if memcache should be enabled on the local unit """Determine if memcache should be enabled on the local unit
@param source: source string for charm
@param release: release of OpenStack currently deployed @param release: release of OpenStack currently deployed
@param package: package to derive OpenStack version deployed
@returns boolean Whether memcache should be enabled @returns boolean Whether memcache should be enabled
""" """
if not release: _release = None
release = get_os_codename_install_source(source) if release:
return release >= 'mitaka' _release = release
else:
_release = os_release(package, base='icehouse')
if not _release:
_release = get_os_codename_install_source(source)
# TODO: this should be changed to a numeric comparison using a known list
# of releases and comparing by index.
return _release >= 'mitaka'
def token_cache_pkgs(source=None, release=None): def token_cache_pkgs(source=None, release=None):

View File

@ -616,6 +616,20 @@ def close_port(port, protocol="TCP"):
subprocess.check_call(_args) subprocess.check_call(_args)
def open_ports(start, end, protocol="TCP"):
"""Opens a range of service network ports"""
_args = ['open-port']
_args.append('{}-{}/{}'.format(start, end, protocol))
subprocess.check_call(_args)
def close_ports(start, end, protocol="TCP"):
"""Close a range of service network ports"""
_args = ['close-port']
_args.append('{}-{}/{}'.format(start, end, protocol))
subprocess.check_call(_args)
@cached @cached
def unit_get(attribute): def unit_get(attribute):
"""Get the unit ID for the remote unit""" """Get the unit ID for the remote unit"""

View File

@ -306,15 +306,17 @@ def add_user_to_group(username, group):
subprocess.check_call(cmd) subprocess.check_call(cmd)
def rsync(from_path, to_path, flags='-r', options=None): def rsync(from_path, to_path, flags='-r', options=None, timeout=None):
"""Replicate the contents of a path""" """Replicate the contents of a path"""
options = options or ['--delete', '--executability'] options = options or ['--delete', '--executability']
cmd = ['/usr/bin/rsync', flags] cmd = ['/usr/bin/rsync', flags]
if timeout:
cmd = ['timeout', str(timeout)] + cmd
cmd.extend(options) cmd.extend(options)
cmd.append(from_path) cmd.append(from_path)
cmd.append(to_path) cmd.append(to_path)
log(" ".join(cmd)) log(" ".join(cmd))
return subprocess.check_output(cmd).decode('UTF-8').strip() return subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode('UTF-8').strip()
def symlink(source, destination): def symlink(source, destination):

View File

@ -88,6 +88,7 @@ class HAProxyContext(OSContextGenerator):
ctxt = { ctxt = {
'service_ports': {'cinder_api': [haproxy_port, apache_port]}, 'service_ports': {'cinder_api': [haproxy_port, apache_port]},
'osapi_volume_listen_port': api_port, 'osapi_volume_listen_port': api_port,
'port': api_port,
} }
return ctxt return ctxt
@ -100,7 +101,7 @@ class ApacheSSLContext(SSLContext):
def __call__(self): def __call__(self):
# late import to work around circular dependency # late import to work around circular dependency
from cinder_utils import service_enabled from cinder_utils import service_enabled
if not service_enabled('cinder-api'): if not service_enabled('cinder-common'):
return {} return {}
return super(ApacheSSLContext, self).__call__() return super(ApacheSSLContext, self).__call__()

View File

@ -24,6 +24,7 @@ from subprocess import (
from cinder_utils import ( from cinder_utils import (
determine_packages, determine_packages,
disable_package_apache_site,
do_openstack_upgrade, do_openstack_upgrade,
git_install, git_install,
juju_log, juju_log,
@ -31,6 +32,7 @@ from cinder_utils import (
configure_lvm_storage, configure_lvm_storage,
register_configs, register_configs,
restart_map, restart_map,
run_in_apache,
services, services,
service_enabled, service_enabled,
service_restart, service_restart,
@ -140,6 +142,9 @@ def install():
apt_update() apt_update()
apt_install(determine_packages(), fatal=True) apt_install(determine_packages(), fatal=True)
if run_in_apache():
disable_package_apache_site()
status_set('maintenance', 'Git install') status_set('maintenance', 'Git install')
git_install(config('openstack-origin-git')) git_install(config('openstack-origin-git'))

View File

@ -180,6 +180,8 @@ APACHE_SITE_CONF = '/etc/apache2/sites-available/openstack_https_frontend'
APACHE_SITE_24_CONF = '/etc/apache2/sites-available/' \ APACHE_SITE_24_CONF = '/etc/apache2/sites-available/' \
'openstack_https_frontend.conf' 'openstack_https_frontend.conf'
MEMCACHED_CONF = '/etc/memcached.conf' MEMCACHED_CONF = '/etc/memcached.conf'
WSGI_CINDER_API_CONF = '/etc/apache2/sites-enabled/wsgi-openstack-api.conf'
PACKAGE_CINDER_API_CONF = '/etc/apache2/sites-enabled/cinder-wsgi.conf'
VERSION_PACKAGE = 'cinder-common' VERSION_PACKAGE = 'cinder-common'
@ -323,6 +325,21 @@ def resource_map(release=None):
'contexts': [context.MemcacheContext()], 'contexts': [context.MemcacheContext()],
'services': ['memcached']} 'services': ['memcached']}
if run_in_apache():
for cfile in resource_map:
svcs = resource_map[cfile]['services']
if 'cinder-api' in svcs:
svcs.remove('cinder-api')
if 'apache2' not in svcs:
svcs.append('apache2')
wsgi_script = "/usr/bin/cinder-wsgi"
resource_map[WSGI_CINDER_API_CONF] = {
'contexts': [context.WSGIWorkerConfigContext(name="cinder",
script=wsgi_script),
cinder_contexts.HAProxyContext()],
'services': ['apache2']
}
return resource_map return resource_map
@ -731,6 +748,9 @@ def do_openstack_upgrade(configs):
configs.set_release(openstack_release=new_os_rel) configs.set_release(openstack_release=new_os_rel)
configs.write_all() configs.write_all()
if run_in_apache():
disable_package_apache_site()
# Stop/start services and migrate DB if leader # Stop/start services and migrate DB if leader
[service_stop(s) for s in services()] [service_stop(s) for s in services()]
if is_elected_leader(CLUSTER_RES): if is_elected_leader(CLUSTER_RES):
@ -1053,3 +1073,18 @@ def _pause_resume_helper(f, configs):
f(assess_status_func(configs), f(assess_status_func(configs),
services=services(), services=services(),
ports=None) ports=None)
def run_in_apache():
"""Return true if cinder API is run under apache2 with mod_wsgi in
this release.
"""
return os_release('cinder-common') >= 'ocata'
def disable_package_apache_site():
"""Ensure that the package-provided apache configuration is disabled to
prevent it from conflicting with the charm-provided version.
"""
if os.path.exists(PACKAGE_CINDER_API_CONF):
subprocess.check_call(['a2dissite', 'cinder-wsgi'])

View File

@ -767,10 +767,13 @@ class CinderBasicDeployment(OpenStackAmuletDeployment):
# Services which are expected to restart upon config change # Services which are expected to restart upon config change
services = { services = {
'cinder-api': conf_file,
'cinder-scheduler': conf_file, 'cinder-scheduler': conf_file,
'cinder-volume': conf_file 'cinder-volume': conf_file
} }
if self._get_openstack_release() >= self.xenial_ocata:
services['apache2'] = conf_file
else:
services['cinder-api'] = conf_file
# Make config change, check for service restarts # Make config change, check for service restarts
u.log.debug('Making config change on {}...'.format(juju_service)) u.log.debug('Making config change on {}...'.format(juju_service))

View File

@ -87,6 +87,7 @@ TO_PATCH = [
'configure_installation_source', 'configure_installation_source',
'openstack_upgrade_available', 'openstack_upgrade_available',
'os_release', 'os_release',
'run_in_apache',
# charmhelpers.contrib.openstack.openstack.ha.utils # charmhelpers.contrib.openstack.openstack.ha.utils
'update_dns_ha_resource_params', 'update_dns_ha_resource_params',
# charmhelpers.contrib.hahelpers.cluster_utils # charmhelpers.contrib.hahelpers.cluster_utils