← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~jasonzio/cloud-init:requestMountAll into cloud-init:master


Jason Zions has proposed merging ~jasonzio/cloud-init:requestMountAll into cloud-init:master.

Commit message:
cc_mounts: Do mount-a if datasource metadata requests it

Under some circumstances, cc_disk_setup may reformat volumes which already appear in /etc/fstab (e.g. Azure ephemeral drive is reformatted from NTFS to ext4 after service-heal). Normally, cc_mounts only calls mount -a if it altered /etc/fstab. With this change, a module or datasource can request that cc_mounts always does the mount -a operation without regard to whether /etc/fstab was altered by cc_mounts or not. A datasource must indicate its willingness to permit this by adding the key "request_mountall" to its metadata dictionary. That key must be present and its value must evaluate as True to trigger the always-mount action.

Requested reviews:
  cloud-init commiters (cloud-init-dev)
Related bugs:
  Bug #1825596 in cloud-init: "Azure reboot with unformatted ephemeral drive won't mount reformatted volume"

For more details, see:
Your team cloud-init commiters is requested to review the proposed merge of ~jasonzio/cloud-init:requestMountAll into cloud-init:master.
diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py
index 29e192e..151d25e 100644
--- a/cloudinit/config/cc_disk_setup.py
+++ b/cloudinit/config/cc_disk_setup.py
@@ -156,6 +156,10 @@ def handle(_name, cfg, cloud, log, _args):
                               msg="Creating fs for %s" % device,
                               func=mkfs, args=(definition,))
+                metadata = cloud.datasource.metadata
+                if metadata and 'request_mountall' in metadata:
+                    metadata['request_mountall'] = True
             except Exception as e:
                 util.logexc(LOG, "Failed during filesystem operation\n%s" % e)
diff --git a/cloudinit/config/cc_mounts.py b/cloudinit/config/cc_mounts.py
index 339baba..631c460 100644
--- a/cloudinit/config/cc_mounts.py
+++ b/cloudinit/config/cc_mounts.py
@@ -328,6 +328,14 @@ def handle(_name, cfg, cloud, log, _args):
     LOG.debug("mounts configuration is %s", cfgmnt)
+    do_mountall = False
+    metadata = cloud.datasource.metadata
+    if metadata and 'request_mountall' in metadata:
+        do_mountall = metadata['request_mountall']
+        metadata['request_mountall'] = False
+        if do_mountall:
+            LOG.debug("note: mounts requested by datasource to do mount -a")
     fstab_lines = []
     fstab_devs = {}
     fstab_removed = []
@@ -473,6 +481,9 @@ def handle(_name, cfg, cloud, log, _args):
         log.debug("No changes to /etc/fstab made.")
         log.debug("Changes to fstab: %s", sops)
+        do_mountall = True
+    if do_mountall:
         activate_cmds.append(["mount", "-a"])
         if uses_systemd:
             activate_cmds.append(["systemctl", "daemon-reload"])
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
index 6416525..048b68f 100755
--- a/cloudinit/sources/DataSourceAzure.py
+++ b/cloudinit/sources/DataSourceAzure.py
@@ -33,7 +33,8 @@ from cloudinit.sources.helpers.azure import (azure_ds_reporter,
 LOG = logging.getLogger(__name__)
 DS_NAME = 'Azure'
-DEFAULT_METADATA = {"instance-id": "iid-AZURE-NODE"}
+DEFAULT_METADATA = {"instance-id": "iid-AZURE-NODE",
+                    "request_mountall": False}
 AGENT_START = ['service', 'walinuxagent', 'start']
 AGENT_START_BUILTIN = "__builtin__"
diff --git a/tests/unittests/test_handler/test_handler_mounts.py b/tests/unittests/test_handler/test_handler_mounts.py
index 8fea6c2..6a914ba 100644
--- a/tests/unittests/test_handler/test_handler_mounts.py
+++ b/tests/unittests/test_handler/test_handler_mounts.py
@@ -159,6 +159,8 @@ class TestFstabHandling(test_helpers.FilesystemMockingTestCase):
         self.mock_cloud = mock.Mock()
         self.mock_log = mock.Mock()
         self.mock_cloud.device_name_to_device = self.device_name_to_device
+        self.mock_cloud.datasource = mock.Mock()
+        self.mock_cloud.datasource.metadata = {}
     def _makedirs(self, directory):
         directory = os.path.join(self.new_root, directory.lstrip('/'))

Follow ups