diff --git a/coriolis/osmorphing/base.py b/coriolis/osmorphing/base.py index fbf7445e..fa1ecb1c 100644 --- a/coriolis/osmorphing/base.py +++ b/coriolis/osmorphing/base.py @@ -78,6 +78,10 @@ def check_os_supported(cls, detected_os_info): "OS compatibility check not implemented for tools class %s" % ( cls.__name__)) + @abc.abstractmethod + def get_installed_packages(self, package_name): + pass + @abc.abstractmethod def set_net_config(self, nics_info, dhcp): pass @@ -121,6 +125,7 @@ def set_environment(self, environment): class BaseLinuxOSMorphingTools(BaseOSMorphingTools): _packages = {} + installed_packages = [] def __init__(self, conn, os_root_dir, os_root_dev, hypervisor, event_manager, detected_os_info, osmorphing_parameters, diff --git a/coriolis/osmorphing/coreos.py b/coriolis/osmorphing/coreos.py index 4cc3628c..30c9d056 100644 --- a/coriolis/osmorphing/coreos.py +++ b/coriolis/osmorphing/coreos.py @@ -14,6 +14,9 @@ def check_os_supported(cls, detected_os_info): return True return False + def get_installed_package(self): + pass + def disable_predictable_nic_names(self): pass diff --git a/coriolis/osmorphing/debian.py b/coriolis/osmorphing/debian.py index 6f87c1ef..a376ab4d 100644 --- a/coriolis/osmorphing/debian.py +++ b/coriolis/osmorphing/debian.py @@ -122,6 +122,14 @@ def set_net_config(self, nics_info, dhcp): cfg_name = "%s/coriolis_netplan.yaml" % netplan_base self._write_file_sudo(cfg_name, new_cfg) + def get_installed_packages(self): + cmd = "dpkg-query -f '${binary:Package}\\n' -W" + try: + self.installed_packages = self._exec_cmd_chroot( + cmd).decode('utf-8').splitlines() + except exception.CoriolisException: + pass + def pre_packages_install(self, package_names): super(BaseDebianMorphingTools, self).pre_packages_install( package_names) diff --git a/coriolis/osmorphing/manager.py b/coriolis/osmorphing/manager.py index bf900d03..50493b8a 100644 --- a/coriolis/osmorphing/manager.py +++ b/coriolis/osmorphing/manager.py @@ -239,6 +239,11 @@ def morph_image(origin_provider, destination_provider, connection_info, LOG.info("Post packages uninstall") export_os_morphing_tools.post_packages_uninstall(packages_remove) + LOG.info("Checking for packages already installed") + import_os_morphing_tools.get_installed_packages() + packages_add = list( + set(packages_add) - set(import_os_morphing_tools.installed_packages)) + LOG.info("Pre packages install") import_os_morphing_tools.pre_packages_install(packages_add) diff --git a/coriolis/osmorphing/openwrt.py b/coriolis/osmorphing/openwrt.py index 63acbbf0..c0b9afae 100644 --- a/coriolis/osmorphing/openwrt.py +++ b/coriolis/osmorphing/openwrt.py @@ -17,6 +17,9 @@ def check_os_supported(cls, detected_os_info): return True return False + def get_installed_package(self): + pass + def disable_predictable_nic_names(self): pass diff --git a/coriolis/osmorphing/redhat.py b/coriolis/osmorphing/redhat.py index 7d0fa93f..1abf523f 100644 --- a/coriolis/osmorphing/redhat.py +++ b/coriolis/osmorphing/redhat.py @@ -209,15 +209,14 @@ def set_net_config(self, nics_info, dhcp): mac_addresses) self._add_net_udev_rules(net_ifaces_info) - def _has_package_installed(self, package_name): - cmd = 'rpm -q %s' % ("".join(package_name)) + def get_installed_packages(self): + cmd = 'rpm -qa --qf "%{NAME}\\n"' try: - self._exec_cmd_chroot(cmd) - return True + self.installed_packages = self._exec_cmd_chroot( + cmd).decode('utf-8').splitlines() except exception.CoriolisException: - LOG.warning(f"Package ${package_name} is not installed") + LOG.warning("Failed to get installed packages") LOG.trace(utils.get_exception_details()) - return False def _yum_install(self, package_names, enable_repos=[]): try: @@ -295,7 +294,7 @@ def pre_packages_install(self, package_names): super(BaseRedHatMorphingTools, self).pre_packages_install( package_names) self._yum_clean_all() - if not self._has_package_installed('grubby'): + if 'grubby' not in self.installed_packages: self._yum_install(['grubby']) else: LOG.debug("Skipping package 'grubby' as it's already installed") diff --git a/coriolis/osmorphing/suse.py b/coriolis/osmorphing/suse.py index 5ef6bda0..7da4f06d 100644 --- a/coriolis/osmorphing/suse.py +++ b/coriolis/osmorphing/suse.py @@ -65,6 +65,15 @@ def set_net_config(self, nics_info, dhcp): # TODO(alexpilotti): add networking support pass + def get_installed_packages(self): + cmd = 'rpm -qa --qf "%{NAME}\\n"' + try: + self.installed_packages = self._exec_cmd_chroot( + cmd).decode('utf-8').splitlines() + except exception.CoriolisException: + LOG.warning("Failed to get installed packages") + LOG.trace(utils.get_exception_details()) + def get_update_grub2_command(self): location = self._get_grub2_cfg_location() return "grub2-mkconfig -o %s" % location diff --git a/coriolis/osmorphing/windows.py b/coriolis/osmorphing/windows.py index 1a060912..8c8f707b 100644 --- a/coriolis/osmorphing/windows.py +++ b/coriolis/osmorphing/windows.py @@ -610,6 +610,9 @@ def set_net_config(self, nics_info, dhcp): def get_packages(self): return [], [] + def get_installed_packages(self): + pass + def pre_packages_install(self, package_names): pass diff --git a/coriolis/tests/osmorphing/test_base.py b/coriolis/tests/osmorphing/test_base.py index eb70d02a..f942881d 100644 --- a/coriolis/tests/osmorphing/test_base.py +++ b/coriolis/tests/osmorphing/test_base.py @@ -110,6 +110,9 @@ class TestLinuxOSMorphingTools(base.BaseLinuxOSMorphingTools): def check_os_supported(self): pass + def get_installed_packages(self): + pass + def install_packages(self): pass diff --git a/coriolis/tests/osmorphing/test_debian.py b/coriolis/tests/osmorphing/test_debian.py index d4c9a0c4..5bac1ec8 100644 --- a/coriolis/tests/osmorphing/test_debian.py +++ b/coriolis/tests/osmorphing/test_debian.py @@ -211,6 +211,33 @@ def test_set_net_config_no_dhcp( mock_write_file_sudo.assert_not_called() mock_exec_cmd_chroot.assert_not_called() + @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') + def test_get_installed_packages(self, mock_exec_cmd_chroot): + mock_exec_cmd_chroot.return_value = \ + "package1\npackage2".encode('utf-8') + + self.morpher.get_installed_packages() + + self.assertEqual( + self.morpher.installed_packages, + ['package1', 'package2'] + ) + mock_exec_cmd_chroot.assert_called_once_with( + "dpkg-query -f '${binary:Package}\\n' -W") + + @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') + def test_get_installed_packages_none(self, mock_exec_cmd_chroot): + mock_exec_cmd_chroot.side_effect = exception.CoriolisException() + + self.morpher.get_installed_packages() + + self.assertEqual( + self.morpher.installed_packages, + [] + ) + mock_exec_cmd_chroot.assert_called_once_with( + "dpkg-query -f '${binary:Package}\\n' -W") + @mock.patch.object(base.BaseLinuxOSMorphingTools, 'pre_packages_install') @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot') def test_pre_packages_install(self, mock_exec_cmd_chroot, diff --git a/coriolis/tests/osmorphing/test_manager.py b/coriolis/tests/osmorphing/test_manager.py index fd425b24..2012e413 100644 --- a/coriolis/tests/osmorphing/test_manager.py +++ b/coriolis/tests/osmorphing/test_manager.py @@ -153,6 +153,8 @@ def check_os_supported(cls, detected_os_info): self.assertIsNone(result) class MockOSMorphingToolsClass: + installed_packages = [] + def __init__(self, *args, **kwargs): pass @@ -174,6 +176,9 @@ def post_packages_uninstall(self, packages_remove): def pre_packages_install(self, packages_add): pass + def get_installed_packages(self): + pass + def set_net_config(self, nics_info, dhcp): pass diff --git a/coriolis/tests/osmorphing/test_openwrt.py b/coriolis/tests/osmorphing/test_openwrt.py index 783f8540..bcd72e75 100644 --- a/coriolis/tests/osmorphing/test_openwrt.py +++ b/coriolis/tests/osmorphing/test_openwrt.py @@ -9,6 +9,9 @@ class MockOpenWRTMorphingTools(openwrt.BaseOpenWRTMorphingTools): def __init__(self): pass + def get_installed_packages(self): + pass + def install_packages(self, packages): pass diff --git a/coriolis/tests/osmorphing/test_redhat.py b/coriolis/tests/osmorphing/test_redhat.py index c624969e..e916896b 100644 --- a/coriolis/tests/osmorphing/test_redhat.py +++ b/coriolis/tests/osmorphing/test_redhat.py @@ -364,27 +364,33 @@ def test_set_net_config_no_dhcp( mock_get_net_ifaces_info.return_value) @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') - def test_has_package_installed(self, mock_exec_cmd_chroot): - result = self.morphing_tools._has_package_installed("mock_package") + def test_get_installed_packages(self, mock_exec_cmd_chroot): + mock_exec_cmd_chroot.return_value = \ + "package1\npackage2".encode('utf-8') + + self.morphing_tools.get_installed_packages() self.assertEqual( - True, - result + self.morphing_tools.installed_packages, + ['package1', 'package2'] ) - mock_exec_cmd_chroot.assert_called_once_with("rpm -q mock_package") + mock_exec_cmd_chroot.assert_called_once_with( + 'rpm -qa --qf "%{NAME}\\n"') - mock_exec_cmd_chroot.reset_mock() + @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') + def test_get_installed_packages_none(self, mock_exec_cmd_chroot): mock_exec_cmd_chroot.side_effect = exception.CoriolisException() with self.assertLogs( 'coriolis.osmorphing.redhat', level=logging.DEBUG): - result = self.morphing_tools._has_package_installed("mock_package") + self.morphing_tools.get_installed_packages() self.assertEqual( - False, - result + self.morphing_tools.installed_packages, + [] ) - mock_exec_cmd_chroot.assert_called_once_with("rpm -q mock_package") + mock_exec_cmd_chroot.assert_called_once_with( + 'rpm -qa --qf "%{NAME}\\n"') @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') def test__yum_install(self, mock_exec_cmd_chroot): @@ -472,15 +478,12 @@ def test__find_yum_repos_not_found(self, mock_read_file, mock_list_dir): with self.assertLogs('coriolis.osmorphing.redhat', level=logging.WARN): self.morphing_tools._find_yum_repos(repos_to_enable) - @mock.patch.object(redhat.BaseRedHatMorphingTools, - '_has_package_installed') @mock.patch.object(redhat.BaseRedHatMorphingTools, '_yum_install') @mock.patch.object(redhat.BaseRedHatMorphingTools, '_yum_clean_all') @mock.patch.object(base.BaseLinuxOSMorphingTools, 'pre_packages_install') def test_pre_packages_install(self, mock_pre_packages_install, - mock_yum_clean_all, mock_yum_install, - mock_has_package_installed): - mock_has_package_installed.return_value = False + mock_yum_clean_all, mock_yum_install): + self.morphing_tools.installed_packages = [] self.morphing_tools.pre_packages_install(self.package_names) @@ -488,15 +491,12 @@ def test_pre_packages_install(self, mock_pre_packages_install, mock_yum_clean_all.assert_called_once() mock_yum_install.assert_called_once_with(['grubby']) - @mock.patch.object(redhat.BaseRedHatMorphingTools, - '_has_package_installed') @mock.patch.object(redhat.BaseRedHatMorphingTools, '_yum_install') @mock.patch.object(redhat.BaseRedHatMorphingTools, '_yum_clean_all') @mock.patch.object(base.BaseLinuxOSMorphingTools, 'pre_packages_install') def test_pre_packages_install_has_grubby( - self, mock_pre_packages_install, mock_yum_clean_all, mock_yum_install, - mock_has_package_installed): - mock_has_package_installed.return_value = True + self, mock_pre_packages_install, mock_yum_clean_all, mock_yum_install): + self.morphing_tools.installed_packages = ['grubby'] self.morphing_tools.pre_packages_install(self.package_names) diff --git a/coriolis/tests/osmorphing/test_suse.py b/coriolis/tests/osmorphing/test_suse.py index 765d5dff..f1ca436b 100644 --- a/coriolis/tests/osmorphing/test_suse.py +++ b/coriolis/tests/osmorphing/test_suse.py @@ -76,6 +76,35 @@ def test_check_os_not_supported(self): self.assertFalse(result) + @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') + def test_get_installed_packages(self, mock_exec_cmd_chroot): + mock_exec_cmd_chroot.return_value = \ + "package1\npackage2".encode('utf-8') + + self.morphing_tools.get_installed_packages() + + self.assertEqual( + self.morphing_tools.installed_packages, + ['package1', 'package2'] + ) + mock_exec_cmd_chroot.assert_called_once_with( + 'rpm -qa --qf "%{NAME}\\n"') + + @mock.patch.object(base.BaseLinuxOSMorphingTools, '_exec_cmd_chroot') + def test_get_installed_packages_none(self, mock_exec_cmd_chroot): + mock_exec_cmd_chroot.side_effect = exception.CoriolisException() + + with self.assertLogs( + 'coriolis.osmorphing.suse', level=logging.DEBUG): + self.morphing_tools.get_installed_packages() + + self.assertEqual( + self.morphing_tools.installed_packages, + [] + ) + mock_exec_cmd_chroot.assert_called_once_with( + 'rpm -qa --qf "%{NAME}\\n"') + @mock.patch.object( suse.BaseSUSEMorphingTools, '_get_grub2_cfg_location' )