diff --git a/charmhelpers/contrib/openstack/context.py b/charmhelpers/contrib/openstack/context.py
index 91ddcec..3078076 100644
--- a/charmhelpers/contrib/openstack/context.py
+++ b/charmhelpers/contrib/openstack/context.py
@@ -14,6 +14,7 @@
import glob
import json
+import math
import os
import re
import time
@@ -90,6 +91,8 @@ from charmhelpers.contrib.network.ip import (
from charmhelpers.contrib.openstack.utils import (
config_flags_parser,
get_host_ip,
+ git_determine_usr_bin,
+ git_determine_python_path,
enable_memcache,
)
from charmhelpers.core.unitdata import kv
@@ -1208,6 +1211,43 @@ class WorkerConfigContext(OSContextGenerator):
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):
interfaces = ['zeromq-configuration']
diff --git a/charmhelpers/contrib/openstack/templates/wsgi-openstack-api.conf b/charmhelpers/contrib/openstack/templates/wsgi-openstack-api.conf
new file mode 100644
index 0000000..315b2a3
--- /dev/null
+++ b/charmhelpers/contrib/openstack/templates/wsgi-openstack-api.conf
@@ -0,0 +1,100 @@
+# Configuration file maintained by Juju. Local changes may be overwritten.
+
+{% if port -%}
+Listen {{ port }}
+{% endif -%}
+
+{% if admin_port -%}
+Listen {{ admin_port }}
+{% endif -%}
+
+{% if public_port -%}
+Listen {{ public_port }}
+{% endif -%}
+
+{% if port -%}
+
+ WSGIDaemonProcess {{ service_name }} processes={{ processes }} threads={{ threads }} user={{ service_name }} group={{ service_name }} \
+{% if python_path -%}
+ python-path={{ python_path }} \
+{% endif -%}
+ display-name=%{GROUP}
+ WSGIProcessGroup {{ service_name }}
+ WSGIScriptAlias / {{ script }}
+ WSGIApplicationGroup %{GLOBAL}
+ WSGIPassAuthorization On
+ = 2.4>
+ ErrorLogFormat "%{cu}t %M"
+
+ ErrorLog /var/log/apache2/{{ service_name }}_error.log
+ CustomLog /var/log/apache2/{{ service_name }}_access.log combined
+
+
+ = 2.4>
+ Require all granted
+
+
+ Order allow,deny
+ Allow from all
+
+
+
+{% endif -%}
+
+{% if admin_port -%}
+
+ WSGIDaemonProcess {{ service_name }}-admin processes={{ admin_processes }} threads={{ threads }} user={{ service_name }} group={{ service_name }} \
+{% if python_path -%}
+ python-path={{ python_path }} \
+{% endif -%}
+ display-name=%{GROUP}
+ WSGIProcessGroup {{ service_name }}-admin
+ WSGIScriptAlias / {{ admin_script }}
+ WSGIApplicationGroup %{GLOBAL}
+ WSGIPassAuthorization On
+ = 2.4>
+ ErrorLogFormat "%{cu}t %M"
+
+ ErrorLog /var/log/apache2/{{ service_name }}_error.log
+ CustomLog /var/log/apache2/{{ service_name }}_access.log combined
+
+
+ = 2.4>
+ Require all granted
+
+
+ Order allow,deny
+ Allow from all
+
+
+
+{% endif -%}
+
+{% if public_port -%}
+
+ WSGIDaemonProcess {{ service_name }}-public processes={{ public_processes }} threads={{ threads }} user={{ service_name }} group={{ service_name }} \
+{% if python_path -%}
+ python-path={{ python_path }} \
+{% endif -%}
+ display-name=%{GROUP}
+ WSGIProcessGroup {{ service_name }}-public
+ WSGIScriptAlias / {{ public_script }}
+ WSGIApplicationGroup %{GLOBAL}
+ WSGIPassAuthorization On
+ = 2.4>
+ ErrorLogFormat "%{cu}t %M"
+
+ ErrorLog /var/log/apache2/{{ service_name }}_error.log
+ CustomLog /var/log/apache2/{{ service_name }}_access.log combined
+
+
+ = 2.4>
+ Require all granted
+
+
+ Order allow,deny
+ Allow from all
+
+
+
+{% endif -%}
diff --git a/charmhelpers/contrib/openstack/utils.py b/charmhelpers/contrib/openstack/utils.py
index 59f9f51..3d47d81 100644
--- a/charmhelpers/contrib/openstack/utils.py
+++ b/charmhelpers/contrib/openstack/utils.py
@@ -1119,6 +1119,35 @@ def git_generate_systemd_init_files(templates_dir):
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):
"""
Decorator to set workload status based on complete contexts
diff --git a/config.yaml b/config.yaml
index 45342db..a2f391b 100644
--- a/config.yaml
+++ b/config.yaml
@@ -47,10 +47,6 @@ options:
NOTE: updating this setting to a source that is known to provide
a later version of OpenStack will trigger a software upgrade.
-
- NOTE: when openstack-origin-git is specified, openstack specific
- packages will be installed from source rather than from the
- openstack-origin repository.
region:
default: RegionOne
type: string
diff --git a/hooks/ceilometer_hooks.py b/hooks/ceilometer_hooks.py
index 7f18c0a..c325fb4 100755
--- a/hooks/ceilometer_hooks.py
+++ b/hooks/ceilometer_hooks.py
@@ -52,6 +52,7 @@ from charmhelpers.contrib.openstack.ha.utils import (
update_dns_ha_resource_params,
)
from ceilometer_utils import (
+ disable_package_apache_site,
get_packages,
CEILOMETER_DB,
CEILOMETER_SERVICE,
@@ -59,6 +60,7 @@ from ceilometer_utils import (
CEILOMETER_API_SYSTEMD_CONF,
register_configs,
restart_map,
+ run_in_apache,
services,
get_ceilometer_context,
get_shared_secret,
@@ -114,6 +116,8 @@ def install():
# NOTE(jamespage): ensure systemd override folder exists prior to
# attempting to write override.conf
mkdir(os.path.dirname(CEILOMETER_API_SYSTEMD_CONF))
+ if run_in_apache():
+ disable_package_apache_site()
@hooks.hook("amqp-relation-joined")
diff --git a/lib/ceilometer_contexts.py b/lib/ceilometer_contexts.py
index 9d7fe2c..26c67d2 100644
--- a/lib/ceilometer_contexts.py
+++ b/lib/ceilometer_contexts.py
@@ -46,7 +46,7 @@ class MongoDBContext(OSContextGenerator):
def __call__(self):
mongo_servers = []
replset = None
- use_replset = os_release('ceilometer-api') >= 'icehouse'
+ use_replset = os_release('ceilometer-common') >= 'icehouse'
for relid in relation_ids('shared-db'):
rel_units = related_units(relid)
diff --git a/lib/ceilometer_utils.py b/lib/ceilometer_utils.py
index cf04d33..3203c4d 100644
--- a/lib/ceilometer_utils.py
+++ b/lib/ceilometer_utils.py
@@ -34,6 +34,7 @@ from charmhelpers.contrib.openstack.utils import (
get_os_codename_package,
get_os_codename_install_source,
configure_installation_source,
+ os_release,
pause_unit,
resume_unit,
make_assess_status_func,
@@ -104,6 +105,8 @@ REQUIRED_INTERFACES = {
CEILOMETER_ROLE = "ResellerAdmin"
SVC = 'ceilometer'
+WSGI_CEILOMETER_API_CONF = '/etc/apache2/sites-enabled/wsgi-openstack-api.conf'
+PACKAGE_CEILOMETER_API_CONF = '/etc/apache2/sites-enabled/ceilometer-api.conf'
CONFIG_FILES = OrderedDict([
(CEILOMETER_CONF, {
@@ -178,6 +181,14 @@ def register_configs():
CONFIG_FILES[HTTPS_APACHE_CONF]['hook_contexts'])
if enable_memcache(release=release):
configs.register(MEMCACHED_CONF, [context.MemcacheContext()])
+
+ if run_in_apache():
+ wsgi_script = "/usr/share/ceilometer/app.wsgi"
+ configs.register(WSGI_CEILOMETER_API_CONF,
+ [context.WSGIWorkerConfigContext(name="ceilometer",
+ script=wsgi_script),
+ CeilometerContext(),
+ HAProxyContext()])
return configs
@@ -203,6 +214,15 @@ def restart_map():
if enable_memcache(source=config('openstack-origin')):
_map[MEMCACHED_CONF] = ['memcached']
+ if run_in_apache():
+ for cfile in _map:
+ svcs = _map[cfile]
+ if 'ceilometer-api' in svcs:
+ svcs.remove('ceilometer-api')
+ if 'apache2' not in svcs:
+ svcs.append('apache2')
+ _map['WSGI_CEILOMETER_API_CONF'] = ['apache2']
+
return _map
@@ -260,6 +280,9 @@ def do_openstack_upgrade(configs):
# set CONFIGS to load templates from new release
configs.set_release(openstack_release=new_os_rel)
+ if run_in_apache():
+ disable_package_apache_site()
+
def ceilometer_release_services():
codename = get_os_codename_install_source(config('openstack-origin'))
@@ -389,3 +412,18 @@ def reload_systemd():
"""
if init_is_systemd():
subprocess.check_call(['systemctl', 'daemon-reload'])
+
+
+def run_in_apache():
+ """Return true if ceilometer API is run under apache2 with mod_wsgi in
+ this release.
+ """
+ return os_release('ceilometer-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_CEILOMETER_API_CONF):
+ subprocess.check_call(['a2dissite', 'ceilometer-api'])
diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py
index 6b340f7..ec9fbb9 100644
--- a/tests/basic_deployment.py
+++ b/tests/basic_deployment.py
@@ -173,9 +173,12 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
ceilometer_svcs = [
'ceilometer-agent-central',
'ceilometer-collector',
- 'ceilometer-api',
'ceilometer-agent-notification',
]
+ if self._get_openstack_release() >= self.xenial_ocata:
+ ceilometer_svcs.append('apache2')
+ else:
+ ceilometer_svcs.append('ceilometer-api')
if self._get_openstack_release() < self.trusty_mitaka:
ceilometer_svcs.append('ceilometer-alarm-evaluator')
@@ -641,11 +644,14 @@ class CeilometerBasicDeployment(OpenStackAmuletDeployment):
if self._get_openstack_release() >= self.xenial_newton:
services = {
'ceilometer-collector - CollectorService(0)': conf_file,
- 'ceilometer-api': conf_file,
'ceilometer-polling - AgentManager(0)': conf_file,
'ceilometer-agent-notification - NotificationService(0)':
conf_file,
}
+ if self._get_openstack_release() >= self.xenial_ocata:
+ services['apache2'] = conf_file
+ else:
+ services['ceilometer-api'] = conf_file
else:
services = {
'ceilometer-collector': conf_file,
diff --git a/unit_tests/test_ceilometer_hooks.py b/unit_tests/test_ceilometer_hooks.py
index 878496a..0e63aa6 100644
--- a/unit_tests/test_ceilometer_hooks.py
+++ b/unit_tests/test_ceilometer_hooks.py
@@ -64,6 +64,7 @@ TO_PATCH = [
'status_set',
'update_dns_ha_resource_params',
'reload_systemd',
+ 'run_in_apache',
'mkdir',
'init_is_systemd',
'os_release',
diff --git a/unit_tests/test_ceilometer_utils.py b/unit_tests/test_ceilometer_utils.py
index 0cb68cf..07ead94 100644
--- a/unit_tests/test_ceilometer_utils.py
+++ b/unit_tests/test_ceilometer_utils.py
@@ -36,6 +36,7 @@ TO_PATCH = [
'os',
'enable_memcache',
'token_cache_pkgs',
+ 'os_release',
]