Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Windows static IP configuration #341

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions coriolis/osmorphing/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from coriolis.osmorphing.osdetect import windows as windows_osdetect
from coriolis import utils


LOG = logging.getLogger(__name__)

WINDOWS_CLIENT_IDENTIFIER = windows_osdetect.WINDOWS_CLIENT_IDENTIFIER
Expand Down Expand Up @@ -562,23 +561,39 @@ def _compile_static_ip_conf_from_registry(self, key_name):

return ips_info

def _check_ips_info(self, nics_info, ips_info):
source_ip_addresses = set()
def _get_static_nics_info(self, nics_info, ips_info):
static_nics_info = []
reg_ip_addresses = set()
for nic in nics_info:
source_ip_addresses.update(nic.get('ip_addresses', []))

for ip_info in ips_info:
if ip_info.get('ip_address'):
reg_ip_addresses.add(ip_info['ip_address'])

diff = source_ip_addresses - reg_ip_addresses
if diff:
raise exception.OSMorphingException(
"The following IP(s): %s found on the source VM's NICs were "
"not found in the registry. Please check whether the static "
"IP configurations on the source machine are properly set up "
"and retry the migration." % diff)
for nic in nics_info:
static_nic = copy.deepcopy(nic)
nic_ips = nic.get('ip_addresses', [])
if not nic_ips:
LOG.warning(
f"Skipping NIC ('{nic.get('mac_address')}'). It has no "
f"detected IP addresses")
continue
diff = set(nic_ips) - reg_ip_addresses
if diff:
LOG.warning(
f"The IP addresses {list(diff)} found on the source "
f"VM's NIC were not found in the registry. These IPs will "
f"be skipped in the static IP configuration process")
ip_matches = list(reg_ip_addresses.intersection(set(nic_ips)))
if not ip_matches:
LOG.warning(
f"Couldn't find any static IP configuration that "
f"matches the addresses {list(nic_ips)} of the source "
f"NIC ({nic.get('mac_address')}). Skipping")
continue
static_nic['ip_addresses'] = ip_matches
static_nics_info.append(static_nic)

return static_nics_info

def _write_static_ip_script(self, base_dir, nics_info, ips_info):
scripts_dir = self._get_cbslinit_scripts_dir(base_dir)
Expand All @@ -601,9 +616,16 @@ def set_net_config(self, nics_info, dhcp):
try:
cbslinit_base_dir = self._get_cbslinit_base_dir()
ips_info = self._compile_static_ip_conf_from_registry(key_name)
self._check_ips_info(nics_info, ips_info)
self._write_static_ip_script(
cbslinit_base_dir, nics_info, ips_info)
LOG.debug(f"Registry static IP configuration: {ips_info}")
static_nics_info = self._get_static_nics_info(nics_info, ips_info)
LOG.debug(f"Detected static NICS info: {static_nics_info}")
if static_nics_info:
self._write_static_ip_script(
cbslinit_base_dir, static_nics_info, ips_info)
else:
LOG.warning(
"No static IP configuration found on the source VM. "
"Static IP configuration will be skipped.")
finally:
self._unload_registry_hive("HKLM\\%s" % key_name)

Expand Down
95 changes: 74 additions & 21 deletions coriolis/tests/osmorphing/test_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,27 +735,32 @@ def test_compile_static_ip_conf_from_registry_no_static_ip(self):
interfaces_reg_path),
])

def test_check_ips_info(self):
def test__get_static_nics_info(self):
# detected static IPs
ips_info = [{"ip_address": "10.0.0.16"},
{"ip_address": "fe80::728a:688:1a92:baec"}]
nics_info = [
{'ip_addresses': [mock.sentinel.ip_address]}
]
ips_info = [
{'ip_address': mock.sentinel.ip_address}
]
self.morphing_tools._check_ips_info(nics_info, ips_info)

def test_check_ips_info_different_ips(self):
nics_info = [
{'ip_addresses': [
mock.sentinel.ip_address, mock.sentinel.ip_address2]}
]
ips_info = [
{'ip_address': mock.sentinel.ip_address}
]
# no IP addresses on NIC
{"ip_addresses": [], "mac_address": "00:50:56:92:91:42"},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values, "00:50:56:92:91:" , ""fe81::728a:688:1a92:baec" .. etc .. can be defined as constants and can be referenced here. As we are using them multiple times.

# dynamic ipv6 IP
{"ip_addresses": ["10.0.0.16", "fe81::728a:688:1a92:baec"],
"mac_address": "00:50:56:92:91:43"},
# both IPs dynamic
{"ip_addresses": ["10.0.1.16", "fe81::728a:688:1a92:baec"],
"mac_address": "00:50:56:92:91:44"},
# dynamic ipv4 IP
{"ip_addresses": ["10.0.1.17", "fe80::728a:688:1a92:baec"],
"mac_address": "00:50:56:92:91:45"}]

expected_result = [
{"mac_address": "00:50:56:92:91:43",
"ip_addresses": ["10.0.0.16"]},
{"mac_address": "00:50:56:92:91:45",
"ip_addresses": ["fe80::728a:688:1a92:baec"]}]

self.assertRaises(exception.OSMorphingException,
self.morphing_tools._check_ips_info,
nics_info, ips_info)
self.assertEqual(
self.morphing_tools._get_static_nics_info(nics_info, ips_info),
expected_result)

@mock.patch.object(windows.utils, 'write_winrm_file')
def test__write_static_ip_script(self, mock_write_winrm_file):
Expand Down Expand Up @@ -786,6 +791,8 @@ def test__write_static_ip_script(self, mock_write_winrm_file):
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_write_static_ip_script'
)
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_get_static_nics_info')
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_unload_registry_hive'
)
Expand All @@ -795,6 +802,7 @@ def test__write_static_ip_script(self, mock_write_winrm_file):
@mock.patch.object(windows.uuid, 'uuid4')
def test_set_net_config(self, mock_uuid4, mock_load_registry_hive,
mock_unload_registry_hive,
mock_get_static_nics_info,
mock_write_static_ip_script,
mock_compile_static_ip_conf_from_registry):
dhcp = False
Expand All @@ -813,13 +821,57 @@ def test_set_net_config(self, mock_uuid4, mock_load_registry_hive,
"%sWindows\\System32\\config\\SYSTEM" % self.os_root_dir)
mock_compile_static_ip_conf_from_registry.assert_called_once_with(
str(mock_uuid4.return_value))
mock_get_static_nics_info.assert_called_once_with(nics_info, ips_info)
mock_write_static_ip_script.assert_called_once_with(
"C:\\Cloudbase-Init",
nics_info,
mock_get_static_nics_info.return_value,
mock_compile_static_ip_conf_from_registry.return_value)
mock_unload_registry_hive.assert_called_once_with(
"HKLM\\%s" % mock_uuid4.return_value)

@mock.patch.object(
windows.BaseWindowsMorphingTools,
'_compile_static_ip_conf_from_registry'
)
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_write_static_ip_script'
)
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_get_static_nics_info')
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_unload_registry_hive'
)
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_load_registry_hive'
)
@mock.patch.object(windows.uuid, 'uuid4')
def test_set_net_config_no_static_info(
self, mock_uuid4, mock_load_registry_hive,
mock_unload_registry_hive, mock_get_static_nics_info,
mock_write_static_ip_script,
mock_compile_static_ip_conf_from_registry):
dhcp = False
nics_info = [
{'ip_addresses': ["10.1.10.10"]}
]
ips_info = [
{'ip_address': "10.1.10.10"}
]
mock_compile_static_ip_conf_from_registry.return_value = ips_info
mock_get_static_nics_info.return_value = []

self.morphing_tools.set_net_config(nics_info, dhcp=dhcp)

mock_load_registry_hive.assert_called_once_with(
"HKLM\\%s" % mock_uuid4.return_value,
"%sWindows\\System32\\config\\SYSTEM" % self.os_root_dir)
mock_compile_static_ip_conf_from_registry.assert_called_once_with(
str(mock_uuid4.return_value))
mock_get_static_nics_info.assert_called_once_with(nics_info, ips_info)
mock_write_static_ip_script.assert_not_called()
mock_unload_registry_hive.assert_called_once_with(
"HKLM\\%s" % mock_uuid4.return_value)

@mock.patch.object(
windows.BaseWindowsMorphingTools, '_get_cbslinit_base_dir'
)
Expand All @@ -836,7 +888,8 @@ def test_set_net_config(self, mock_uuid4, mock_load_registry_hive,
@mock.patch.object(
windows.BaseWindowsMorphingTools, '_load_registry_hive'
)
@mock.patch.object(windows.BaseWindowsMorphingTools, '_check_ips_info')
@mock.patch.object(windows.BaseWindowsMorphingTools,
'_get_static_nics_info')
def test_set_net_config_with_dhcp(
self, mock_check_ips_info, mock_load_registry_hive,
mock_unload_registry_hive, mock_write_static_ip_script,
Expand Down
Loading