diff --git a/hooks/keystone-middleware-relation-broken b/hooks/keystone-middleware-relation-broken new file mode 120000 index 00000000..dd3b3eff --- /dev/null +++ b/hooks/keystone-middleware-relation-broken @@ -0,0 +1 @@ +keystone_hooks.py \ No newline at end of file diff --git a/hooks/keystone-middleware-relation-changed b/hooks/keystone-middleware-relation-changed new file mode 120000 index 00000000..dd3b3eff --- /dev/null +++ b/hooks/keystone-middleware-relation-changed @@ -0,0 +1 @@ +keystone_hooks.py \ No newline at end of file diff --git a/hooks/keystone-middleware-relation-departed b/hooks/keystone-middleware-relation-departed new file mode 120000 index 00000000..dd3b3eff --- /dev/null +++ b/hooks/keystone-middleware-relation-departed @@ -0,0 +1 @@ +keystone_hooks.py \ No newline at end of file diff --git a/hooks/keystone-middleware-relation-joined b/hooks/keystone-middleware-relation-joined new file mode 120000 index 00000000..dd3b3eff --- /dev/null +++ b/hooks/keystone-middleware-relation-joined @@ -0,0 +1 @@ +keystone_hooks.py \ No newline at end of file diff --git a/hooks/keystone_context.py b/hooks/keystone_context.py index 5287a8aa..d145f966 100644 --- a/hooks/keystone_context.py +++ b/hooks/keystone_context.py @@ -42,6 +42,26 @@ from charmhelpers.contrib.openstack.utils import ( ) +class MiddlewareContext(context.OSContextGenerator): + interfaces = ['keystone-middleware'] + + def __call__(self): + + middlewares = [] + + for rid in relation_ids('keystone-middleware'): + if related_units(rid): + for unit in related_units(rid): + middleware_name = relation_get('middleware_name', + rid=rid, + unit=unit) + if middleware_name: + middlewares.append(middleware_name) + return { + 'middlewares': ",".join(middlewares) + } + + class ApacheSSLContext(context.ApacheSSLContext): interfaces = ['https'] external_ports = [] diff --git a/hooks/keystone_hooks.py b/hooks/keystone_hooks.py index 7d6d1172..f922248f 100755 --- a/hooks/keystone_hooks.py +++ b/hooks/keystone_hooks.py @@ -789,6 +789,15 @@ def certs_changed(relation_id=None, unit=None): update_all_domain_backends() +@hooks.hook('keystone-middleware-relation-joined', + 'keystone-middleware-relation-changed', + 'keystone-middleware-relation-broken', + 'keystone-middleware-relation-departed') +@restart_on_change(restart_map()) +def keystone_middleware_changed(): + CONFIGS.write(KEYSTONE_CONF) + + @hooks.hook('pre-series-upgrade') def pre_series_upgrade(): log("Running prepare series upgrade hook", "INFO") diff --git a/hooks/keystone_utils.py b/hooks/keystone_utils.py index 16354e56..8a0e9dec 100644 --- a/hooks/keystone_utils.py +++ b/hooks/keystone_utils.py @@ -233,7 +233,12 @@ BASE_RESOURCE_MAP = OrderedDict([ context.WorkerConfigContext(), context.MemcacheContext(package='keystone'), keystone_context.KeystoneFIDServiceProviderContext(), - keystone_context.WebSSOTrustedDashboardContext()], + keystone_context.WebSSOTrustedDashboardContext(), + keystone_context.context.SubordinateConfigContext( + interface=['keystone-middleware'], + service='keystone', + config_file=KEYSTONE_CONF), + keystone_context.MiddlewareContext()] }), (KEYSTONE_LOGGER_CONF, { 'contexts': [keystone_context.KeystoneLoggingContext()], diff --git a/metadata.yaml b/metadata.yaml index aad95f17..c19347ec 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -46,6 +46,9 @@ requires: interface: websso-trusted-dashboard certificates: interface: tls-certificates + keystone-middleware: + interface: keystone-middleware + scope: container peers: cluster: interface: keystone-ha diff --git a/templates/ocata/keystone.conf b/templates/ocata/keystone.conf index d9c2bd48..aede63fe 100644 --- a/templates/ocata/keystone.conf +++ b/templates/ocata/keystone.conf @@ -69,11 +69,15 @@ driver = {{ assignment_backend }} [oauth1] +{% if middlewares -%} +{% include "parts/section-middleware" %} +{% else %} [auth] methods = external,password,token,oauth1,mapped,openid,totp password = keystone.auth.plugins.password.Password token = keystone.auth.plugins.token.Token oauth1 = keystone.auth.plugins.oauth1.OAuth +{% endif %} [paste_deploy] config_file = {{ paste_config_file }} diff --git a/templates/parts/section-middleware b/templates/parts/section-middleware new file mode 100644 index 00000000..e65f1d98 --- /dev/null +++ b/templates/parts/section-middleware @@ -0,0 +1,6 @@ +{% for section in sections -%} +[{{section}}] +{% for key, value in sections[section].items() -%} +{{ key }} = {{ value }} +{% endfor %} +{%- endfor %} diff --git a/unit_tests/test_keystone_contexts.py b/unit_tests/test_keystone_contexts.py index 8a78329a..0b4fd16a 100644 --- a/unit_tests/test_keystone_contexts.py +++ b/unit_tests/test_keystone_contexts.py @@ -439,3 +439,69 @@ class TestKeystoneContexts(CharmTestCase): self.maxDiff = None self.assertCountEqual(ctxt(), {}) + + @patch.object(context, 'relation_ids') + def test_middleware_no_related_units(self, mock_relation_ids): + os.environ['JUJU_UNIT_NAME'] = 'keystone' + + def relation_ids_side_effect(rname): + return { + 'keystone-middleware': {} + }[rname] + + mock_relation_ids.side_effect = relation_ids_side_effect + ctxt = context.MiddlewareContext() + + self.assertEqual(ctxt(), {'middlewares': ''}) + + @patch('charmhelpers.contrib.openstack.context.relation_ids') + @patch('charmhelpers.contrib.openstack.context.related_units') + @patch('charmhelpers.contrib.openstack.context.relation_get') + def test_middleware_related_units( + self, mock_relation_get, mock_related_units, mock_relation_ids): + mock_relation_ids.return_value = ['keystone-middleware:0'] + mock_related_units.return_value = ['keystone-ico/0'] + settings = \ + { + 'middleware_name': 'keystone-ico', + 'subordinate_configuration': + '{"keystone":' + '{"/etc/keystone/keystone.conf":' + '{"sections":' + '{"authentication":' + '[["simple_token_header", "SimpleToken"],' + '["simple_token_secret", "foobar"]],' + '"auth":' + '[["methods", "external,password,token,oauth1"],' + '["external", "keystone.auth.plugins.external.Domain"],' + '["password", "keystone.auth.plugins.password.Password"],' + '["token", "keystone.auth.plugins.token.Token"],' + '["oauth1", "keystone.auth.plugins.oauth1.OAuth"]]' + '}}}}' + + } + + def fake_rel_get(attribute=None, unit=None, rid=None): + return settings[attribute] + + mock_relation_get.side_effect = fake_rel_get + ctxt = context.context.SubordinateConfigContext( + interface=['keystone-middleware'], + service='keystone', + config_file='/etc/keystone/keystone.conf') + + exp = {'sections': { + u'auth': [[u'methods', + u'external,password,token,oauth1'], + [u'external', + u'keystone.auth.plugins.external.Domain'], + [u'password', + u'keystone.auth.plugins.password.Password'], + [u'token', + u'keystone.auth.plugins.token.Token'], + [u'oauth1', + u'keystone.auth.plugins.oauth1.OAuth']], + u'authentication': [[u'simple_token_header', u'SimpleToken'], + [u'simple_token_secret', u'foobar']]}} + + self.assertEqual(ctxt(), exp)