diff --git a/src/lib/charm/openstack/octavia.py b/src/lib/charm/openstack/octavia.py index f9287dd3..2a548e06 100644 --- a/src/lib/charm/openstack/octavia.py +++ b/src/lib/charm/openstack/octavia.py @@ -45,6 +45,14 @@ OCTAVIA_MGMT_SECGRP = OCTAVIA_MGMT_NAME_PREFIX + '-sec-grp' OCTAVIA_HEALTH_SECGRP = 'lb-health-mgr-sec-grp' OCTAVIA_HEALTH_LISTEN_PORT = '5555' +OCTAVIA_ROLES = [ + 'load-balancer_observer', + 'load-balancer_global_observer', + 'load-balancer_member', + 'load-balancer_quota_admin', + 'load-balancer_admin', +] + charms_openstack.charm.use_defaults('charm.default-select-release') diff --git a/src/reactive/octavia_handlers.py b/src/reactive/octavia_handlers.py index 88931563..d7ca0dd3 100644 --- a/src/reactive/octavia_handlers.py +++ b/src/reactive/octavia_handlers.py @@ -25,6 +25,7 @@ import charms_openstack.ip as os_ip import charmhelpers.core as ch_core import charm.openstack.api_crud as api_crud +import charm.openstack.octavia as octavia charms_openstack.bus.discover() @@ -32,12 +33,30 @@ charm.use_defaults( 'charm.installed', 'amqp.connected', 'shared-db.connected', - 'identity-service.connected', 'identity-service.available', 'config.changed', 'update-status') +@reactive.when('identity-service.connected') +def setup_endpoint_connection(keystone): + """Custom register endpoint function for Octavia. + + Octavia expects end users to have specifc roles assigned for access to the + load-balancer API [0]. Create these roles on charm deployment / upgrade. + + 0: https://docs.openstack.org/octavia/latest/configuration/policy.html + """ + with charm.provide_charm_instance() as instance: + keystone.register_endpoints(instance.service_type, + instance.region, + instance.public_url, + instance.internal_url, + instance.admin_url, + requested_roles=octavia.OCTAVIA_ROLES) + instance.assess_status() + + @reactive.when('leadership.is_leader') @reactive.when_not('leadership.set.heartbeat-key') def generate_heartbeat_key(): diff --git a/unit_tests/test_octavia_handlers.py b/unit_tests/test_octavia_handlers.py index 3f260248..886e7e11 100644 --- a/unit_tests/test_octavia_handlers.py +++ b/unit_tests/test_octavia_handlers.py @@ -18,6 +18,7 @@ from __future__ import print_function import json import mock +import charm.openstack.octavia as octavia import reactive.octavia_handlers as handlers import charms_openstack.test_utils as test_utils @@ -30,7 +31,6 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks): 'charm.installed', 'amqp.connected', 'shared-db.connected', - 'identity-service.connected', 'identity-service.available', 'config.changed', 'update-status'] @@ -55,6 +55,8 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks): 'identity-service.available', 'neutron-api.available', 'amqp.available',), + 'setup_endpoint_connection': ( + 'identity-service.connected',), }, 'when_not': { 'init_db': ('db.synced',), @@ -71,6 +73,7 @@ class TestOctaviaHandlers(test_utils.PatchHelper): def setUp(self): super().setUp() + self.patch_release(octavia.OctaviaCharm.release) self.octavia_charm = mock.MagicMock() self.patch_object(handlers.charm, 'provide_charm_instance', new=mock.MagicMock()) @@ -78,6 +81,18 @@ class TestOctaviaHandlers(test_utils.PatchHelper): self.octavia_charm self.provide_charm_instance().__exit__.return_value = None + def test_setup_endpoint_connection(self): + keystone = mock.MagicMock() + handlers.setup_endpoint_connection(keystone) + keystone.register_endpoints.assert_called_once_with( + self.octavia_charm.service_type, + self.octavia_charm.region, + self.octavia_charm.public_url, + self.octavia_charm.internal_url, + self.octavia_charm.admin_url, + requested_roles=octavia.OCTAVIA_ROLES) + self.octavia_charm.assess_status.assert_called_once_with() + def test_generate_heartbeat_key(self): self.patch('charms.leadership.leader_set', 'leader_set') self.patch('uuid.uuid4', 'uuid4')