diff options
author | dermotbradley <dermot_bradley@yahoo.com> | 2022-11-08 01:34:06 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-07 19:34:06 -0600 |
commit | 56f2d751f226e19cb26d56bed7c524fdb9557713 (patch) | |
tree | f68087a9830b491c17fef71c892185a37cf03fe9 | |
parent | 699b6a05e20253b3666eb51eb77654741aa7c37d (diff) | |
download | cloud-init-git-56f2d751f226e19cb26d56bed7c524fdb9557713.tar.gz |
udevadm settle should handle non-udev system gracefully (#1806)
Not all Linux systems use udev (and therefore udevadm). Specifically
an Alpine Linux system may have either udev (via "eudev" package)
or mdev, or mdevd installed.
Change the udev_settle function to check for the presence of the
udevadm binary before calling it - if it is not present then
silently exit the function.
This change will enable cloud-init to run on Alpine systems using
mdev/mdevd rather than udev.
-rw-r--r-- | cloudinit/util.py | 4 | ||||
-rw-r--r-- | tests/unittests/test_util.py | 35 |
2 files changed, 29 insertions, 10 deletions
diff --git a/cloudinit/util.py b/cloudinit/util.py index 1fd2c81b..078ce1c2 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -2934,6 +2934,10 @@ def mount_is_read_write(mount_point): def udevadm_settle(exists=None, timeout=None): """Invoke udevadm settle with optional exists and timeout parameters""" + if not subp.which("udevadm"): + # a distro, such as Alpine, may not have udev installed if + # it relies on a udev alternative such as mdev/mdevd. + return settle_cmd = ["udevadm", "settle"] if exists: # skip the settle if the requested path already exists diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index 6dc827c1..0c2735ae 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -822,46 +822,60 @@ class TestBlkid(CiTestCase): ) +@mock.patch("cloudinit.subp.which") @mock.patch("cloudinit.subp.subp") class TestUdevadmSettle(CiTestCase): - def test_with_no_params(self, m_subp): + def test_with_no_params(self, m_which, m_subp): """called with no parameters.""" + m_which.side_effect = lambda m: m in ("udevadm",) util.udevadm_settle() m_subp.called_once_with(mock.call(["udevadm", "settle"])) - def test_with_exists_and_not_exists(self, m_subp): + def test_udevadm_not_present(self, m_which, m_subp): + """where udevadm program does not exist should not invoke subp.""" + m_which.side_effect = lambda m: m in ("",) + util.udevadm_settle() + m_subp.called_once_with(["which", "udevadm"]) + + def test_with_exists_and_not_exists(self, m_which, m_subp): """with exists=file where file does not exist should invoke subp.""" + m_which.side_effect = lambda m: m in ("udevadm",) mydev = self.tmp_path("mydev") util.udevadm_settle(exists=mydev) m_subp.called_once_with( ["udevadm", "settle", "--exit-if-exists=%s" % mydev] ) - def test_with_exists_and_file_exists(self, m_subp): - """with exists=file where file does exist should not invoke subp.""" + def test_with_exists_and_file_exists(self, m_which, m_subp): + """with exists=file where file does exist should only invoke subp + once for 'which' call.""" + m_which.side_effect = lambda m: m in ("udevadm",) mydev = self.tmp_path("mydev") util.write_file(mydev, "foo\n") util.udevadm_settle(exists=mydev) - self.assertIsNone(m_subp.call_args) + m_subp.called_once_with(["which", "udevadm"]) - def test_with_timeout_int(self, m_subp): + def test_with_timeout_int(self, m_which, m_subp): """timeout can be an integer.""" + m_which.side_effect = lambda m: m in ("udevadm",) timeout = 9 util.udevadm_settle(timeout=timeout) m_subp.called_once_with( ["udevadm", "settle", "--timeout=%s" % timeout] ) - def test_with_timeout_string(self, m_subp): + def test_with_timeout_string(self, m_which, m_subp): """timeout can be a string.""" + m_which.side_effect = lambda m: m in ("udevadm",) timeout = "555" util.udevadm_settle(timeout=timeout) - m_subp.assert_called_once_with( + m_subp.called_once_with( ["udevadm", "settle", "--timeout=%s" % timeout] ) - def test_with_exists_and_timeout(self, m_subp): + def test_with_exists_and_timeout(self, m_which, m_subp): """test call with both exists and timeout.""" + m_which.side_effect = lambda m: m in ("udevadm",) mydev = self.tmp_path("mydev") timeout = "3" util.udevadm_settle(exists=mydev) @@ -874,7 +888,8 @@ class TestUdevadmSettle(CiTestCase): ] ) - def test_subp_exception_raises_to_caller(self, m_subp): + def test_subp_exception_raises_to_caller(self, m_which, m_subp): + m_which.side_effect = lambda m: m in ("udevadm",) m_subp.side_effect = subp.ProcessExecutionError("BOOM") self.assertRaises(subp.ProcessExecutionError, util.udevadm_settle) |