From 7878523e3457116497cd48bdc7fa8b3761d0c621 Mon Sep 17 00:00:00 2001 From: Garrett Thompson Date: Wed, 3 Feb 2021 18:01:28 +0000 Subject: [PATCH 1/3] Rename zaza_juju to be consistent with all of repo --- unit_tests/utilities/test_zaza_utilities_ceph.py | 2 +- zaza/openstack/utilities/ceph.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/unit_tests/utilities/test_zaza_utilities_ceph.py b/unit_tests/utilities/test_zaza_utilities_ceph.py index ea718b7..e6ac337 100644 --- a/unit_tests/utilities/test_zaza_utilities_ceph.py +++ b/unit_tests/utilities/test_zaza_utilities_ceph.py @@ -118,7 +118,7 @@ class TestCephUtils(ut_utils.BaseTestCase): model_name='amodel') def test_pools_from_broker_req(self): - self.patch_object(ceph_utils.zaza_juju, 'get_relation_from_unit') + self.patch_object(ceph_utils.juju_utils, 'get_relation_from_unit') self.get_relation_from_unit.return_value = { 'broker_req': ( '{"api-version": 1, "ops": [' diff --git a/zaza/openstack/utilities/ceph.py b/zaza/openstack/utilities/ceph.py index 6613154..a01f56e 100644 --- a/zaza/openstack/utilities/ceph.py +++ b/zaza/openstack/utilities/ceph.py @@ -3,7 +3,7 @@ import json import logging import zaza.model as zaza_model -import zaza.utilities.juju as zaza_juju +import zaza.utilities.juju as juju_utils import zaza.openstack.utilities.openstack as openstack_utils @@ -225,7 +225,7 @@ def get_pools_from_broker_req(application_or_unit, model_name=None): """ # NOTE: we do not pass on a name for the remote_interface_name as that # varies between the Ceph consuming applications. - relation_data = zaza_juju.get_relation_from_unit( + relation_data = juju_utils.get_relation_from_unit( 'ceph-mon', application_or_unit, None, model_name=model_name) # NOTE: we probably should consume the Ceph broker code from c-h but c-h is From 2ab9cebbf67c8e88aabbe09250bd1c27396c5613 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Thu, 4 Feb 2021 08:48:17 +0100 Subject: [PATCH 2/3] Use per-model tmp-dir to store local copy of CA cert (#493) The current approach of storing the deployment CA certificate in the 'test/' relative path does not allow for executing tests for multiple targets from the same environment. We have previously moved (7a90110) the local copy of the SSH private key for similar reasons. Remove the global constants as we cannot build them without making function calls, and we'd rather avoid doing that at module import time. Code using the location of the local CA certificate has already been changed to use helper functions. --- .../test_zaza_utilities_openstack.py | 30 +++++++++++++------ zaza/openstack/utilities/openstack.py | 26 +++++++++++----- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/unit_tests/utilities/test_zaza_utilities_openstack.py b/unit_tests/utilities/test_zaza_utilities_openstack.py index 67cd417..c42fc9d 100644 --- a/unit_tests/utilities/test_zaza_utilities_openstack.py +++ b/unit_tests/utilities/test_zaza_utilities_openstack.py @@ -1333,25 +1333,34 @@ class TestOpenStackUtils(ut_utils.BaseTestCase): 'bridge-interface-mappings', {'ovn-bridge-mappings': 'physnet1:br-ex'})) + def test_get_cacert_absolute_path(self): + self.patch_object(openstack_utils.deployment_env, 'get_tmpdir') + self.get_tmpdir.return_value = '/tmp/default' + self.assertEqual( + openstack_utils.get_cacert_absolute_path('filename'), + '/tmp/default/filename') + def test_get_cacert(self): + self.patch_object(openstack_utils.deployment_env, 'get_tmpdir') + self.get_tmpdir.return_value = '/tmp/default' self.patch_object(openstack_utils.os.path, 'exists') results = { - 'tests/vault_juju_ca_cert.crt': True} + '/tmp/default/vault_juju_ca_cert.crt': True} self.exists.side_effect = lambda x: results[x] self.assertEqual( openstack_utils.get_cacert(), - 'tests/vault_juju_ca_cert.crt') + '/tmp/default/vault_juju_ca_cert.crt') results = { - 'tests/vault_juju_ca_cert.crt': False, - 'tests/keystone_juju_ca_cert.crt': True} + '/tmp/default/vault_juju_ca_cert.crt': False, + '/tmp/default/keystone_juju_ca_cert.crt': True} self.assertEqual( openstack_utils.get_cacert(), - 'tests/keystone_juju_ca_cert.crt') + '/tmp/default/keystone_juju_ca_cert.crt') results = { - 'tests/vault_juju_ca_cert.crt': False, - 'tests/keystone_juju_ca_cert.crt': False} + '/tmp/default/vault_juju_ca_cert.crt': False, + '/tmp/default/keystone_juju_ca_cert.crt': False} self.assertIsNone(openstack_utils.get_cacert()) def test_get_remote_ca_cert_file(self): @@ -1364,6 +1373,8 @@ class TestOpenStackUtils(ut_utils.BaseTestCase): self.patch_object(openstack_utils.shutil, 'move') self.patch_object(openstack_utils.os, 'chmod') self.patch_object(openstack_utils.tempfile, 'NamedTemporaryFile') + self.patch_object(openstack_utils.deployment_env, 'get_tmpdir') + self.get_tmpdir.return_value = '/tmp/default' enter_mock = mock.MagicMock() enter_mock.__enter__.return_value.name = 'tempfilename' self.NamedTemporaryFile.return_value = enter_mock @@ -1377,8 +1388,9 @@ class TestOpenStackUtils(ut_utils.BaseTestCase): 'neutron-api/0', '/tmp/ca1.cert', 'tempfilename') - self.chmod.assert_called_once_with('tests/ca1.cert', 0o644) - self.move.assert_called_once_with('tempfilename', 'tests/ca1.cert') + self.chmod.assert_called_once_with('/tmp/default/ca1.cert', 0o644) + self.move.assert_called_once_with( + 'tempfilename', '/tmp/default/ca1.cert') class TestAsyncOpenstackUtils(ut_utils.AioTestCase): diff --git a/zaza/openstack/utilities/openstack.py b/zaza/openstack/utilities/openstack.py index 522df31..d277656 100644 --- a/zaza/openstack/utilities/openstack.py +++ b/zaza/openstack/utilities/openstack.py @@ -185,12 +185,10 @@ WORKLOAD_STATUS_EXCEPTIONS = { # For vault TLS certificates CACERT_FILENAME_FORMAT = "{}_juju_ca_cert.crt" CERT_PROVIDERS = ['vault'] -LOCAL_CERT_DIR = "tests" REMOTE_CERT_DIR = "/usr/local/share/ca-certificates" KEYSTONE_CACERT = "keystone_juju_ca_cert.crt" KEYSTONE_REMOTE_CACERT = ( "/usr/local/share/ca-certificates/{}".format(KEYSTONE_CACERT)) -KEYSTONE_LOCAL_CACERT = ("{}/{}".format(LOCAL_CERT_DIR, KEYSTONE_CACERT)) async def async_block_until_ca_exists(application_name, ca_cert, @@ -236,6 +234,18 @@ async def async_block_until_ca_exists(application_name, ca_cert, block_until_ca_exists = zaza.model.sync_wrapper(async_block_until_ca_exists) +def get_cacert_absolute_path(filename): + """Build string containing location of the CA Certificate file. + + :param filename: Expected filename for CA Certificate file. + :type filename: str + :returns: Absolute path to file containing CA Certificate + :rtype: str + """ + return os.path.join( + deployment_env.get_tmpdir(), filename) + + def get_cacert(): """Return path to CA Certificate bundle for verification during test. @@ -243,12 +253,13 @@ def get_cacert(): :rtype: Union[str, None] """ for _provider in CERT_PROVIDERS: - _cert = LOCAL_CERT_DIR + '/' + CACERT_FILENAME_FORMAT.format( - _provider) + _cert = get_cacert_absolute_path( + CACERT_FILENAME_FORMAT.format(_provider)) if os.path.exists(_cert): return _cert - if os.path.exists(KEYSTONE_LOCAL_CACERT): - return KEYSTONE_LOCAL_CACERT + _keystone_local_cacert = get_cacert_absolute_path(KEYSTONE_CACERT) + if os.path.exists(_keystone_local_cacert): + return _keystone_local_cacert # OpenStack Client helpers @@ -2056,8 +2067,7 @@ def get_remote_ca_cert_file(application, model_name=None): application, model_name=model_name) for cert_file in cert_files: - _local_cert_file = "{}/{}".format( - LOCAL_CERT_DIR, + _local_cert_file = get_cacert_absolute_path( os.path.basename(cert_file)) with tempfile.NamedTemporaryFile(mode="w", delete=False) as _tmp_ca: try: From 4cbf70dd5e931285973ab230e65ba3678fa87994 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Thu, 4 Feb 2021 08:56:22 +0100 Subject: [PATCH 3/3] octavia: Configure SSH key to allow debugging of Amphorae (#495) --- zaza/openstack/charm_tests/octavia/setup.py | 50 +++++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/zaza/openstack/charm_tests/octavia/setup.py b/zaza/openstack/charm_tests/octavia/setup.py index 677c368..4b09aa0 100644 --- a/zaza/openstack/charm_tests/octavia/setup.py +++ b/zaza/openstack/charm_tests/octavia/setup.py @@ -25,6 +25,9 @@ import zaza.openstack.charm_tests.glance.setup as glance_setup import zaza.openstack.utilities.openstack as openstack import zaza.openstack.configure.guest +import zaza.openstack.charm_tests.nova.setup as nova_setup +import zaza.openstack.charm_tests.nova.utils as nova_utils + def ensure_lts_images(): """Ensure that bionic and focal images are available for the tests.""" @@ -51,13 +54,32 @@ def add_amphora_image(image_url=None): def configure_octavia(): - """Do mandatory post deployment configuration of Octavia.""" - # Tell Octavia charm it is safe to create cloud resources - logging.info('Running `configure-resources` action on Octavia leader unit') - zaza.model.run_action_on_leader( - 'octavia', - 'configure-resources', - action_params={}) + """Do post deployment configuration and initialization of Octavia. + + Certificates for the private Octavia worker <-> Amphorae communication must + be generated and set trough charm configuration. + + The optional SSH configuration options are set to enable debug and log + collection from Amphorae, we will use the same keypair as Zaza uses for + instance creation. + + The `configure-resources` action must be run to have the charm create + in-cloud resources such as management network and associated ports and + security groups. + """ + # Set up Nova client to create/retrieve keypair for Amphora debug purposes. + # + # We reuse the Nova setup code for this and in most cases the test + # declaration will already defined that the Nova manage_ssh_key setup + # helper to run before we get here. Re-run here to make sure this setup + # function can be used separately, manage_ssh_key is idempotent. + keystone_session = openstack.get_overcloud_keystone_session() + nova_client = openstack.get_nova_session_client( + keystone_session) + nova_setup.manage_ssh_key(nova_client) + ssh_public_key = openstack.get_public_key( + nova_client, nova_utils.KEYPAIR_NAME) + # Generate certificates for controller/load balancer instance communication (issuing_cakey, issuing_cacert) = cert.generate_cert( 'OSCI Zaza Issuer', @@ -71,7 +93,7 @@ def configure_octavia(): issuer_name='OSCI Zaza Octavia Controller', signing_key=controller_cakey) controller_bundle = controller_cert + controller_key - cert_config = { + charm_config = { 'lb-mgmt-issuing-cacert': base64.b64encode( issuing_cacert).decode('utf-8'), 'lb-mgmt-issuing-ca-private-key': base64.b64encode( @@ -81,6 +103,9 @@ def configure_octavia(): controller_cacert).decode('utf-8'), 'lb-mgmt-controller-cert': base64.b64encode( controller_bundle).decode('utf-8'), + 'amp-ssh-key-name': 'octavia', + 'amp-ssh-pub-key': base64.b64encode( + bytes(ssh_public_key, 'utf-8')).decode('utf-8'), } logging.info('Configuring certificates for mandatory Octavia ' 'client/server authentication ' @@ -93,10 +118,17 @@ def configure_octavia(): _singleton = zaza.openstack.charm_tests.test_utils.OpenStackBaseTest() _singleton.setUpClass(application_name='octavia') - with _singleton.config_change(cert_config, cert_config): + with _singleton.config_change(charm_config, charm_config): # wait for configuration to be applied then return pass + # Tell Octavia charm it is safe to create cloud resources + logging.info('Running `configure-resources` action on Octavia leader unit') + zaza.model.run_action_on_leader( + 'octavia', + 'configure-resources', + action_params={}) + def centralized_fip_network(): """Create network with centralized router for connecting lb and fips.