diff --git a/cloudinit/config/cc_install_hotplug.py b/cloudinit/config/cc_install_hotplug.py index d6b2a2df449..da98c409dfe 100644 --- a/cloudinit/config/cc_install_hotplug.py +++ b/cloudinit/config/cc_install_hotplug.py @@ -85,11 +85,11 @@ HOTPLUG_UDEV_PATH = "/etc/udev/rules.d/10-cloud-init-hook-hotplug.rules" -HOTPLUG_UDEV_RULES = """\ +HOTPLUG_UDEV_RULES_TEMPLATE = """\ # Installed by cloud-init due to network hotplug userdata ACTION!="add|remove", GOTO="cloudinit_end" LABEL="cloudinit_hook" -SUBSYSTEM=="net", RUN+="/usr/lib/cloud-init/hook-hotplug" +SUBSYSTEM=="net", RUN+="{libexecdir}/hook-hotplug" LABEL="cloudinit_end" """ @@ -129,8 +129,12 @@ def handle(_name, cfg, cloud, log, _args): log.debug("Skipping hotplug install, udevadm not found") return + # This may need to turn into a distro property at some point + libexecdir = "/usr/libexec/cloud-init" + if not os.path.exists(libexecdir): + libexecdir = "/usr/lib/cloud-init" util.write_file( filename=HOTPLUG_UDEV_PATH, - content=HOTPLUG_UDEV_RULES, + content=HOTPLUG_UDEV_RULES_TEMPLATE.format(libexecdir=libexecdir), ) subp.subp(["udevadm", "control", "--reload-rules"]) diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py index d61d280d95d..f2f2343cfa9 100644 --- a/cloudinit/sources/__init__.py +++ b/cloudinit/sources/__init__.py @@ -196,6 +196,7 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta): EventType.BOOT_NEW_INSTANCE, EventType.BOOT, EventType.BOOT_LEGACY, + EventType.HOTPLUG, }} default_update_events = {EventScope.NETWORK: { EventType.BOOT_NEW_INSTANCE, diff --git a/packages/redhat/cloud-init.spec.in b/packages/redhat/cloud-init.spec.in index 22db4b50adb..1491822bba6 100644 --- a/packages/redhat/cloud-init.spec.in +++ b/packages/redhat/cloud-init.spec.in @@ -119,12 +119,6 @@ version_pys=$(cd "$RPM_BUILD_ROOT" && find . -name version.py -type f) ( cd "$RPM_BUILD_ROOT" && sed -i "s,@@PACKAGED_VERSION@@,%{version}-%{release}," $version_pys ) -# patch hotplug /usr/libexec script path -hotplug_file=$(cd "$RPM_BUILD_ROOT" && find . -name 10-cloud-init-hook-hotplug.rules -type f) - -( cd "$RPM_BUILD_ROOT" && - sed -i "s,/usr/lib,%{_libexecdir}," $hotplug_file ) - %clean rm -rf $RPM_BUILD_ROOT @@ -178,7 +172,6 @@ fi %files /lib/udev/rules.d/66-azure-ephemeral.rules -/lib/udev/rules.d/10-cloud-init-hook-hotplug.rules %if "%{init_system}" == "systemd" /usr/lib/systemd/system-generators/cloud-init-generator diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py index f5818a3a189..ad7446f853d 100644 --- a/tests/unittests/test_datasource/test_ovf.py +++ b/tests/unittests/test_datasource/test_ovf.py @@ -518,10 +518,16 @@ def test_get_data_vmware_seed_platform_info(self): 'vmware (%s/seed/ovf-env.xml)' % self.tdir, ds.subplatform) - def test_get_data_vmware_guestinfo_with_network_config(self): + @mock.patch('cloudinit.subp.subp') + @mock.patch('cloudinit.sources.DataSource.persist_instance_data') + def test_get_data_vmware_guestinfo_with_network_config( + self, m_persist, m_subp + ): self._test_get_data_with_network_config(guestinfo=False, iso=True) - def test_get_data_iso9660_with_network_config(self): + @mock.patch('cloudinit.subp.subp') + @mock.patch('cloudinit.sources.DataSource.persist_instance_data') + def test_get_data_iso9660_with_network_config(self, m_persist, m_subp): self._test_get_data_with_network_config(guestinfo=True, iso=False) def _test_get_data_with_network_config(self, guestinfo, iso): diff --git a/tests/unittests/test_handler/test_handler_install_hotplug.py b/tests/unittests/test_handler/test_handler_install_hotplug.py index 19b0cc4113e..5d6b1e7719d 100644 --- a/tests/unittests/test_handler/test_handler_install_hotplug.py +++ b/tests/unittests/test_handler/test_handler_install_hotplug.py @@ -7,7 +7,7 @@ from cloudinit.config.cc_install_hotplug import ( handle, HOTPLUG_UDEV_PATH, - HOTPLUG_UDEV_RULES, + HOTPLUG_UDEV_RULES_TEMPLATE, ) from cloudinit.event import EventScope, EventType @@ -38,7 +38,10 @@ def mocks(): class TestInstallHotplug: - def test_rules_installed_when_supported_and_enabled(self, mocks): + @pytest.mark.parametrize('libexec_exists', [True, False]) + def test_rules_installed_when_supported_and_enabled( + self, mocks, libexec_exists + ): mocks.m_which.return_value = 'udevadm' mocks.m_update_enabled.return_value = True m_cloud = mock.MagicMock() @@ -46,11 +49,17 @@ def test_rules_installed_when_supported_and_enabled(self, mocks): EventScope.NETWORK: {EventType.HOTPLUG} } - handle(None, {}, m_cloud, mock.Mock(), None) - mocks.m_write.assert_called_once_with( - filename=HOTPLUG_UDEV_PATH, - content=HOTPLUG_UDEV_RULES, - ) + if libexec_exists: + libexecdir = "/usr/libexec/cloud-init" + else: + libexecdir = "/usr/lib/cloud-init" + with mock.patch('os.path.exists', return_value=libexec_exists): + handle(None, {}, m_cloud, mock.Mock(), None) + mocks.m_write.assert_called_once_with( + filename=HOTPLUG_UDEV_PATH, + content=HOTPLUG_UDEV_RULES_TEMPLATE.format( + libexecdir=libexecdir), + ) assert mocks.m_subp.call_args_list == [mock.call([ 'udevadm', 'control', '--reload-rules', ])]