Skip to content
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
60 changes: 59 additions & 1 deletion coriolis/osmorphing/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
INTERFACES_PATH_FORMAT = (
"HKLM:\\%s\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces")

DEVICE_CLASS_BASE_PATH_FORMAT = (
"HKLM:\\%s\\ControlSet001\\Control\\Network")

STATIC_IP_SCRIPT_TEMPLATE = """
$ErrorActionPreference = "Stop"

Expand Down Expand Up @@ -175,6 +178,16 @@
Set-DnsClientServerAddress -InterfaceIndex $interface.IfIndex -ResetServerAddresses

Set-IPAddresses $interface $nic.ip_addresses $ips_info

if ($nic.PSObject.Properties['interface_name'] -and $nic.interface_name) {
$conflictAdapter = Get-NetAdapter -Name $nic.interface_name -ErrorAction SilentlyContinue
if ($conflictAdapter -and $conflictAdapter.IfIndex -ne $interface.IfIndex) {
Write-Host "Removing conflicting adapter '$($conflictAdapter.Name)' to free up name '$($nic.interface_name)'"
Remove-NetAdapter -Name $conflictAdapter.Name -Confirm:$false
}
Rename-NetAdapter -Name $interface.Name -NewName $nic.interface_name
Write-Host "Renamed network adapter '$($interface.Name)' to '$($nic.interface_name)'"
}
}
}

Expand Down Expand Up @@ -599,12 +612,41 @@ def _install_cloudbase_init(self, download_url,

return cloudbaseinit_base_dir

def _get_guid_to_adapter_info_map(self, key_name):
network_base_path = DEVICE_CLASS_BASE_PATH_FORMAT % key_name
ps_command = (
"$ErrorActionPreference = 'SilentlyContinue'; "
"$networkBase = '%(base)s'; "
"Get-ChildItem -Path $networkBase | "
"ForEach-Object { $classPath = $_.PSPath; "
"Get-ChildItem -Path $classPath | "
"ForEach-Object { $netGuid = $_.PSChildName; "
"$connPath = \"$classPath\\$netGuid\\Connection\"; "
"$p = Get-ItemProperty -Path $connPath; "
"if ($p.Name) { \"$netGuid|$($p.Name)\" } } }; "
"exit 0" % {'base': network_base_path})
result = self._conn.exec_ps_command(ps_command)
Comment thread
mihaelabalutoiu marked this conversation as resolved.
LOG.debug(
"GUID-to-adapter-info PS command output: %s", result)
guid_map = {}
for line in result.splitlines():
if '|' in line:
parts = line.split('|', 1)
guid = parts[0].strip().upper()
name = parts[1].strip()
guid_map[guid] = {'interface_name': name}
LOG.debug(
"Found interface name '%s' for adapter GUID '%s'",
name, guid)
return guid_map

def _compile_static_ip_conf_from_registry(self, key_name):
ips_info = []
interfaces_reg_path = INTERFACES_PATH_FORMAT % key_name
interfaces = self._conn.exec_ps_command(
"(((Get-ChildItem -Path '%s').Name | Select-String -Pattern "
"'[^\\\\]+$').Matches).Value" % interfaces_reg_path)
guid_to_adapter_info = self._get_guid_to_adapter_info_map(key_name)
for interface in interfaces.splitlines():
reg_path = '%s\\%s' % (interfaces_reg_path, interface)
enable_dhcp = self._conn.exec_ps_command(
Expand All @@ -630,11 +672,20 @@ def _compile_static_ip_conf_from_registry(self, key_name):
prefix_lengths.append(
ipaddress.IPv4Network((0, submask)).prefixlen)

adapter_info = guid_to_adapter_info.get(interface.upper(), {})
interface_name = adapter_info.get('interface_name', '')
if not interface_name:
LOG.warning(
"Could not find interface name for interface GUID "
"'%s'. Adapter name will not be preserved."
% interface)

ip_info = {
"ip_addresses": ip_addresses.splitlines(),
"prefix_lengths": prefix_lengths,
"default_gateway": default_gateway,
"dns_addresses": name_server}
"dns_addresses": name_server,
"interface_name": interface_name}
LOG.debug(
"Found static IP configuration for interface '%s': "
"%s" % (interface, ip_info))
Expand Down Expand Up @@ -678,6 +729,13 @@ def _get_static_nics_info(self, nics_info, ips_info):
f"NIC ({nic.get('mac_address')}). Skipping")
continue
static_nic['ip_addresses'] = ip_matches
for ip_info in ips_info:
if set(static_nic['ip_addresses']).intersection(
set(ip_info.get('ip_addresses', []))):
interface_name = ip_info.get('interface_name')
if interface_name:
static_nic['interface_name'] = interface_name
break
static_nics_info.append(static_nic)

return static_nics_info
Expand Down
51 changes: 50 additions & 1 deletion coriolis/tests/osmorphing/test_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,8 +677,23 @@ def test_install_cloudbase_init_existing_service(
"HKLM\\%s" % mock_uuid4.return_value)

def test__compile_static_ip_conf_from_registry(self):
network_base_path = (windows.DEVICE_CLASS_BASE_PATH_FORMAT %
mock.sentinel.key_name)
adapter_map_ps_cmd = (
"$ErrorActionPreference = 'SilentlyContinue'; "
"$networkBase = '%(base)s'; "
"Get-ChildItem -Path $networkBase | "
"ForEach-Object { $classPath = $_.PSPath; "
"Get-ChildItem -Path $classPath | "
"ForEach-Object { $netGuid = $_.PSChildName; "
"$connPath = \"$classPath\\$netGuid\\Connection\"; "
"$p = Get-ItemProperty -Path $connPath; "
"if ($p.Name) { \"$netGuid|$($p.Name)\" } } }; "
"exit 0" % {'base': network_base_path})

self.conn.exec_ps_command.side_effect = [
'interface1\ninterface2',
'',
'0',
'192.168.1.254',
'8.8.8.8',
Expand All @@ -696,6 +711,7 @@ def test__compile_static_ip_conf_from_registry(self):
mock.call(
"(((Get-ChildItem -Path '%s').Name | Select-String -Pattern "
"'[^\\\\]+$').Matches).Value" % interfaces_reg_path),
mock.call(adapter_map_ps_cmd),
mock.call(
"(Get-ItemProperty -Path '%s\\interface1').EnableDHCP" %
interfaces_reg_path),
Expand All @@ -720,13 +736,29 @@ def test__compile_static_ip_conf_from_registry(self):
{"ip_addresses": ['192.168.1.1'],
"prefix_lengths": [24],
"default_gateway": '192.168.1.254',
"dns_addresses": '8.8.8.8'}
"dns_addresses": '8.8.8.8',
"interface_name": ''}
]
self.assertEqual(result, expected_ips_info)

def test_compile_static_ip_conf_from_registry_no_ip_or_subnet(self):
network_base_path = (windows.DEVICE_CLASS_BASE_PATH_FORMAT %
mock.sentinel.key_name)
adapter_map_ps_cmd = (
"$ErrorActionPreference = 'SilentlyContinue'; "
"$networkBase = '%(base)s'; "
"Get-ChildItem -Path $networkBase | "
"ForEach-Object { $classPath = $_.PSPath; "
"Get-ChildItem -Path $classPath | "
"ForEach-Object { $netGuid = $_.PSChildName; "
"$connPath = \"$classPath\\$netGuid\\Connection\"; "
"$p = Get-ItemProperty -Path $connPath; "
"if ($p.Name) { \"$netGuid|$($p.Name)\" } } }; "
"exit 0" % {'base': network_base_path})

self.conn.exec_ps_command.side_effect = [
'interface1',
'',
'0',
"default_gateway",
"nameservers",
Expand All @@ -745,6 +777,7 @@ def test_compile_static_ip_conf_from_registry_no_ip_or_subnet(self):
mock.call(
"(((Get-ChildItem -Path '%s').Name | Select-String -Pattern "
"'[^\\\\]+$').Matches).Value" % interfaces_reg_path),
mock.call(adapter_map_ps_cmd),
mock.call("(Get-ItemProperty -Path '%s\\interface1').EnableDHCP" %
interfaces_reg_path),
mock.call(
Expand All @@ -760,8 +793,23 @@ def test_compile_static_ip_conf_from_registry_no_ip_or_subnet(self):
])

def test_compile_static_ip_conf_from_registry_no_static_ip(self):
network_base_path = (windows.DEVICE_CLASS_BASE_PATH_FORMAT %
mock.sentinel.key_name)
adapter_map_ps_cmd = (
"$ErrorActionPreference = 'SilentlyContinue'; "
"$networkBase = '%(base)s'; "
"Get-ChildItem -Path $networkBase | "
"ForEach-Object { $classPath = $_.PSPath; "
"Get-ChildItem -Path $classPath | "
"ForEach-Object { $netGuid = $_.PSChildName; "
"$connPath = \"$classPath\\$netGuid\\Connection\"; "
"$p = Get-ItemProperty -Path $connPath; "
"if ($p.Name) { \"$netGuid|$($p.Name)\" } } }; "
"exit 0" % {'base': network_base_path})

self.conn.exec_ps_command.side_effect = [
'interface1',
'',
'1',
]
interfaces_reg_path = (windows.INTERFACES_PATH_FORMAT %
Expand All @@ -775,6 +823,7 @@ def test_compile_static_ip_conf_from_registry_no_static_ip(self):
mock.call(
"(((Get-ChildItem -Path '%s').Name | Select-String -Pattern "
"'[^\\\\]+$').Matches).Value" % interfaces_reg_path),
mock.call(adapter_map_ps_cmd),
mock.call("(Get-ItemProperty -Path '%s\\interface1').EnableDHCP" %
interfaces_reg_path),
])
Expand Down
Loading