diff --git a/zaza/openstack/charm_tests/ceph/tests.py b/zaza/openstack/charm_tests/ceph/tests.py index 1200934..d20486f 100644 --- a/zaza/openstack/charm_tests/ceph/tests.py +++ b/zaza/openstack/charm_tests/ceph/tests.py @@ -794,6 +794,50 @@ class CephPrometheusTest(unittest.TestCase): '3', _get_mon_count_from_prometheus(unit.public_address)) +class CephPoolConfig(Exception): + """Custom Exception for bad Ceph pool config.""" + + pass + + +class CheckPoolTypes(unittest.TestCase): + """Test the ceph pools created for clients are of the expected type.""" + + def test_check_pool_types(self): + """Check type of pools created for clients.""" + app_pools = [ + ('glance', 'glance'), + ('nova-compute', 'nova'), + ('cinder-ceph', 'cinder-ceph')] + runtime_pool_details = zaza_ceph.get_ceph_pool_details() + for app, pool_name in app_pools: + juju_pool_config = zaza_model.get_application_config(app).get( + 'pool-type') + if juju_pool_config: + expected_pool_type = juju_pool_config['value'] + else: + # If the pool-type option is absent assume the default of + # replicated. + expected_pool_type = zaza_ceph.REPLICATED_POOL_TYPE + for pool_config in runtime_pool_details: + if pool_config['pool_name'] == pool_name: + logging.info('Checking {} is {}'.format( + pool_name, + expected_pool_type)) + expected_pool_code = -1 + if expected_pool_type == zaza_ceph.REPLICATED_POOL_TYPE: + expected_pool_code = zaza_ceph.REPLICATED_POOL_CODE + elif expected_pool_type == zaza_ceph.ERASURE_POOL_TYPE: + expected_pool_code = zaza_ceph.ERASURE_POOL_CODE + self.assertEqual( + pool_config['type'], + expected_pool_code) + break + else: + raise CephPoolConfig( + "Failed to find config for {}".format(pool_name)) + + # NOTE: We might query before prometheus has fetch data @tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, min=5, max=10), diff --git a/zaza/openstack/charm_tests/neutron/tests.py b/zaza/openstack/charm_tests/neutron/tests.py index ec6998d..311e763 100644 --- a/zaza/openstack/charm_tests/neutron/tests.py +++ b/zaza/openstack/charm_tests/neutron/tests.py @@ -295,19 +295,31 @@ class NeutronCreateNetworkTest(test_utils.OpenStackBaseTest): def test_400_create_network(self): """Create a network, verify that it exists, and then delete it.""" + self._wait_for_neutron_ready() self._assert_test_network_doesnt_exist() self._create_test_network() net_id = self._assert_test_network_exists_and_return_id() self._delete_test_network(net_id) self._assert_test_network_doesnt_exist() + @classmethod + def _wait_for_neutron_ready(cls): + logging.info('Waiting for Neutron to become ready...') + zaza.model.wait_for_application_states() + for attempt in tenacity.Retrying( + wait=tenacity.wait_fixed(5), # seconds + stop=tenacity.stop_after_attempt(12), + reraise=True): + with attempt: + cls.neutron_client.list_networks() + def _create_test_network(self): - logging.debug('Creating neutron network...') + logging.info('Creating neutron network...') network = {'name': self._TEST_NET_NAME} self.neutron_client.create_network({'network': network}) def _delete_test_network(self, net_id): - logging.debug('Deleting neutron network...') + logging.info('Deleting neutron network...') self.neutron_client.delete_network(net_id) def _assert_test_network_exists_and_return_id(self): diff --git a/zaza/openstack/charm_tests/neutron_arista/tests.py b/zaza/openstack/charm_tests/neutron_arista/tests.py index ba29bd6..354dfd1 100644 --- a/zaza/openstack/charm_tests/neutron_arista/tests.py +++ b/zaza/openstack/charm_tests/neutron_arista/tests.py @@ -29,14 +29,7 @@ class NeutronCreateAristaNetworkTest(neutron_tests.NeutronCreateNetworkTest): def setUpClass(cls): """Run class setup for running Neutron Arista tests.""" super(NeutronCreateAristaNetworkTest, cls).setUpClass() - - logging.info('Waiting for Neutron to become ready...') - for attempt in tenacity.Retrying( - wait=tenacity.wait_fixed(5), # seconds - stop=tenacity.stop_after_attempt(12), - reraise=True): - with attempt: - cls.neutron_client.list_networks() + cls._wait_for_neutron_ready() def _assert_test_network_exists_and_return_id(self): logging.info('Checking that the test network exists on the Arista ' diff --git a/zaza/openstack/charm_tests/saml_mellon/tests.py b/zaza/openstack/charm_tests/saml_mellon/tests.py index 28ceb4e..9b5b211 100644 --- a/zaza/openstack/charm_tests/saml_mellon/tests.py +++ b/zaza/openstack/charm_tests/saml_mellon/tests.py @@ -21,6 +21,7 @@ import requests import zaza.model from zaza.openstack.charm_tests.keystone import BaseKeystoneTest import zaza.charm_lifecycle.utils as lifecycle_utils +import zaza.openstack.utilities.openstack as openstack_utils class FailedToReachIDP(Exception): @@ -42,6 +43,8 @@ class CharmKeystoneSAMLMellonTest(BaseKeystoneTest): cls.test_config = lifecycle_utils.get_charm_config() cls.application_name = cls.test_config['charm_name'] cls.action = "get-sp-metadata" + cls.current_release = openstack_utils.get_os_release() + cls.FOCAL_USSURI = openstack_utils.get_os_release("focal_ussuri") def test_run_get_sp_metadata_action(self): """Validate the get-sp-metadata action.""" @@ -92,8 +95,13 @@ class CharmKeystoneSAMLMellonTest(BaseKeystoneTest): else: proto = "http" + # Use Keystone URL for < Focal + if self.current_release < self.FOCAL_USSURI: + region = "{}://{}:5000/v3".format(proto, keystone_ip) + else: + region = "default" + url = "{}://{}/horizon/auth/login/".format(proto, horizon_ip) - region = "{}://{}:5000/v3".format(proto, keystone_ip) horizon_expect = ('') diff --git a/zaza/openstack/charm_tests/vault/tests.py b/zaza/openstack/charm_tests/vault/tests.py index 5c93046..40227fd 100644 --- a/zaza/openstack/charm_tests/vault/tests.py +++ b/zaza/openstack/charm_tests/vault/tests.py @@ -51,6 +51,10 @@ class BaseVaultTest(test_utils.OpenStackBaseTest): vault_utils.auth_all(cls.clients, cls.vault_creds['root_token']) vault_utils.ensure_secret_backend(cls.clients[0]) + def tearDown(self): + """Tun test cleanup for Vault tests.""" + vault_utils.unseal_all(self.clients, self.vault_creds['keys'][0]) + @contextlib.contextmanager def pause_resume(self, services, pgrep_full=False): """Override pause_resume for Vault behavior.""" diff --git a/zaza/openstack/utilities/ceph.py b/zaza/openstack/utilities/ceph.py index 61d7d66..893ea5e 100644 --- a/zaza/openstack/utilities/ceph.py +++ b/zaza/openstack/utilities/ceph.py @@ -5,6 +5,11 @@ import logging import zaza.openstack.utilities.openstack as openstack_utils import zaza.model as zaza_model +REPLICATED_POOL_TYPE = 'replicated' +ERASURE_POOL_TYPE = 'erasure-coded' +REPLICATED_POOL_CODE = 1 +ERASURE_POOL_CODE = 3 + def get_expected_pools(radosgw=False): """Get expected ceph pools. @@ -97,6 +102,39 @@ def get_ceph_pools(unit_name, model_name=None): return pools +def get_ceph_pool_details(query_leader=True, unit_name=None, model_name=None): + """Get ceph pool details. + + Return a list of ceph pools details dicts. + + :param query_leader: Whether to query the leader for pool details. + :type query_leader: bool + :param unit_name: Name of unit to get the pools on if query_leader is False + :type unit_name: string + :param model_name: Name of model to operate in + :type model_name: str + :returns: Dict of ceph pools + :rtype: List[Dict,] + :raise: zaza_model.CommandRunFailed + """ + cmd = 'sudo ceph osd pool ls detail -f json' + if query_leader and unit_name: + raise ValueError("Cannot set query_leader and unit_name") + if query_leader: + result = zaza_model.run_on_leader( + 'ceph-mon', + cmd, + model_name=model_name) + else: + result = zaza_model.run_on_unit( + unit_name, + cmd, + model_name=model_name) + if int(result.get('Code')) != 0: + raise zaza_model.CommandRunFailed(cmd, result) + return json.loads(result.get('Stdout')) + + def get_ceph_df(unit_name, model_name=None): """Return dict of ceph df json output, including ceph pool state.