From fdfa62275cb4a8adbc52448a05b4f12db3fdabc6 Mon Sep 17 00:00:00 2001 From: coreycb Date: Fri, 30 Jun 2023 10:02:38 -0400 Subject: [PATCH] Service token support [xena] (#797) (#812) * Add configuration for use of service tokens Add a new template to configure the service_user ini file section and also add two needed parameters in keystone_authtoken configuration (cherry picked from commit f8c8861b4f0cb2181792013f9a973b3924a1e831) * Fixes for service tokens * Make admin role configurable * Move keystone_authtoken configuration from mitaka version to base version * Sync service_user config with keystone_authtoken for the base version (cherry picked from commit 7bcb1942ad11aafa307d5872d7b36a7bd7908288) Conflicts Resolved: charmhelpers/contrib/openstack/context.py * Fix tests (cherry picked from commit 4090532d1194d215cf5b065c1c108072652b8cfe) * Add test for this feature (cherry picked from commit e43008d7671433e44e27c58312292d8fb504fc59) * Fix test (cherry picked from commit c7cc5db9e4acd4dd66282bd4303f59db9ef8e9c6) * Add service token parameters to last authtoken template Copy parameters added in pull request #740 to the newest keystone-authtoken template. (cherry picked from commit 23d838bc55c842ea27ba29f4b1097b2ec9469fca) * Pin tox<4.0 --------- Co-authored-by: Jorge Merlino (cherry picked from commit 32772ff502e179027f46daaa04729a2f5d49f5e5) Co-authored-by: Felipe Reyes --- charmhelpers/contrib/openstack/context.py | 2 + .../templates/section-keystone-authtoken | 2 + .../section-keystone-authtoken-mitaka | 2 + .../openstack/templates/section-service-user | 11 +++++ tests/contrib/openstack/test_os_contexts.py | 43 +++++++++++++++++++ tox.ini | 1 + 6 files changed, 61 insertions(+) create mode 100644 charmhelpers/contrib/openstack/templates/section-service-user diff --git a/charmhelpers/contrib/openstack/context.py b/charmhelpers/contrib/openstack/context.py index df00c9702..2c21ed357 100644 --- a/charmhelpers/contrib/openstack/context.py +++ b/charmhelpers/contrib/openstack/context.py @@ -463,6 +463,7 @@ def __call__(self): int_host = format_ipv6_addr(int_host) or int_host svc_protocol = rdata.get('service_protocol') or 'http' auth_protocol = rdata.get('auth_protocol') or 'http' + admin_role = rdata.get('admin_role') or 'Admin' int_protocol = rdata.get('internal_protocol') or 'http' api_version = rdata.get('api_version') or '2.0' ctxt.update({'service_port': rdata.get('service_port'), @@ -474,6 +475,7 @@ def __call__(self): 'admin_tenant_name': rdata.get('service_tenant'), 'admin_user': rdata.get('service_username'), 'admin_password': rdata.get('service_password'), + 'admin_role': admin_role, 'service_protocol': svc_protocol, 'auth_protocol': auth_protocol, 'internal_protocol': int_protocol, diff --git a/charmhelpers/contrib/openstack/templates/section-keystone-authtoken b/charmhelpers/contrib/openstack/templates/section-keystone-authtoken index c9b01528e..dbad506fe 100644 --- a/charmhelpers/contrib/openstack/templates/section-keystone-authtoken +++ b/charmhelpers/contrib/openstack/templates/section-keystone-authtoken @@ -12,4 +12,6 @@ signing_dir = {{ signing_dir }} {% if service_type -%} service_type = {{ service_type }} {% endif -%} +service_token_roles = {{ admin_role }} +service_token_roles_required = True {% endif -%} diff --git a/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-mitaka b/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-mitaka index 14c25b4db..139a05128 100644 --- a/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-mitaka +++ b/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-mitaka @@ -22,4 +22,6 @@ signing_dir = {{ signing_dir }} {% if use_memcache == true %} memcached_servers = {{ memcache_url }} {% endif -%} +service_token_roles = {{ admin_role }} +service_token_roles_required = True {% endif -%} diff --git a/charmhelpers/contrib/openstack/templates/section-service-user b/charmhelpers/contrib/openstack/templates/section-service-user new file mode 100644 index 000000000..c740cc284 --- /dev/null +++ b/charmhelpers/contrib/openstack/templates/section-service-user @@ -0,0 +1,11 @@ +{% if auth_host -%} +[service_user] +send_service_user_token = true +auth_type = password +auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }} +project_domain_id = default +user_domain_id = default +project_name = {{ admin_tenant_name }} +username = {{ admin_user }} +password = {{ admin_password }} +{% endif -%} diff --git a/tests/contrib/openstack/test_os_contexts.py b/tests/contrib/openstack/test_os_contexts.py index c2b9d179a..fde43dc0e 100644 --- a/tests/contrib/openstack/test_os_contexts.py +++ b/tests/contrib/openstack/test_os_contexts.py @@ -224,6 +224,11 @@ def relation_units(self, relation_id): } IDENTITY_SERVICE_RELATION_VERSIONED.update(IDENTITY_SERVICE_RELATION_HTTPS) +IDENTITY_SERVICE_RELATION_ADMIN_ROLE = { + 'admin_role': 'Role', +} +IDENTITY_SERVICE_RELATION_ADMIN_ROLE.update(IDENTITY_SERVICE_RELATION_HTTPS) + IDENTITY_CREDENTIALS_RELATION_VERSIONED = { 'api_version': '3', 'service_tenant_id': 'svc-proj-id', @@ -1029,6 +1034,7 @@ def test_identity_service_context_with_data(self, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_tenant_name': 'admin', 'admin_tenant_id': None, 'admin_domain_id': None, @@ -1085,6 +1091,7 @@ def test_identity_service_context_with_altname(self, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_tenant_name': 'admin', 'admin_tenant_id': None, 'admin_domain_id': None, @@ -1116,6 +1123,7 @@ def test_identity_service_context_with_cache(self, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_tenant_name': 'admin', 'admin_tenant_id': None, 'admin_domain_id': None, @@ -1146,6 +1154,7 @@ def test_identity_service_context_with_data_http(self, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_tenant_name': 'admin', 'admin_tenant_id': '123456', 'admin_domain_id': None, @@ -1175,6 +1184,7 @@ def test_identity_service_context_with_data_https(self, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_tenant_name': 'admin', 'admin_tenant_id': None, 'admin_domain_id': None, @@ -1205,6 +1215,7 @@ def test_identity_service_context_with_data_versioned(self, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_domain_name': 'admin_domain', 'admin_tenant_name': 'admin', 'admin_tenant_id': 'svc-proj-id', @@ -1227,6 +1238,37 @@ def test_identity_service_context_with_data_versioned(self, *args): result.pop('keystone_authtoken') self.assertEquals(result, expected) + @patch.object(context, 'filter_installed_packages', return_value=[]) + @patch.object(context, 'os_release', return_value='rocky') + def test_identity_service_context_with_admin_role(self, *args): + '''Test shared-db context with admin role supplied from keystone''' + relation = FakeRelation( + relation_data=IDENTITY_SERVICE_RELATION_ADMIN_ROLE) + self.relation_get.side_effect = relation.get + identity_service = context.IdentityServiceContext() + result = identity_service() + expected = { + 'admin_password': 'foo', + 'admin_role': 'Role', + 'admin_tenant_name': 'admin', + 'admin_tenant_id': None, + 'admin_domain_id': None, + 'admin_user': 'adam', + 'auth_host': 'keystone-host.local', + 'auth_port': '35357', + 'auth_protocol': 'https', + 'service_host': 'keystonehost.local', + 'service_port': '5000', + 'service_protocol': 'https', + 'service_type': 'volume', + 'internal_host': 'keystone-internal.local', + 'internal_port': '5000', + 'internal_protocol': 'https', + 'api_version': '2.0', + } + result.pop('keystone_authtoken') + self.assertEquals(result, expected) + def test_identity_credentials_context_with_data_versioned(self): '''Test identity-credentials context with api version supplied from keystone''' relation = FakeRelation( @@ -1263,6 +1305,7 @@ def test_identity_service_context_with_ipv6(self, format_ipv6_addr, *args): result = identity_service() expected = { 'admin_password': 'foo', + 'admin_role': 'Admin', 'admin_tenant_name': 'admin', 'admin_tenant_id': '123456', 'admin_domain_id': None, diff --git a/tox.ini b/tox.ini index a11577657..a72939a57 100644 --- a/tox.ini +++ b/tox.ini @@ -17,6 +17,7 @@ ignore_basepython_conflict = true # https://stackoverflow.com/a/38133283 requires = pip < 20.3 virtualenv < 20.0 + tox < 4.0 # NOTE: https://wiki.canonical.com/engineering/OpenStack/InstallLatestToxOnOsci minversion = 3.2.0