From ac1a668492b85c85ca8a4361f3c0b0cf9909e06b Mon Sep 17 00:00:00 2001 From: Corey Bryant Date: Fri, 6 Jan 2017 20:48:01 +0000 Subject: [PATCH] Run aodh-api under mod_wsgi with apache2 This change aligns with the Ocata aodh package, which has moved the aodh-api to run under mod_wsgi with apache2. Change-Id: I4aa6a978eb719c955ad216326514d1175c86b4a7 --- src/layer.yaml | 1 + src/lib/charm/openstack/aodh.py | 55 +++++++++--- src/metadata.yaml | 4 + src/templates/ocata/aodh-api.conf | 13 +++ src/tests/basic_deployment.py | 19 +++-- unit_tests/test_lib_charm_openstack_aodh.py | 95 +++++++++++---------- 6 files changed, 124 insertions(+), 63 deletions(-) create mode 100644 src/templates/ocata/aodh-api.conf diff --git a/src/layer.yaml b/src/layer.yaml index 0697c57..1f575e7 100644 --- a/src/layer.yaml +++ b/src/layer.yaml @@ -3,3 +3,4 @@ options: basic: use_venv: True include_system_packages: True +repo: https://github.com/openstack/charm-aodh diff --git a/src/lib/charm/openstack/aodh.py b/src/lib/charm/openstack/aodh.py index 9d6b1f1..e03e5a5 100644 --- a/src/lib/charm/openstack/aodh.py +++ b/src/lib/charm/openstack/aodh.py @@ -16,7 +16,6 @@ import collections import os import subprocess -import charmhelpers.contrib.openstack.utils as ch_utils import charmhelpers.core.host as ch_host import charms_openstack.charm @@ -28,6 +27,10 @@ AODH_CONF = os.path.join(AODH_DIR, 'aodh.conf') AODH_API_SYSTEMD_CONF = ( '/etc/systemd/system/aodh-api.service.d/override.conf' ) +AODH_WSGI_CONF = '/etc/apache2/sites-available/aodh-api.conf' + + +charms_openstack.charm.use_defaults('charm.default-select-release') class AodhAdapters(charms_openstack.adapters.OpenStackAPIRelationAdapters): @@ -105,14 +108,41 @@ class AodhCharm(charms_openstack.charm.HAOpenStackCharm): ]), } - def __init__(self, release=None, **kwargs): - """Custom initialiser for class - If no release is passed, then the charm determines the release from the - ch_utils.os_release() function. - """ - if release is None: - release = ch_utils.os_release('python-keystonemiddleware') - super(AodhCharm, self).__init__(release=release, **kwargs) + @staticmethod + def reload_and_restart(): + if ch_host.init_is_systemd(): + subprocess.check_call(['systemctl', 'daemon-reload']) + ch_host.service_restart('aodh-api') + + +class AodhCharmOcata(AodhCharm): + """From ocata onwards there is no aodh-api service, as this is handled via + apache2 with a wsgi handler. Therefore, these specialisations are simple + to switch out the aodh-api. + """ + + # This charms support Ocata and onward + release = 'ocata' + + # Init services the charm manages + # Ocata onwards uses apache2 rather than aodh-api + services = ['aodh-evaluator', 'aodh-notifier', + 'aodh-listener', 'apache2'] + + # The restart map defines which services should be restarted when a given + # file changes + # Ocata onwards doesn't require aodh-api and the AODH_API_SYSTEMD_CONF + # file. + restart_map = { + AODH_CONF: services, + AODH_WSGI_CONF: services, + } + + @staticmethod + def reload_and_restart(): + if ch_host.init_is_systemd(): + subprocess.check_call(['systemctl', 'daemon-reload']) + # no need to restart aodh-api in ocata and onwards def install(): @@ -182,10 +212,7 @@ def upgrade_if_available(interfaces_list): AodhCharm.singleton.upgrade_if_available(interfaces_list) -# TODO: drop once charm switches to apache+mod_wsgi def reload_and_restart(): - """Reload systemd and restart aodh-api when override file changes + """Reload systemd and restart aodh API when override file changes """ - if ch_host.init_is_systemd(): - subprocess.check_call(['systemctl', 'daemon-reload']) - ch_host.service_restart('aodh-api') + AodhCharm.singleton.reload_and_restart() diff --git a/src/metadata.yaml b/src/metadata.yaml index ed9f7fa..392f479 100644 --- a/src/metadata.yaml +++ b/src/metadata.yaml @@ -1,5 +1,6 @@ name: aodh summary: OpenStack Telemetry - Alarming service +maintainer: OpenStack Charmers description: | Ceilometer aims to deliver a Single Point Of Contact for billing systems, providing all the counters they need to establish customer billing, across @@ -9,10 +10,13 @@ description: | overall system. . Aodh provides the Alarming service as part of OpenStack telemetry. +tags: + - openstack series: - xenial - trusty - yakkety +subordinate: false requires: mongodb: interface: mongodb diff --git a/src/templates/ocata/aodh-api.conf b/src/templates/ocata/aodh-api.conf new file mode 100644 index 0000000..0994280 --- /dev/null +++ b/src/templates/ocata/aodh-api.conf @@ -0,0 +1,13 @@ +Listen {{ options.service_listen_info.aodh_api.public_port }} + + + WSGIDaemonProcess aodh-api user=aodh group=aodh processes=2 threads=10 display-name=%{GROUP} + WSGIProcessGroup aodh-api + WSGIScriptAlias / /usr/share/aodh/app.wsgi + WSGIApplicationGroup %{GLOBAL} + = 2.4> + ErrorLogFormat "%{cu}t %M" + + ErrorLog /var/log/apache2/aodh_error.log + CustomLog /var/log/apache2/aodh_access.log combined + diff --git a/src/tests/basic_deployment.py b/src/tests/basic_deployment.py index bba519e..654e8da 100644 --- a/src/tests/basic_deployment.py +++ b/src/tests/basic_deployment.py @@ -157,11 +157,11 @@ class AodhBasicDeployment(OpenStackAmuletDeployment): service units.""" u.log.debug('Checking system services on units...') - aodh_svcs = [ - 'aodh-api', 'aodh-evaluator', - 'aodh-notifier', 'aodh-listener' - ] - + aodh_svcs = ['aodh-evaluator', 'aodh-notifier', 'aodh-listener'] + if self._get_openstack_release() >= self.xenial_ocata: + aodh_svcs.append('apache2') + else: + aodh_svcs.append('aodh-api') if self._get_openstack_release() < self.trusty_mitaka: aodh_svcs.append('aodh-alarm-evaluator') aodh_svcs.append('aodh-alarm-notifier') @@ -333,7 +333,14 @@ class AodhBasicDeployment(OpenStackAmuletDeployment): # Services which are expected to restart upon config change, # and corresponding config files affected by the change conf_file = '/etc/aodh/aodh.conf' - if self._get_openstack_release() >= self.xenial_newton: + if self._get_openstack_release() >= self.xenial_ocata: + services = { + 'apache2': conf_file, + 'aodh-evaluator - AlarmEvaluationService(0)': conf_file, + 'aodh-notifier - AlarmNotifierService(0)': conf_file, + 'aodh-listener - EventAlarmEvaluationService(0)': conf_file, + } + elif self._get_openstack_release() >= self.xenial_newton: services = { ('/usr/bin/python /usr/bin/aodh-api --port 8032 -- ' '--config-file=/etc/aodh/aodh.conf ' diff --git a/unit_tests/test_lib_charm_openstack_aodh.py b/unit_tests/test_lib_charm_openstack_aodh.py index 674aa38..5ccde22 100644 --- a/unit_tests/test_lib_charm_openstack_aodh.py +++ b/unit_tests/test_lib_charm_openstack_aodh.py @@ -15,53 +15,38 @@ from __future__ import absolute_import from __future__ import print_function -import unittest - import mock import charm.openstack.aodh as aodh +import charms_openstack.test_utils as test_utils -class Helper(unittest.TestCase): + +class Helper(test_utils.PatchHelper): def setUp(self): - self._patches = {} - self._patches_start = {} - - def tearDown(self): - for k, v in self._patches.items(): - v.stop() - setattr(self, k, None) - self._patches = None - self._patches_start = None - - def patch(self, obj, attr, return_value=None, **kwargs): - mocked = mock.patch.object(obj, attr, **kwargs) - self._patches[attr] = mocked - started = mocked.start() - started.return_value = return_value - self._patches_start[attr] = started - setattr(self, attr, started) + super().setUp() + self.patch_release(aodh.AodhCharm.release) class TestOpenStackAodh(Helper): def test_install(self): - self.patch(aodh.AodhCharm.singleton, 'install') + self.patch_object(aodh.AodhCharm.singleton, 'install') aodh.install() self.install.assert_called_once_with() def test_setup_endpoint(self): - self.patch(aodh.AodhCharm, 'service_name', - new_callable=mock.PropertyMock) - self.patch(aodh.AodhCharm, 'region', - new_callable=mock.PropertyMock) - self.patch(aodh.AodhCharm, 'public_url', - new_callable=mock.PropertyMock) - self.patch(aodh.AodhCharm, 'internal_url', - new_callable=mock.PropertyMock) - self.patch(aodh.AodhCharm, 'admin_url', - new_callable=mock.PropertyMock) + self.patch_object(aodh.AodhCharm, 'service_name', + new_callable=mock.PropertyMock) + self.patch_object(aodh.AodhCharm, 'region', + new_callable=mock.PropertyMock) + self.patch_object(aodh.AodhCharm, 'public_url', + new_callable=mock.PropertyMock) + self.patch_object(aodh.AodhCharm, 'internal_url', + new_callable=mock.PropertyMock) + self.patch_object(aodh.AodhCharm, 'admin_url', + new_callable=mock.PropertyMock) self.service_name.return_value = 'type1' self.region.return_value = 'region1' self.public_url.return_value = 'public_url' @@ -73,7 +58,7 @@ class TestOpenStackAodh(Helper): 'type1', 'region1', 'public_url', 'internal_url', 'admin_url') def test_render_configs(self): - self.patch(aodh.AodhCharm.singleton, 'render_with_interfaces') + self.patch_object(aodh.AodhCharm.singleton, 'render_with_interfaces') aodh.render_configs('interfaces-list') self.render_with_interfaces.assert_called_once_with( 'interfaces-list') @@ -87,8 +72,9 @@ class TestAodhAdapters(Helper): 'keystone-api-version': '2', } config.side_effect = lambda: reply - self.patch(aodh.charms_openstack.adapters.APIConfigurationAdapter, - 'get_network_addresses') + self.patch_object( + aodh.charms_openstack.adapters.APIConfigurationAdapter, + 'get_network_addresses') cluster_relation = mock.MagicMock() cluster_relation.relation_name = 'cluster' amqp_relation = mock.MagicMock() @@ -116,17 +102,40 @@ class TestAodhAdapters(Helper): class TestAodhCharm(Helper): - def test__init__(self): - self.patch(aodh.ch_utils, 'os_release') - aodh.AodhCharm() - self.os_release.assert_called_once_with('python-keystonemiddleware') - def test_install(self): b = aodh.AodhCharm() - self.patch(aodh.charms_openstack.charm.OpenStackCharm, - 'configure_source') - self.patch(aodh.charms_openstack.charm.OpenStackCharm, - 'install') + self.patch_object(aodh.charms_openstack.charm.OpenStackCharm, + 'configure_source') + self.patch_object(aodh.charms_openstack.charm.OpenStackCharm, + 'install') b.install() self.configure_source.assert_called_once_with() self.install.assert_called_once_with() + + def test_reload_and_restart(self): + self.patch('subprocess.check_call', name='check_call') + self.patch_object(aodh.ch_host, 'service_restart') + self.patch_object(aodh.ch_host, 'init_is_systemd', return_value=False) + aodh.AodhCharm.reload_and_restart() + self.init_is_systemd.assert_called_once_with() + self.check_call.assert_not_called() + self.service_restart.assert_not_called() + # now say it is systemd. + self.init_is_systemd.return_value = True + aodh.AodhCharm.reload_and_restart() + self.check_call.assert_called_once_with(['systemctl', 'daemon-reload']) + self.service_restart.assert_called_once_with('aodh-api') + + +class TestAodhCharmOcata(Helper): + + def test_reload_and_restart(self): + self.patch('subprocess.check_call', name='check_call') + self.patch_object(aodh.ch_host, 'init_is_systemd', return_value=False) + aodh.AodhCharmOcata.reload_and_restart() + self.init_is_systemd.assert_called_once_with() + self.check_call.assert_not_called() + # now say it is systemd. + self.init_is_systemd.return_value = True + aodh.AodhCharmOcata.reload_and_restart() + self.check_call.assert_called_once_with(['systemctl', 'daemon-reload'])