From 04c642408bd2bd708d6228666e7dda21017fbc2e Mon Sep 17 00:00:00 2001 From: Lukas Kranz Date: Wed, 18 Oct 2023 09:33:00 +0200 Subject: [PATCH] Use MSFT_NetAdapter to rename adapter Currently renaming the adapter on windows 22 core does not cause an error but also has no effect INFO cloudbaseinit.plugins.common.networkconfig [-] Renaming network adapter "Ethernet" to "some-adapter-name" ... ERROR cloudbaseinit.init cloudbaseinit.exception.ItemNotFoundException: Network interface with name "some-adapter-name" not found Using Win32_NetworkAdapter or netsh for renaming network adapters does not work, although they do not fail, but do no-operation (probably a Windows bug). Fixes: https://github.com/cloudbase/cloudbase-init/issues/101 Change-Id: I6b05b313742dd6ff2553dd67b374a8aa4fefd0a7 Signed-off-by: Adrian Vladu --- cloudbaseinit/osutils/windows.py | 21 ++++++++----- cloudbaseinit/tests/osutils/test_windows.py | 33 ++++++++++++--------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/cloudbaseinit/osutils/windows.py b/cloudbaseinit/osutils/windows.py index 5630d212..c741f578 100644 --- a/cloudbaseinit/osutils/windows.py +++ b/cloudbaseinit/osutils/windows.py @@ -858,17 +858,24 @@ def set_network_adapter_mtu(self, name, mtu): 'value "%(mtu)s" failed' % {'name': name, 'mtu': mtu}) def rename_network_adapter(self, old_name, new_name): - base_dir = self._get_system_dir() - netsh_path = os.path.join(base_dir, 'netsh.exe') - - args = [netsh_path, "interface", "set", "interface", - 'name=%s' % old_name, 'newname=%s' % new_name] - (out, err, ret_val) = self.execute_process(args, shell=False) - if ret_val: + net_adapter = self._get_network_msft_adapter(old_name) + try: + net_adapter.rename(new_name) + self._get_network_msft_adapter(new_name) + except Exception: raise exception.CloudbaseInitException( 'Renaming interface "%(old_name)s" to "%(new_name)s" ' 'failed' % {'old_name': old_name, 'new_name': new_name}) + @staticmethod + def _get_network_msft_adapter(name): + conn = wmi.WMI(moniker='//./root/standardcimv2') + query = conn.MSFT_NetAdapter(Name=name) + if not len(query): + raise exception.CloudbaseInitException( + "MSFT network adapter not found: %s" % name) + return query[0] + @staticmethod def _get_network_adapter(name): conn = wmi.WMI(moniker='//./root/cimv2') diff --git a/cloudbaseinit/tests/osutils/test_windows.py b/cloudbaseinit/tests/osutils/test_windows.py index a9eec533..d793627a 100644 --- a/cloudbaseinit/tests/osutils/test_windows.py +++ b/cloudbaseinit/tests/osutils/test_windows.py @@ -839,28 +839,33 @@ def test_set_static_network_config_ipv6(self): self._test_set_static_network_config(ipv6=True) @mock.patch('cloudbaseinit.osutils.windows.WindowsUtils' - '.execute_process') - @mock.patch('cloudbaseinit.osutils.windows.WindowsUtils' - '._get_system_dir') - def _test_rename_network_adapter(self, should_fail, mock_get_system_dir, - mock_execute_process): - base_dir = "fake path" + '._get_network_msft_adapter') + def _test_rename_network_adapter(self, rename_exception, + mock_get_network_adapter): old_name = "fake_old" new_name = "fake_new" - mock_get_system_dir.return_value = base_dir - ret_val = 1 if should_fail else 0 - mock_execute_process.return_value = (None, None, ret_val) - if should_fail: + adapter = mock.Mock() + adapter.Name = mock.sentinel.old_name + mock_get_network_adapter.return_value = adapter + get_network_adapter_called = 1 + if rename_exception: + adapter.rename.side_effect = Exception("fake exception") with self.assertRaises(exception.CloudbaseInitException): self._winutils.rename_network_adapter(old_name, new_name) else: + get_network_adapter_called = 2 self._winutils.rename_network_adapter(old_name, new_name) - mock_get_system_dir.assert_called_once_with() - args = [os.path.join(base_dir, "netsh.exe"), "interface", "set", - "interface", 'name=%s' % old_name, 'newname=%s' % new_name] - mock_execute_process.assert_called_once_with(args, shell=False) + adapter.rename.assert_called() + + self.assertEqual(mock_get_network_adapter.call_count, + get_network_adapter_called) + self.assertEqual(mock_get_network_adapter.call_args_list[0].args, + (old_name,)) + if not exception: + self.assertEqual(mock_get_network_adapter.call_args_list[1].args, + (new_name,)) def _test_get_config_key_name(self, section): response = self._winutils._get_config_key_name(section)