From a445a33add78f9a295b2f49ca1440ad4c1c9a4fe Mon Sep 17 00:00:00 2001 From: Billy Olsen Date: Mon, 4 Feb 2019 19:43:49 -0700 Subject: [PATCH] Install multipath dependencies when use-multipath is True This change ensures that the multipath dependencies are installed on the compute node when the use-multipath config flag is enabled. Change-Id: I39b017398b95f5901d9bc57ffa0c59ff59f3a359 Closes-Bug: #1806830 --- config.yaml | 4 ++-- hooks/nova_compute_hooks.py | 9 +++++++++ hooks/nova_compute_utils.py | 10 ++++++++++ unit_tests/test_nova_compute_hooks.py | 17 ++++++++++++++++ unit_tests/test_nova_compute_utils.py | 28 +++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index eb0e05a0..8e151b68 100644 --- a/config.yaml +++ b/config.yaml @@ -470,8 +470,8 @@ options: type: boolean default: False description: | - Use a multipath connection for iSCSI volumes. Enabling this feature - causes libvirt to discover and login to available iscsi targets before + Use a multipath connection for iSCSI or FC volumes. Enabling this feature + causes libvirt to login, discover and scan available targets before presenting the disk via device mapper (/dev/mapper/XX) to the VM instead of a single path (/dev/disk/by-path/XX). If changed after deployment, each VM will require a full stop/start for changes to take affect. diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 8a30896e..70e817af 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -110,6 +110,7 @@ from nova_compute_utils import ( resume_unit_helper, get_availability_zone, remove_old_packages, + MULTIPATH_PACKAGES, ) from charmhelpers.contrib.network.ip import ( @@ -248,6 +249,7 @@ def config_changed(): NovaNetworkAppArmorContext().setup_aa_profile() install_vaultlocker() + install_multipath() configure_local_ephemeral_storage() @@ -260,6 +262,13 @@ def install_vaultlocker(): apt_install('vaultlocker', fatal=True) +def install_multipath(): + if config('use-multipath'): + installed = len(filter_installed_packages(MULTIPATH_PACKAGES)) == 0 + if not installed: + apt_install(MULTIPATH_PACKAGES, fatal=True) + + @hooks.hook('amqp-relation-joined') def amqp_joined(relation_id=None): relation_set(relation_id=relation_id, diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 55df64d0..5d8decf4 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -141,6 +141,11 @@ PURGE_PACKAGES = [ 'python-nova', ] +MULTIPATH_PACKAGES = [ + 'multipath-tools', + 'sysfsutils', +] + HELD_PACKAGES = [ 'python-memcache', 'python-six', @@ -424,6 +429,11 @@ def determine_packages(): packages.extend(determine_packages_arch()) + # LP#1806830 - ensure that multipath packages are installed when + # use-multipath option is enabled. + if config('use-multipath'): + packages.extend(MULTIPATH_PACKAGES) + if cmp_release >= 'rocky': packages = [p for p in packages if not p.startswith('python-')] packages.extend(PY3_PACKAGES) diff --git a/unit_tests/test_nova_compute_hooks.py b/unit_tests/test_nova_compute_hooks.py index 5b136df9..ff06ac54 100644 --- a/unit_tests/test_nova_compute_hooks.py +++ b/unit_tests/test_nova_compute_hooks.py @@ -258,6 +258,23 @@ class NovaComputeRelationsTests(CharmTestCase): context.exception.message, 'Invalid migration-auth-type') + @patch.object(hooks, 'compute_joined') + def test_config_changed_use_multipath_false(self, + compute_joined): + self.test_config.set('use-multipath', False) + hooks.config_changed() + self.assertEqual(self.filter_installed_packages.call_count, 0) + + @patch.object(hooks, 'compute_joined') + def test_config_changed_use_multipath_true(self, + compute_joined): + self.test_config.set('use-multipath', True) + self.filter_installed_packages.return_value = [] + hooks.config_changed() + self.assertEqual(self.filter_installed_packages.call_count, 1) + self.apt_install.assert_called_with(hooks.MULTIPATH_PACKAGES, + fatal=True) + @patch('nova_compute_hooks.nrpe') @patch('nova_compute_hooks.services') @patch('charmhelpers.core.hookenv') diff --git a/unit_tests/test_nova_compute_utils.py b/unit_tests/test_nova_compute_utils.py index 18beec0c..1d953234 100644 --- a/unit_tests/test_nova_compute_utils.py +++ b/unit_tests/test_nova_compute_utils.py @@ -223,6 +223,34 @@ class NovaComputeUtilsTests(CharmTestCase): result = utils.determine_packages() self.assertTrue('nova-api-metadata' in result) + @patch.object(utils, 'nova_metadata_requirement') + @patch.object(utils, 'neutron_plugin') + @patch.object(utils, 'network_manager') + def test_determine_packages_use_multipath(self, net_man, + n_plugin, en_meta): + self.os_release.return_value = 'ocata' + en_meta.return_value = (False, None) + net_man.return_value = 'bob' + self.test_config.set('use-multipath', True) + self.relation_ids.return_value = [] + result = utils.determine_packages() + for pkg in utils.MULTIPATH_PACKAGES: + self.assertTrue(pkg in result) + + @patch.object(utils, 'nova_metadata_requirement') + @patch.object(utils, 'neutron_plugin') + @patch.object(utils, 'network_manager') + def test_determine_packages_no_multipath(self, net_man, + n_plugin, en_meta): + self.os_release.return_value = 'ocata' + en_meta.return_value = (False, None) + net_man.return_value = 'bob' + self.test_config.set('use-multipath', False) + self.relation_ids.return_value = [] + result = utils.determine_packages() + for pkg in utils.MULTIPATH_PACKAGES: + self.assertFalse(pkg in result) + @patch.object(utils, 'os') @patch.object(utils, 'nova_metadata_requirement') @patch.object(utils, 'network_manager')