Просмотр исходного кода

first-boot scripts: allow specifying a file name

Lucian Petrut 2 недель назад
Родитель
Сommit
cb831fb859

+ 30 - 7
coriolis/osmorphing/base.py

@@ -58,11 +58,13 @@ run_scripts /usr/lib/coriolis/firstboot/service
 run_scripts /usr/lib/coriolis/firstboot/user
 
 if [ $first_error -eq 0 ]; then
-    echo "All the scripts completed successfully, creating /var/lib/coriolis/firstboot-complete"
+    echo "All the scripts completed successfully."
+    echo "Creating /var/lib/coriolis/firstboot-complete"
     mkdir -p /var/lib/coriolis
     touch /var/lib/coriolis/firstboot-complete
 else
-    echo "One of the scripts failed, won't create /var/lib/coriolis/firstboot-complete"
+    echo "One of the scripts failed."
+    echo "Won't create /var/lib/coriolis/firstboot-complete"
 fi
 
 exit $first_error
@@ -168,8 +170,23 @@ class BaseOSMorphingTools(object, with_metaclass(abc.ABCMeta)):
         self,
         script: str,
         index: int = 0,
-        user_provided=True,
+        user_provided: bool = True,
+        script_filename: str | None = None,
     ):
+        """Register a script to be executed during the first replica boot.
+
+        :param script: the script content
+        :param index: script execution index (0-99), used as a script filename
+                      prefix. The scripts will be executed in alphabetic order,
+                      the Coriolis scripts first and then user provided scripts
+                      afterwards.
+        :param user_provider: whether this is a Coriolis internal script
+                              (executed first) or user provided script.
+        :param script_filename: optional script filename. The index parameter
+                                will be ignored when explicitly specifying
+                                the filename. Coriolis internal scripts should
+                                specify a filename to facilitate debugging.
+        """
         pass
 
     @abc.abstractmethod
@@ -796,9 +813,11 @@ class BaseLinuxOSMorphingTools(BaseOSMorphingTools):
         self,
         script: str,
         index: int = 0,
-        user_provided=True,
+        user_provided: bool = True,
+        script_filename: str | None = None,
     ):
-        if len(script) == 0:
+
+        if not script:
             LOG.debug("Empty first-boot script, skipping...")
             return
 
@@ -806,8 +825,12 @@ class BaseLinuxOSMorphingTools(BaseOSMorphingTools):
             script_dir = "/usr/lib/coriolis/firstboot/user"
         else:
             script_dir = "/usr/lib/coriolis/firstboot/service"
-        unique_id = str(uuid.uuid4()).split("-")[0]
-        script_path = os.path.join(script_dir, f"{index:02d}-{unique_id}.sh")
+
+        if not script_filename:
+            unique_id = str(uuid.uuid4()).split("-")[0]
+            script_filename = f"{index:02d}-{unique_id}.sh"
+
+        script_path = os.path.join(script_dir, script_filename)
 
         self._exec_cmd_chroot(f"mkdir -p {script_dir}")
         self._write_file_sudo(script_path, script)

+ 7 - 5
coriolis/osmorphing/windows.py

@@ -733,9 +733,10 @@ class BaseWindowsMorphingTools(base.BaseOSMorphingTools):
         self,
         script: str,
         index: int = 0,
-        user_provided=True,
+        user_provided: bool = True,
+        script_filename: str | None = None,
     ):
-        if len(script) == 0:
+        if not script:
             LOG.debug("Empty first-boot script, skipping...")
             return
 
@@ -752,9 +753,10 @@ class BaseWindowsMorphingTools(base.BaseOSMorphingTools):
 
         cbslinit_base_dir = self._get_cbslinit_base_dir()
         script_dir = self._get_cbslinit_scripts_dir(cbslinit_base_dir)
-        unique_id = str(uuid.uuid4()).split("-")[0]
-        script_path = os.path.join(
-            script_dir, f"{index:02d}-{unique_id}.ps1")
+        if not script_filename:
+            unique_id = str(uuid.uuid4()).split("-")[0]
+            script_filename = f"{index:02d}-{unique_id}.ps1"
+        script_path = os.path.join(script_dir, script_filename)
 
         self._conn.exec_ps_command(f"mkdir -Force {script_dir}")
         utils.write_winrm_file(

+ 3 - 0
coriolis/tests/integration/deployments/test_osmorphing.py

@@ -184,6 +184,9 @@ class OsMorphingDeploymentTest(integration_base.ReplicaIntegrationTestBase):
                     first_boot_script_path)
                 if payload == first_boot_script:
                     found = True
+                if payload == "should-not-get-executed":
+                    raise AssertionError(
+                        "Linux instance contains Windows script.")
 
         if not found:
             raise AssertionError(

+ 1 - 1
coriolis/tests/osmorphing/test_manager.py

@@ -31,7 +31,7 @@ class ManagerTestCase(test_base.CoriolisBaseTestCase):
             },
             {
                 "phase": constants.PHASE_REPLICA_FIRST_BOOT,
-                "payload": "fist-boot-script",
+                "payload": "first-boot-script",
             },
         ]
 

+ 25 - 0
coriolis/tests/osmorphing/test_windows.py

@@ -964,3 +964,28 @@ class BaseWindowsMorphingToolsTestCase(test_base.CoriolisBaseTestCase):
             self.morphing_tools._conn,
             "C:\\Cloudbase-Init\\LocalScripts/61-37c27abd.ps1",
             mock_script)
+
+    @mock.patch.object(windows.utils, 'write_winrm_file')
+    @mock.patch("uuid.uuid4")
+    def test_register_firstboot_script_explicit_fname(
+        self,
+        mock_uuid,
+        mock_write_winrm_file,
+    ):
+        mock_uuid.return_value = "37c27abd-85ff-4cb8-8d31-4e7067e145ab"
+        mock_script = "mock-script"
+        script_filename = "test-filename.ps1"
+
+        self.morphing_tools.register_firstboot_script(
+            mock_script,
+            index=10,
+            user_provided=True,
+            script_filename=script_filename,
+        )
+
+        self.morphing_tools._conn.exec_ps_command.assert_called_once_with(
+            "mkdir -Force C:\\Cloudbase-Init\\LocalScripts")
+        mock_write_winrm_file.assert_called_once_with(
+            self.morphing_tools._conn,
+            f"C:\\Cloudbase-Init\\LocalScripts/{script_filename}",
+            mock_script)