فهرست منبع

Move common Debian morphing code to Coriolis core

The code that enables Debian 7 backports is duplicated across
Coriolis providers. So is the method that enables an UEFI
fallback bootloader.

We'll go ahead and move them to Coriolis core. However, the UEFI
fallback bootloader won't be enabled by default since providers
that preserve the firmware type shouldn't actually need it.
Lucian Petrut 1 هفته پیش
والد
کامیت
3f3a6ef5f1
2فایلهای تغییر یافته به همراه186 افزوده شده و 0 حذف شده
  1. 40 0
      coriolis/osmorphing/debian.py
  2. 146 0
      coriolis/tests/osmorphing/test_debian.py

+ 40 - 0
coriolis/osmorphing/debian.py

@@ -2,6 +2,8 @@
 # All Rights Reserved.
 
 from io import StringIO
+import os
+import re
 
 from oslo_log import log as logging
 import yaml
@@ -97,6 +99,42 @@ class BaseDebianMorphingTools(base.BaseLinuxOSMorphingTools):
             }
         return yaml.dump(cfg, default_flow_style=False)
 
+    # NOTE(apilotti): wheezy backports are required in order to install
+    # cloud-init on debian 7
+    def _add_wheezy_backports(self):
+        sources = self._read_file("etc/apt/sources.list")
+        backports = (
+            b"deb http://archive.debian.org/debian wheezy-backports main")
+        regex = b"^" + backports
+
+        repo_found = re.search(regex, sources, flags=re.MULTILINE)
+        if not repo_found:
+            self._event_manager.progress_update("Adding wheezy backports")
+            sources_updated = sources + b"\n" + backports + b"\n"
+            self._write_file_sudo("etc/apt/sources.list", sources_updated)
+            self._exec_cmd_chroot("apt-get update -y")
+
+    def _install_uefi_fallback_bootloader(self):
+        bootloader_dir = "/boot/efi/EFI/BOOT"
+        arch_map = {"x86_64": "BOOTX64.efi"}
+        arch = self._exec_cmd_chroot("uname -m").splitlines()[0]
+        if not arch_map.get(arch):
+            LOG.warning(
+                "Can't create bootloader for "
+                f"unsupported architecture: {arch}")
+            return
+
+        if self._test_path_chroot(os.path.join(bootloader_dir,
+                                  arch_map[arch])):
+            LOG.info("Fallback bootloader exists. Skipping")
+            return
+
+        self._exec_cmd_chroot(
+            f"grub-install --removable --target={arch}-efi "
+            "--efi-directory=/boot/efi --uefi-secure-boot"
+        )
+        self._exec_cmd_chroot("update-grub")
+
     def set_net_config(self, nics_info, dhcp):
         if not dhcp:
             LOG.info("Setting static IP configuration")
@@ -139,6 +177,8 @@ class BaseDebianMorphingTools(base.BaseLinuxOSMorphingTools):
                 self._event_manager.progress_update("Updating packages list")
                 self._exec_cmd_chroot('apt-get clean')
                 self._exec_cmd_chroot('apt-get update -y')
+                if self._version.startswith("7"):
+                    self._add_wheezy_backports()
         except Exception as err:
             raise exception.PackageManagerOperationException(
                 "Failed to refresh apt repositories. Please ensure that *all* "

+ 146 - 0
coriolis/tests/osmorphing/test_debian.py

@@ -252,6 +252,25 @@ class BaseDebianMorphingToolsTestCase(test_base.CoriolisBaseTestCase):
             mock.call('apt-get update -y')
         ])
 
+    @mock.patch.object(base.BaseLinuxOSMorphingTools, 'pre_packages_install')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_add_wheezy_backports')
+    def test_pre_packages_install_wheezy(
+        self,
+        mock_add_wheezy_backports,
+        mock_exec_cmd_chroot,
+        mock_pre_packages_install,
+    ):
+        self.morpher._version = "7"
+        self.morpher.pre_packages_install(self.package_names)
+
+        mock_pre_packages_install.assert_called_once_with(self.package_names)
+        mock_exec_cmd_chroot.assert_has_calls([
+            mock.call('apt-get clean'),
+            mock.call('apt-get update -y')
+        ])
+        mock_add_wheezy_backports.assert_called_once_with()
+
     @mock.patch.object(base.BaseLinuxOSMorphingTools, 'pre_packages_install')
     @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
     def test_pre_packages_install_with_exception(self, mock_exec_cmd_chroot,
@@ -312,3 +331,130 @@ class BaseDebianMorphingToolsTestCase(test_base.CoriolisBaseTestCase):
 
         self.assertRaises(exception.FailedPackageUninstallationException,
                           self.morpher.uninstall_packages, self.package_names)
+
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_read_file')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_write_file_sudo')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
+    def test_add_wheezy_backports(
+        self,
+        mock_exec_cmd_chroot,
+        mock_write_file_sudo,
+        mock_read_file,
+    ):
+        existing_sources = b"""
+deb http://archive.debian.org/debian wheezy main non-free-firmware
+deb http://archive.debian.org/debian wheezy-updates main non-free-firmware
+"""
+        exp_updated_sources = b"""
+deb http://archive.debian.org/debian wheezy main non-free-firmware
+deb http://archive.debian.org/debian wheezy-updates main non-free-firmware
+
+deb http://archive.debian.org/debian wheezy-backports main
+"""
+        mock_read_file.return_value = existing_sources
+
+        self.morpher._add_wheezy_backports()
+
+        mock_read_file.assert_called_once_with("etc/apt/sources.list")
+        mock_write_file_sudo.assert_called_once_with(
+            "etc/apt/sources.list",
+            exp_updated_sources)
+        mock_exec_cmd_chroot.assert_called_once_with("apt-get update -y")
+
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_read_file')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_write_file_sudo')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
+    def test_add_wheezy_backports_already_included(
+        self,
+        mock_exec_cmd_chroot,
+        mock_write_file_sudo,
+        mock_read_file,
+    ):
+        existing_sources = b"""
+deb http://archive.debian.org/debian wheezy main non-free-firmware
+deb http://archive.debian.org/debian wheezy-backports main
+deb http://archive.debian.org/debian wheezy-updates main non-free-firmware
+"""
+        mock_read_file.return_value = existing_sources
+
+        self.morpher._add_wheezy_backports()
+
+        mock_read_file.assert_called_once_with("etc/apt/sources.list")
+        mock_write_file_sudo.assert_not_called()
+        mock_exec_cmd_chroot.assert_not_called()
+
+
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_test_path_chroot')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
+    def test_install_uefi_fallback_bootloader(
+        self,
+        mock_exec_cmd_chroot,
+        mock_test_path_chroot,
+    ):
+        mock_exec_cmd_chroot.side_effect = [
+            # uname -m
+            "x86_64",
+            # grub-install
+            "",
+            # update-grub
+            "",
+        ]
+        mock_test_path_chroot.return_value = False
+
+        self.morpher._install_uefi_fallback_bootloader()
+
+        mock_exec_cmd_chroot.assert_has_calls([
+            mock.call("uname -m"),
+            mock.call(
+                "grub-install --removable --target=x86_64-efi "
+                "--efi-directory=/boot/efi --uefi-secure-boot"),
+            mock.call("update-grub"),
+        ])
+        mock_test_path_chroot.assert_called_once_with(
+            "/boot/efi/EFI/BOOT/BOOTX64.efi")
+
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_test_path_chroot')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
+    def test_install_uefi_fallback_bootloader_unsupported_arch(
+        self,
+        mock_exec_cmd_chroot,
+        mock_test_path_chroot,
+    ):
+        mock_exec_cmd_chroot.side_effect = [
+            # uname -m
+            "x86",
+            # grub-install
+            "",
+            # update-grub,
+        ]
+        mock_test_path_chroot.return_value = False
+
+        self.morpher._install_uefi_fallback_bootloader()
+
+        mock_exec_cmd_chroot.assert_has_calls([
+            mock.call("uname -m"),
+        ])
+        mock_test_path_chroot.assert_not_called()
+
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_test_path_chroot')
+    @mock.patch.object(debian.BaseDebianMorphingTools, '_exec_cmd_chroot')
+    def test_install_uefi_fallback_bootloader_already_exists(
+        self,
+        mock_exec_cmd_chroot,
+        mock_test_path_chroot,
+    ):
+        mock_exec_cmd_chroot.side_effect = [
+            # uname -m
+            "x86_64",
+            # grub-install, shouldn't get here.
+            IOError,
+        ]
+        mock_test_path_chroot.return_value = True
+
+        self.morpher._install_uefi_fallback_bootloader()
+
+        mock_exec_cmd_chroot.assert_has_calls([
+            mock.call("uname -m"),
+        ])
+        mock_test_path_chroot.assert_called_once_with(
+            "/boot/efi/EFI/BOOT/BOOTX64.efi")