From d36a55f4ac722a371f0da4e073bc911504df4427 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Mon, 18 Jul 2016 12:21:11 +0000 Subject: [PATCH] Add SSL support * Change charm to inherit layer:openstack-api as this is an API charm This adds the SSL config options to the charms config.yaml * Barbican now servers the API service through Apache so add code to manage /etc/apache2/conf-available/barbican-api.conf * Switch BarbicanConfigurationAdapter to be a child of APIConfigurationAdapter to inherit methods for configuring haproxy and apache2. * Add reactive handle to configure ssl when identity relation is complete * Move Juno template dir to mitaka as mitaka is the earliest supported release. * Updated host_href in barbican.conf to specify the correct external url for accessing the service. Without this clients are redirected to the wrong location. --- .gitignore | 1 + src/layer.yaml | 2 +- src/lib/charm/openstack/barbican.py | 25 +++++++++++++++---- src/reactive/barbican_handlers.py | 6 +++++ .../{juno => mitaka}/barbican-api-paste.ini | 0 src/templates/mitaka/barbican-api.conf | 18 +++++++++++++ src/templates/{juno => mitaka}/barbican.conf | 7 +++--- unit_tests/__init__.py | 2 ++ unit_tests/test_barbican_handlers.py | 1 + .../test_lib_charm_openstack_barbican.py | 6 +++++ 10 files changed, 59 insertions(+), 9 deletions(-) rename src/templates/{juno => mitaka}/barbican-api-paste.ini (100%) create mode 100644 src/templates/mitaka/barbican-api.conf rename src/templates/{juno => mitaka}/barbican.conf (98%) diff --git a/.gitignore b/.gitignore index 53bfadc..a68c28d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ layers interfaces trusty .testrepository +__pycache__ diff --git a/src/layer.yaml b/src/layer.yaml index f7594c4..4bbb62d 100644 --- a/src/layer.yaml +++ b/src/layer.yaml @@ -1,5 +1,5 @@ includes: - - layer:openstack + - layer:openstack-api - interface:mysql-shared - interface:rabbitmq - interface:keystone diff --git a/src/lib/charm/openstack/barbican.py b/src/lib/charm/openstack/barbican.py index 3c68ceb..cc5e40b 100644 --- a/src/lib/charm/openstack/barbican.py +++ b/src/lib/charm/openstack/barbican.py @@ -33,6 +33,7 @@ PACKAGES = ['barbican-common', 'barbican-api', 'barbican-worker', BARBICAN_DIR = '/etc/barbican/' BARBICAN_CONF = BARBICAN_DIR + "barbican.conf" BARBICAN_API_PASTE_CONF = BARBICAN_DIR + "barbican-api-paste.ini" +BARBICAN_WSGI_CONF = '/etc/apache2/conf-available/barbican-api.conf' OPENSTACK_RELEASE_KEY = 'barbican-charm.openstack-release-version' @@ -92,14 +93,24 @@ def assess_status(): BarbicanCharm.singleton.assess_status() +def configure_ssl(keystone=None): + """Use the singleton from the BarbicanCharm to configure ssl + + :param keystone: KeystoneRequires() interface class + """ + BarbicanCharm.singleton.configure_ssl(keystone) + + ### # Implementation of the Barbican Charm classes class BarbicanConfigurationAdapter( - charms_openstack.adapters.ConfigurationAdapter): + charms_openstack.adapters.APIConfigurationAdapter): - def __init__(self): - super(BarbicanConfigurationAdapter, self).__init__() + def __init__(self, port_map=None): + super(BarbicanConfigurationAdapter, self).__init__( + service_name='barbican', + port_map=port_map) if self.keystone_api_version not in ['2', '3', 'none']: raise ValueError( "Unsupported keystone-api-version ({}). It should be 2 or 3" @@ -176,10 +187,12 @@ class BarbicanAdapters(charms_openstack.adapters.OpenStackAPIRelationAdapters): def __init__(self, relations): super(BarbicanAdapters, self).__init__( - relations, options_instance=BarbicanConfigurationAdapter()) + relations, + options_instance=BarbicanConfigurationAdapter( + port_map=BarbicanCharm.api_ports)) -class BarbicanCharm(charms_openstack.charm.OpenStackCharm): +class BarbicanCharm(charms_openstack.charm.HAOpenStackCharm): """BarbicanCharm provides the specialisation of the OpenStackCharm functionality to manage a barbican unit. """ @@ -204,9 +217,11 @@ class BarbicanCharm(charms_openstack.charm.OpenStackCharm): restart_map = { BARBICAN_CONF: services, BARBICAN_API_PASTE_CONF: services, + BARBICAN_WSGI_CONF: services, } adapters_class = BarbicanAdapters + ha_resources = ['vips', 'haproxy'] def install(self): """Customise the installation, configure the source and then call the diff --git a/src/reactive/barbican_handlers.py b/src/reactive/barbican_handlers.py index bc5ee24..86584b5 100644 --- a/src/reactive/barbican_handlers.py +++ b/src/reactive/barbican_handlers.py @@ -81,3 +81,9 @@ def config_changed(): """When the configuration changes, assess the unit's status to update any juju state required""" barbican.assess_status() + + +@reactive.when('identity-service.available') +def configure_ssl(keystone): + '''Configure SSL access to Barbican if requested''' + barbican.configure_ssl(keystone) diff --git a/src/templates/juno/barbican-api-paste.ini b/src/templates/mitaka/barbican-api-paste.ini similarity index 100% rename from src/templates/juno/barbican-api-paste.ini rename to src/templates/mitaka/barbican-api-paste.ini diff --git a/src/templates/mitaka/barbican-api.conf b/src/templates/mitaka/barbican-api.conf new file mode 100644 index 0000000..20b8354 --- /dev/null +++ b/src/templates/mitaka/barbican-api.conf @@ -0,0 +1,18 @@ +Listen {{ options.service_listen_info.barbican_worker.public_port }} +Listen {{ options.service_listen_info.barbican_worker.admin_port }} + + + WSGIScriptAlias / /usr/share/barbican/app.wsgi + WSGIDaemonProcess barbican-api user=barbican group=barbican processes=3 threads=10 + WSGIProcessGroup barbican-api + ErrorLog /var/log/barbican/barbican-api.log + CustomLog /var/log/barbican/barbican-api.log combined + + + + WSGIScriptAlias / /usr/share/barbican/app.wsgi + WSGIDaemonProcess barbican-api-admin user=barbican group=barbican processes=3 threads=10 + WSGIProcessGroup barbican-api-admin + ErrorLog /var/log/barbican/barbican-api.log + CustomLog /var/log/barbican/barbican-api.log combined + diff --git a/src/templates/juno/barbican.conf b/src/templates/mitaka/barbican.conf similarity index 98% rename from src/templates/juno/barbican.conf rename to src/templates/mitaka/barbican.conf index fc5e056..d84268a 100644 --- a/src/templates/juno/barbican.conf +++ b/src/templates/mitaka/barbican.conf @@ -6,15 +6,16 @@ verbose = {{ options.verbose }} debug = {{ options.debug }} # Address to bind the API server -bind_host = 0.0.0.0 +# {{ options.service_listen_info }} +bind_host = {{ options.service_listen_info.barbican_worker.ip }} # Port to bind the API server to -bind_port = 9311 +bind_port = {{ options.service_listen_info.barbican_worker.port }} # Host name, for use in HATEOAS-style references # Note: Typically this would be the load balanced endpoint that clients would use # communicate back with this service. -host_href = http://localhost:9311 +host_href = {{ options.external_endpoints.barbican_worker.url }} # Log to this file. Make sure you do not set the same log # file for both the API and registry servers! diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py index 4d30f85..ba6362f 100644 --- a/unit_tests/__init__.py +++ b/unit_tests/__init__.py @@ -21,6 +21,8 @@ sys.path.append('src/lib') # Mock out charmhelpers so that we can test without it. # also stops sideeffects from occuring. charmhelpers = mock.MagicMock() +apt_pkg = mock.MagicMock() +sys.modules['apt_pkg'] = apt_pkg sys.modules['charmhelpers'] = charmhelpers sys.modules['charmhelpers.core'] = charmhelpers.core sys.modules['charmhelpers.core.hookenv'] = charmhelpers.core.hookenv diff --git a/unit_tests/test_barbican_handlers.py b/unit_tests/test_barbican_handlers.py index ee58b06..d9c06ba 100644 --- a/unit_tests/test_barbican_handlers.py +++ b/unit_tests/test_barbican_handlers.py @@ -108,6 +108,7 @@ class TestBarbicanHandlers(unittest.TestCase): 'identity-service.available', 'amqp.available',), 'config_changed': ('config.changed', ), + 'configure_ssl': ('identity-service.available', ), } when_not_patterns = { 'install_packages': ('charm.installed', ), diff --git a/unit_tests/test_lib_charm_openstack_barbican.py b/unit_tests/test_lib_charm_openstack_barbican.py index 83dc917..8c0fd09 100644 --- a/unit_tests/test_lib_charm_openstack_barbican.py +++ b/unit_tests/test_lib_charm_openstack_barbican.py @@ -52,11 +52,13 @@ class Helper(unittest.TestCase): class TestOpenStackBarbican(Helper): def test_install(self): + self.patch(barbican.BarbicanCharm, 'set_config_defined_certs_and_keys') self.patch(barbican.BarbicanCharm.singleton, 'install') barbican.install() self.install.assert_called_once_with() def test_setup_endpoint(self): + self.patch(barbican.BarbicanCharm, 'set_config_defined_certs_and_keys') self.patch(barbican.BarbicanCharm, 'service_type', new_callable=mock.PropertyMock) self.patch(barbican.BarbicanCharm, 'region', @@ -78,6 +80,7 @@ class TestOpenStackBarbican(Helper): 'type1', 'region1', 'public_url', 'internal_url', 'admin_url') def test_render_configs(self): + self.patch(barbican.BarbicanCharm, 'set_config_defined_certs_and_keys') self.patch(barbican.BarbicanCharm.singleton, 'render_with_interfaces') barbican.render_configs('interfaces-list') self.render_with_interfaces.assert_called_once_with( @@ -88,6 +91,9 @@ class TestBarbicanConfigurationAdapter(Helper): @mock.patch('charmhelpers.core.hookenv.config') def test_barbican_configuration_adapter(self, config): + self.patch( + barbican.charms_openstack.adapters.APIConfigurationAdapter, + 'get_network_addresses') reply = { 'keystone-api-version': '2', }