From f3a38c0c905b9c587c4143dc52300763ac732458 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Wed, 25 Aug 2021 20:11:10 -0300 Subject: [PATCH 1/5] Implement the tests for the cinder-lvm charm The cinder-lvm charm is a subordinate of the cinder charm. The spec can be found here: https://github.com/openstack/charm-specs/blob/master/specs/xena/backlog/cinder-lvm.rst --- .../charm_tests/cinder_lvm/__init__.py | 15 +++ .../openstack/charm_tests/cinder_lvm/tests.py | 124 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 zaza/openstack/charm_tests/cinder_lvm/__init__.py create mode 100644 zaza/openstack/charm_tests/cinder_lvm/tests.py diff --git a/zaza/openstack/charm_tests/cinder_lvm/__init__.py b/zaza/openstack/charm_tests/cinder_lvm/__init__.py new file mode 100644 index 0000000..740be90 --- /dev/null +++ b/zaza/openstack/charm_tests/cinder_lvm/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2021 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. + +"""Collection of code for setting up and testing cinder-lvm.""" diff --git a/zaza/openstack/charm_tests/cinder_lvm/tests.py b/zaza/openstack/charm_tests/cinder_lvm/tests.py new file mode 100644 index 0000000..6363bb1 --- /dev/null +++ b/zaza/openstack/charm_tests/cinder_lvm/tests.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +# Copyright 2019 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. + +"""Encapsulate cinder-lvm testing.""" + +import logging +import uuid + +import zaza.model +import zaza.openstack.charm_tests.test_utils as test_utils +import zaza.openstack.utilities.openstack as openstack_utils + + +def with_conf(key, value): + def patched(f): + def inner(*args, **kwargs): + prev = openstack_utils.get_application_config_option( + 'cinder-lvm', key) + try: + zaza.model.set_application_config('cinder-lvm', {key: value}) + zaza.model.wait_for_agent_status(model_name=None) + return f(*args, **kwargs) + finally: + zaza.model.set_application_config( + 'cinder-lvm', {key: str(prev)}) + zaza.model.wait_for_agent_status(model_name=None) + return inner + return patched + + +class CinderLVMTest(test_utils.OpenStackBaseTest): + """Encapsulate cinder-lvm tests.""" + + @classmethod + def setUpClass(cls): + """Run class setup for running tests.""" + super(CinderLVMTest, cls).setUpClass(application_name='cinder-lvm') + cls.model_name = zaza.model.get_juju_model() + cls.cinder_client = openstack_utils.get_cinder_session_client( + cls.keystone_session) + + @classmethod + def tearDown(cls): + volumes = cls.cinder_client.volumes + for volume in volumes.list(): + if volume.name.startswith('zaza'): + try: + volume.detach() + volumes.delete(volume) + except Exception: + pass + + def test_cinder_config(self): + logging.info('cinder-lvm') + expected_contents = { + 'LVM-zaza-lvm': { + 'volume_clear': ['zero'], + 'volumes_dir': ['/var/lib/cinder/volumes'], + 'volume_name_template': ['volume-%s'], + 'volume_clear_size': ['0'], + 'volume_driver': ['cinder.volume.drivers.lvm.LVMVolumeDriver'], + }} + + zaza.model.run_on_leader( + 'cinder', + 'sudo cp /etc/cinder/cinder.conf /tmp/', + model_name=self.model_name) + zaza.model.block_until_oslo_config_entries_match( + 'cinder', + '/tmp/cinder.conf', + expected_contents, + model_name=self.model_name, + timeout=10) + + def _tst_create_volume(self): + test_vol_name = "zaza{}".format(uuid.uuid1().fields[0]) + vol_new = self.cinder_client.volumes.create( + name=test_vol_name, + size='1') + openstack_utils.resource_reaches_status( + self.cinder_client.volumes, + vol_new.id, + wait_iteration_max_time=12000, + stop_after_attempt=5, + expected_status='available', + msg='Volume status wait') + return self.cinder_client.volumes.find(name=test_vol_name) + + def test_create_volume(self): + test_vol = self._tst_create_volume() + self.assertTrue(test_vol) + + host = getattr(test_vol, 'os-vol-host-attr:host').split('#')[0] + self.assertTrue(host.startswith('cinder@LVM')) + + @with_conf('overwrite', 'true') + @with_conf('block-device', '/dev/vdc') + def test_volume_overwrite(self): + self._tst_create_volume() + + @with_conf('block-device', 'none') + def test_device_none(self): + self._tst_create_volume() + + @with_conf('remove-missing', 'true') + def test_remove_missing_volume(self): + self._tst_create_volume() + + @with_conf('remove-missing-force', 'true') + def test_remove_missing_force(self): + self._tst_create_volume() From fef55ec31862caff5ed3f7cd7a4daa7bbfc57f93 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Wed, 25 Aug 2021 20:27:57 -0300 Subject: [PATCH 2/5] PEP8 style fixes --- zaza/openstack/charm_tests/cinder_lvm/tests.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zaza/openstack/charm_tests/cinder_lvm/tests.py b/zaza/openstack/charm_tests/cinder_lvm/tests.py index 6363bb1..43b4faa 100644 --- a/zaza/openstack/charm_tests/cinder_lvm/tests.py +++ b/zaza/openstack/charm_tests/cinder_lvm/tests.py @@ -25,6 +25,7 @@ import zaza.openstack.utilities.openstack as openstack_utils def with_conf(key, value): + """Temporarily set a configuration option for the cinder-lvm unit.""" def patched(f): def inner(*args, **kwargs): prev = openstack_utils.get_application_config_option( @@ -54,6 +55,7 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): @classmethod def tearDown(cls): + """Remove tests resources.""" volumes = cls.cinder_client.volumes for volume in volumes.list(): if volume.name.startswith('zaza'): @@ -64,6 +66,7 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): pass def test_cinder_config(self): + """Test that configuration options match our expectations.""" logging.info('cinder-lvm') expected_contents = { 'LVM-zaza-lvm': { @@ -86,6 +89,7 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): timeout=10) def _tst_create_volume(self): + """Create a volume via the LVM backend.""" test_vol_name = "zaza{}".format(uuid.uuid1().fields[0]) vol_new = self.cinder_client.volumes.create( name=test_vol_name, @@ -100,6 +104,7 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): return self.cinder_client.volumes.find(name=test_vol_name) def test_create_volume(self): + """Test creating a volume with basic configuration.""" test_vol = self._tst_create_volume() self.assertTrue(test_vol) @@ -109,16 +114,20 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): @with_conf('overwrite', 'true') @with_conf('block-device', '/dev/vdc') def test_volume_overwrite(self): + """Test creating a volume by overwriting one on the /dev/vdc device.""" self._tst_create_volume() @with_conf('block-device', 'none') def test_device_none(self): + """Test creating a volume in a dummy device (set as 'none').""" self._tst_create_volume() @with_conf('remove-missing', 'true') def test_remove_missing_volume(self): + """Test creating a volume after removing missing ones in a group.""" self._tst_create_volume() @with_conf('remove-missing-force', 'true') def test_remove_missing_force(self): + """Test volume creation by forcefully removing missing ones.""" self._tst_create_volume() From 5a5974233339d2392c5a70914f2f66280276e6dd Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Tue, 31 Aug 2021 12:24:03 -0300 Subject: [PATCH 3/5] Update the functional tests for cinder-lvm. This brings the changes from the 'cinder-lvm' repo itself, from where this class will be removed. --- .../openstack/charm_tests/cinder_lvm/tests.py | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/zaza/openstack/charm_tests/cinder_lvm/tests.py b/zaza/openstack/charm_tests/cinder_lvm/tests.py index 43b4faa..6ed1d60 100644 --- a/zaza/openstack/charm_tests/cinder_lvm/tests.py +++ b/zaza/openstack/charm_tests/cinder_lvm/tests.py @@ -24,20 +24,24 @@ import zaza.openstack.charm_tests.test_utils as test_utils import zaza.openstack.utilities.openstack as openstack_utils -def with_conf(key, value): - """Temporarily set a configuration option for the cinder-lvm unit.""" +def with_conf(application, config, model_name=None): + """Temporarily change the config options for an application in a model.""" + prev = {} + for key in config.keys(): + prev[key] = str(openstack_utils.get_application_config_option( + application, key, model_name=model_name)) + def patched(f): def inner(*args, **kwargs): - prev = openstack_utils.get_application_config_option( - 'cinder-lvm', key) try: - zaza.model.set_application_config('cinder-lvm', {key: value}) - zaza.model.wait_for_agent_status(model_name=None) + zaza.model.set_application_config( + application, config, model_name=model_name) + zaza.model.wait_for_agent_status(model_name=model_name) return f(*args, **kwargs) finally: zaza.model.set_application_config( - 'cinder-lvm', {key: str(prev)}) - zaza.model.wait_for_agent_status(model_name=None) + application, prev, model_name=model_name) + zaza.model.wait_for_agent_status(model_name=model_name) return inner return patched @@ -55,7 +59,7 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): @classmethod def tearDown(cls): - """Remove tests resources.""" + """Remove test resources.""" volumes = cls.cinder_client.volumes for volume in volumes.list(): if volume.name.startswith('zaza'): @@ -88,7 +92,7 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): model_name=self.model_name, timeout=10) - def _tst_create_volume(self): + def _create_volume(self): """Create a volume via the LVM backend.""" test_vol_name = "zaza{}".format(uuid.uuid1().fields[0]) vol_new = self.cinder_client.volumes.create( @@ -105,29 +109,28 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): def test_create_volume(self): """Test creating a volume with basic configuration.""" - test_vol = self._tst_create_volume() + test_vol = self._create_volume() self.assertTrue(test_vol) host = getattr(test_vol, 'os-vol-host-attr:host').split('#')[0] self.assertTrue(host.startswith('cinder@LVM')) - @with_conf('overwrite', 'true') - @with_conf('block-device', '/dev/vdc') + @with_conf('cinder-lvm', {'overwrite': 'true', 'block-device': '/dev/vdc'}) def test_volume_overwrite(self): """Test creating a volume by overwriting one on the /dev/vdc device.""" - self._tst_create_volume() + self._create_volume() - @with_conf('block-device', 'none') + @with_conf('cinder-lvm', {'block-device': 'none'}) def test_device_none(self): """Test creating a volume in a dummy device (set as 'none').""" - self._tst_create_volume() + self._create_volume() - @with_conf('remove-missing', 'true') + @with_conf('cinder-lvm', {'remove-missing': 'true'}) def test_remove_missing_volume(self): - """Test creating a volume after removing missing ones in a group.""" - self._tst_create_volume() + """Test creating a volume after remove missing ones in a group.""" + self._create_volume() - @with_conf('remove-missing-force', 'true') + @with_conf('cinder-lvm', {'remove-missing-force': 'true'}) def test_remove_missing_force(self): - """Test volume creation by forcefully removing missing ones.""" - self._tst_create_volume() + """Test creating a volume by forcefully removing missing ones.""" + self._create_volume() From 879d35d6fb01576f966bb030ba300149a41f3d22 Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Mon, 6 Sep 2021 19:16:17 -0300 Subject: [PATCH 4/5] Cleanup the test file Instead of introducing a new decorator to temporarily change the configuration, use the existing infrastructure. Furthermore, avoid passing the model name in some calls since it's implied already. --- .../openstack/charm_tests/cinder_lvm/tests.py | 50 +++++++------------ 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/zaza/openstack/charm_tests/cinder_lvm/tests.py b/zaza/openstack/charm_tests/cinder_lvm/tests.py index 6ed1d60..45fd126 100644 --- a/zaza/openstack/charm_tests/cinder_lvm/tests.py +++ b/zaza/openstack/charm_tests/cinder_lvm/tests.py @@ -24,28 +24,6 @@ import zaza.openstack.charm_tests.test_utils as test_utils import zaza.openstack.utilities.openstack as openstack_utils -def with_conf(application, config, model_name=None): - """Temporarily change the config options for an application in a model.""" - prev = {} - for key in config.keys(): - prev[key] = str(openstack_utils.get_application_config_option( - application, key, model_name=model_name)) - - def patched(f): - def inner(*args, **kwargs): - try: - zaza.model.set_application_config( - application, config, model_name=model_name) - zaza.model.wait_for_agent_status(model_name=model_name) - return f(*args, **kwargs) - finally: - zaza.model.set_application_config( - application, prev, model_name=model_name) - zaza.model.wait_for_agent_status(model_name=model_name) - return inner - return patched - - class CinderLVMTest(test_utils.OpenStackBaseTest): """Encapsulate cinder-lvm tests.""" @@ -56,6 +34,8 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): cls.model_name = zaza.model.get_juju_model() cls.cinder_client = openstack_utils.get_cinder_session_client( cls.keystone_session) + cls.block_device = openstack_utils.get_application_config_option( + 'cinder-lvm', 'block-device', model_name=cls.model_name) @classmethod def tearDown(cls): @@ -83,13 +63,11 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): zaza.model.run_on_leader( 'cinder', - 'sudo cp /etc/cinder/cinder.conf /tmp/', - model_name=self.model_name) + 'sudo cp /etc/cinder/cinder.conf /tmp/') zaza.model.block_until_oslo_config_entries_match( 'cinder', '/tmp/cinder.conf', expected_contents, - model_name=self.model_name, timeout=10) def _create_volume(self): @@ -115,22 +93,28 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): host = getattr(test_vol, 'os-vol-host-attr:host').split('#')[0] self.assertTrue(host.startswith('cinder@LVM')) - @with_conf('cinder-lvm', {'overwrite': 'true', 'block-device': '/dev/vdc'}) def test_volume_overwrite(self): """Test creating a volume by overwriting one on the /dev/vdc device.""" - self._create_volume() + with self.config_change({'overwrite': 'false', + 'block-device': self.block_device}, + {'overwrite': 'true', + 'block-device': '/dev/vdc'}): + self._create_volume() - @with_conf('cinder-lvm', {'block-device': 'none'}) def test_device_none(self): """Test creating a volume in a dummy device (set as 'none').""" - self._create_volume() + with self.config_change({'block-device': self.block_device}, + {'block-device': 'none'}): + self._create_volume() - @with_conf('cinder-lvm', {'remove-missing': 'true'}) def test_remove_missing_volume(self): """Test creating a volume after remove missing ones in a group.""" - self._create_volume() + with self.config_change({'remove-missing': 'false'}, + {'remove-missing': 'true'}): + self._create_volume() - @with_conf('cinder-lvm', {'remove-missing-force': 'true'}) def test_remove_missing_force(self): """Test creating a volume by forcefully removing missing ones.""" - self._create_volume() + with self.config_change({'remove-missing-force': 'false'}, + {'remove-missing-force': 'true'}): + self._create_volume() From 839e1a0868d13f39f28ace5604510efbcc7a0c6f Mon Sep 17 00:00:00 2001 From: Luciano Lo Giudice Date: Mon, 20 Sep 2021 20:06:37 -0300 Subject: [PATCH 5/5] Don't make assumptions about present devices Instead of using '/dev/vdc' for a test, use a loop device, since it should always be available and it allows us to set a specific size for it. --- zaza/openstack/charm_tests/cinder_lvm/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zaza/openstack/charm_tests/cinder_lvm/tests.py b/zaza/openstack/charm_tests/cinder_lvm/tests.py index 45fd126..a90c0bf 100644 --- a/zaza/openstack/charm_tests/cinder_lvm/tests.py +++ b/zaza/openstack/charm_tests/cinder_lvm/tests.py @@ -94,11 +94,11 @@ class CinderLVMTest(test_utils.OpenStackBaseTest): self.assertTrue(host.startswith('cinder@LVM')) def test_volume_overwrite(self): - """Test creating a volume by overwriting one on the /dev/vdc device.""" + """Test creating a volume by overwriting one on a loop device.""" with self.config_change({'overwrite': 'false', 'block-device': self.block_device}, {'overwrite': 'true', - 'block-device': '/dev/vdc'}): + 'block-device': '/tmp/vol|2G'}): self._create_volume() def test_device_none(self):