From 3f2d610d532cde885c1ea01b620dcc9f80d7707a Mon Sep 17 00:00:00 2001 From: Liam Young Date: Sun, 24 Sep 2023 10:35:33 +0000 Subject: [PATCH] Add Keystone LDAP on K8s tests Add Keystone LDAP on K8s tests, this includes a minor refator of the existing machine keystone LDAP tests. --- zaza/openstack/charm_tests/keystone/tests.py | 31 +++-- .../charm_tests/keystone/tests_ldap_k8s.py | 108 ++++++++++++++++++ 2 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 zaza/openstack/charm_tests/keystone/tests_ldap_k8s.py diff --git a/zaza/openstack/charm_tests/keystone/tests.py b/zaza/openstack/charm_tests/keystone/tests.py index 2047d87bf..a2ee3c281 100644 --- a/zaza/openstack/charm_tests/keystone/tests.py +++ b/zaza/openstack/charm_tests/keystone/tests.py @@ -488,6 +488,10 @@ def setUpClass(cls): """Run class setup for running Keystone ldap-tests.""" super(LdapTests, cls).setUpClass() + def get_ldap_ips(self): + """Return the ip addresses for the ldap servers.""" + return zaza.model.get_app_ips("ldap-server") + def _get_ldap_config(self): """Generate ldap config for current model. @@ -495,7 +499,7 @@ def _get_ldap_config(self): for the keystone-ldap application. :rtype: Tuple[bool, Dict[str,str]] """ - ldap_ips = zaza.model.get_app_ips("ldap-server") + ldap_ips = self.get_ldap_ips() self.assertTrue(ldap_ips, "Should be at least one ldap server") return { 'ldap-server': "ldap://{}".format(ldap_ips[0]), @@ -703,7 +707,7 @@ def _get_ldap_config(self): for the keystone-ldap application. :rtype: Tuple[bool, Dict[str,str]] """ - ldap_ips = zaza.model.get_app_ips("ldap-server") + ldap_ips = self.get_ldap_ips() self.assertTrue(ldap_ips, "Should be at least one ldap server") return { 'ldap-server': "ldap://{}".format(ldap_ips[0]), @@ -730,6 +734,15 @@ def _get_ldap_config(self): ' group_tree_dn: "group_tree_dn_foobar"}', } + def get_domain_config(self): + """Return rendered domain config.""" + units = zaza.model.get_units("keystone-ldap", + model_name=self.model_name) + result = zaza.model.run_on_unit( + units[0].name, + "cat /etc/keystone/domains/keystone.userdomain.conf") + return result['stdout'] + def test_200_config_flags_precedence(self): """Validates precedence when the same config options are used.""" application_name = 'keystone-ldap' @@ -755,28 +768,24 @@ def test_200_config_flags_precedence(self): zaza.model.wait_for_application_states( states=test_config.get("target_deploy_status", {}) ) - units = zaza.model.get_units("keystone-ldap", - model_name=self.model_name) - result = zaza.model.run_on_unit( - units[0].name, - "cat /etc/keystone/domains/keystone.userdomain.conf") + contents = self.get_domain_config() # not present in charm config, but present in config flags - self.assertIn("use_pool = True", result['stdout'], + self.assertIn("use_pool = True", contents, "use_pool value is expected to be present and " "set to True in the config file") # ldap-config-flags overriding empty charm config value self.assertIn("group_objectclass = posixGroup", - result['stdout'], + contents, "group_objectclass is expected to be present and" " set to posixGroup in the config file") # overridden by charm config, not written to file self.assertNotIn( "group_tree_dn_foobar", - result['stdout'], + contents, "user_tree_dn ldap-config-flags value needs to be " "overridden by ldap-user-tree-dn in config file") # complementing the above, value used is from charm setting - self.assertIn("group_tree_dn = ou=groups", result['stdout'], + self.assertIn("group_tree_dn = ou=groups", contents, "user_tree_dn value is expected to be present " "and set to dc=test,dc=com in the config file") diff --git a/zaza/openstack/charm_tests/keystone/tests_ldap_k8s.py b/zaza/openstack/charm_tests/keystone/tests_ldap_k8s.py new file mode 100644 index 000000000..771f5cdc0 --- /dev/null +++ b/zaza/openstack/charm_tests/keystone/tests_ldap_k8s.py @@ -0,0 +1,108 @@ +# Copyright 2023 Canonical Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Keystone LDAP tests on k8s.""" + +import json + +import contextlib +import zaza.openstack.charm_tests.keystone.tests as ks_tests +import zaza.openstack.charm_tests.tempest.tests as tempest_tests +import zaza.charm_lifecycle.utils as lifecycle_utils +import zaza.model +import subprocess + + +class LdapExplicitCharmConfigTestsK8S(ks_tests.LdapExplicitCharmConfigTests): + """Keystone LDAP tests for K8s deployment.""" + + @classmethod + def setUpClass(cls): + """Run class setup for running Keystone ldap-tests.""" + cls.model_name = zaza.model.get_juju_model() + cls.test_config = lifecycle_utils.get_charm_config(fatal=False) + cls.default_api_version = 3 + cls.api_v3 = 3 + cls.keystone_ips = cls.get_internal_ips("keystone", cls.model_name) + + @contextlib.contextmanager + def v3_keystone_preferred(self): + """Set the preferred keystone api to v3 within called context.""" + with contextlib.nullcontext(): + yield + + @staticmethod + def get_internal_ips(application, model_name): + """Return the internal ip addresses an application.""" + status = zaza.model.get_status(model_name=model_name) + units = status['applications'][application]["units"] + return [v.address for v in units.values()] + + def get_ldap_ips(self): + """Return the ip addresses for the ldap servers.""" + return self.get_internal_ips("ldap-server", self.model_name) + + def get_domain_config(self): + """Collect the rendered domain config file.""" + # libjuju does not support ssh to a payload container + cmd = [ + "juju", + "ssh", + "-m", + self.model_name, + "--container", + "keystone", + zaza.model.get_lead_unit("keystone").entity_id, + 'cat /etc/keystone/domains/keystone.userdomain.conf'] + out = subprocess.check_output(cmd) + return out.decode() + + def _get_ldap_config(self): + """Generate ldap config for current model. + + :return: tuple of whether ldap-server is running and if so, config + for the keystone-ldap application. + :rtype: Tuple[bool, Dict[str,str]] + """ + ldap_ips = self.get_ldap_ips() + self.assertTrue(ldap_ips, "Should be at least one ldap server") + config_flags = json.dumps({ + 'url': "ldap://{}".format(ldap_ips[0]), + 'user': 'cn=admin,dc=test,dc=com', + "use_pool": True, + 'password': 'crapper', + 'suffix': 'dc=test,dc=com', + 'query_scope': 'one', + 'user_objectclass': 'inetOrgPerson', + 'user_id_attribute': 'cn', + 'user_name_attribute': 'sn', + 'user_enabled_attribute': 'enabled', + 'user_enabled_invert': False, + 'user_enabled_mask': 0, + 'user_enabled_default': 'True', + 'group_tree_dn': 'ou=groups,dc=test,dc=com', + 'group_id_attribute': 'cn', + 'group_name_attribute': 'cn', + 'group_member_attribute': 'memberUid', + 'group_members_are_ids': True, + "group_objectclass": "posixGroup", + }) + return { + "ldap-config-flags": config_flags, + "domain-name": "userdomain"} + + +class KeystoneTempestTestK8S(tempest_tests.TempestTestScaleK8SBase): + """Test keystone k8s scale out and scale back.""" + + application_name = "keystone"