From bcc23e70e6748aa7e5b13f666c0a99b34c218f2c Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Fri, 12 Jul 2019 05:36:12 +1000 Subject: [PATCH] win_dns_client - fix bug in devel and added tests (#58971) * win_dns_client - fix bug in devel and added tests * Fix sanity issue --- .../modules/windows/win_dns_client.ps1 | 5 +- .../targets/win_dns_client/aliases | 1 + .../win_dns_client/library/win_device.ps1 | 542 ++++++++++++++++++ .../targets/win_dns_client/tasks/main.yml | 28 + .../targets/win_dns_client/tasks/tests.yml | 178 ++++++ 5 files changed, 752 insertions(+), 2 deletions(-) create mode 100644 test/integration/targets/win_dns_client/aliases create mode 100644 test/integration/targets/win_dns_client/library/win_device.ps1 create mode 100644 test/integration/targets/win_dns_client/tasks/main.yml create mode 100644 test/integration/targets/win_dns_client/tasks/tests.yml diff --git a/lib/ansible/modules/windows/win_dns_client.ps1 b/lib/ansible/modules/windows/win_dns_client.ps1 index bdc9f957e7a6c9..fd885bac85d388 100644 --- a/lib/ansible/modules/windows/win_dns_client.ps1 +++ b/lib/ansible/modules/windows/win_dns_client.ps1 @@ -96,11 +96,12 @@ Function Set-DnsClientServerAddressLegacy { $adapter_config = Get-CIMInstance Win32_NetworkAdapterConfiguration -Filter "Index=$idx" If($ResetServerAddresses) { - $res = $adapter_config.SetDNSServerSearchOrder() + $arguments = @{} } Else { - $res = $adapter_config.SetDNSServerSearchOrder($ServerAddresses) + $arguments = @{ DNSServerSearchOrder = $ServerAddresses } } + $res = Invoke-CimMethod -InputObject $adapter_config -MethodName SetDNSServerSearchOrder -Arguments $arguments If($res.ReturnValue -ne 0) { throw "Set-DnsClientServerAddressLegacy: Error calling SetDNSServerSearchOrder, code $($res.ReturnValue))" diff --git a/test/integration/targets/win_dns_client/aliases b/test/integration/targets/win_dns_client/aliases new file mode 100644 index 00000000000000..423ce3910852af --- /dev/null +++ b/test/integration/targets/win_dns_client/aliases @@ -0,0 +1 @@ +shippable/windows/group2 diff --git a/test/integration/targets/win_dns_client/library/win_device.ps1 b/test/integration/targets/win_dns_client/library/win_device.ps1 new file mode 100644 index 00000000000000..e95d4c818c91a7 --- /dev/null +++ b/test/integration/targets/win_dns_client/library/win_device.ps1 @@ -0,0 +1,542 @@ +#!powershell + +#AnsibleRequires -CSharpUtil Ansible.Basic +#Requires -Module Ansible.ModuleUtils.AddType + +$spec = @{ + options = @{ + hardware_id = @{ type = "str" } + name = @{ type = "str" } + path = @{ type = "path" } + state = @{ type = "str"; choices = @("absent", "present"); default = "present" } + } + required_if = @( + @("state", "present", @("path", "hardware_id"), $true), + @("state", "absent", @(,"name")) + ) + supports_check_mode = $true +} + +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +$hardware_id = $module.Params.hardware_id +$name = $module.Params.name +$path = $module.Params.path +$state = $module.Params.state + +$module.Result.reboot_required = $false + +Add-CSharpType -References @' +using Microsoft.Win32.SafeHandles; +using System; +using System.ComponentModel; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ansible.Device +{ + public class NativeHelpers + { + [StructLayout(LayoutKind.Sequential)] + public class SP_DEVINFO_DATA + { + public UInt32 cbSize; + public Guid ClassGuid; + public UInt32 DevInst; + public IntPtr Reserved; + + public SP_DEVINFO_DATA() + { + this.cbSize = (UInt32)Marshal.SizeOf(this); + this.ClassGuid = Guid.Empty; + } + } + + [Flags] + public enum DeviceInfoCreationFlags : uint + { + DICD_GENERATE_ID = 0x00000001, + DICD_INHERIT_CLASSDRVS = 0x00000002, + } + + public enum DeviceProperty : uint + { + SPDRP_DEVICEDESC = 0x0000000, + SPDRP_HARDWAREID = 0x0000001, + SPDRP_COMPATIBLEIDS = 0x0000002, + SPDRP_UNUSED0 = 0x0000003, + SPDRP_SERVICE = 0x0000004, + SPDRP_UNUSED1 = 0x0000005, + SPDRP_UNUSED2 = 0x0000006, + SPDRP_CLASS = 0x0000007, // Read only - tied to ClassGUID + SPDRP_CLASSGUID = 0x0000008, + SPDRP_DRIVER = 0x0000009, + SPDRP_CONFIGFLAGS = 0x000000a, + SPDRP_MFG = 0x000000b, + SPDRP_FRIENDLYNAME = 0x000000c, + SPDRP_LOCATION_INFORMATION = 0x000000d, + SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x000000e, // Read only + SPDRP_CAPABILITIES = 0x000000f, // Read only + SPDRP_UI_NUMBER = 0x0000010, // Read only + SPDRP_UPPERFILTERS = 0x0000011, + SPDRP_LOWERFILTERS = 0x0000012, + SPDRP_BUSTYPEGUID = 0x0000013, // Read only + SPDRP_LEGACYBUSTYPE = 0x0000014, // Read only + SPDRP_BUSNUMBER = 0x0000015, // Read only + SPDRP_ENUMERATOR_NAME = 0x0000016, // Read only + SPDRP_SECURITY = 0x0000017, + SPDRP_SECURITY_SDS = 0x0000018, + SPDRP_DEVTYPE = 0x0000019, + SPDRP_EXCLUSIVE = 0x000001a, + SPDRP_CHARACTERISTICS = 0x000001b, + SPDRP_ADDRESS = 0x000001c, // Read only + SPDRP_UI_NUMBER_DESC_FORMAT = 0x000001d, + SPDRP_DEVICE_POWER_DATA = 0x000001e, // Read only + SPDRP_REMOVAL_POLICY = 0x000001f, // Read only + SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x0000020, // Read only + SPDRP_REMOVAL_POLICY_OVERRIDE = 0x0000021, + SPDRP_INSTALL_STATE = 0x0000022, // Read only + SPDRP_LOCATION_PATHS = 0x0000023, // Read only + SPDRP_BASE_CONTAINERID = 0x0000024, // Read only + } + + // https://docs.microsoft.com/en-us/previous-versions/ff549793%28v%3dvs.85%29 + public enum DifCodes : uint + { + DIF_SELECTDIVE = 0x00000001, + DIF_INSTALLDEVICE = 0x00000002, + DIF_ASSIGNRESOURCES = 0x00000003, + DIF_PROPERTIES = 0x00000004, + DIF_REMOVE = 0x00000005, + DIF_FIRSTTIMESETUP = 0x00000006, + DIF_FOUNDDEVICE = 0x00000007, + DIF_SELECTCLASSDRIVERS = 0x00000008, + DIF_VALIDATECLASSDRIVERS = 0x00000009, + DIF_INSTALLCLASSDRIVERS = 0x0000000a, + DIF_CALCDISKSPACE = 0x0000000b, + DIF_DESTROYPRIVATEDATA = 0x0000000c, + DIF_VALIDATEDRIVER = 0x0000000d, + DIF_DETECT = 0x0000000f, + DIF_INSTALLWIZARD = 0x00000010, + DIF_DESTROYWIZARDDATA = 0x00000011, + DIF_PROPERTYCHANGE = 0x00000012, + DIF_ENABLECLASS = 0x00000013, + DIF_DETECTVERIFY = 0x00000014, + DIF_INSTALLDEVICEFILES = 0x00000015, + DIF_UNREMOVE = 0x00000016, + DIF_SELECTBESTCOMPATDRV = 0x00000017, + DIF_ALLOW_INSTALL = 0x00000018, + DIF_REGISTERDEVICE = 0x00000019, + DIF_NEWDEVICEWIZARD_PRESELECT = 0x0000001a, + DIF_NEWDEVICEWIZARD_SELECT = 0x0000001b, + DIF_NEWDEVICEWIZARD_PREANALYZE = 0x0000001c, + DIF_NEWDEVICEWIZARD_POSTANALYZE = 0x0000001d, + DIF_NEWDEVICEWIZARD_FINISHINSTALL = 0x0000001e, + DIF_UNUSED1 = 0x0000001e, + DIF_INSTALLINTERFACES = 0x00000020, + DIF_DETECTCANCEL = 0x00000021, + DIF_REGISTER_COINSTALLERS = 0x00000022, + DIF_ADDPROPERTYPAGE_ADVANCED = 0x00000023, + DIF_ADDPROPERTYPAGE_BASIC = 0x00000024, + DIF_RESERVED1 = 0x00000025, + DIF_TROUBLESHOOTER = 0x00000026, + DIF_POWERMESSAGEWAKE = 0x00000027, + DIF_ADDREMOTEPROPERTYPAGE_ADVANCED = 0x00000028, + DIF_UPDATEDRIVER_UI = 0x00000029, + DIF_FINISHINSTALL_ACTION = 0x0000002a, + } + + [Flags] + public enum GetClassFlags : uint + { + DIGCF_DEFAULT = 0x00000001, + DIGCF_PRESENT = 0x00000002, + DIGCF_ALLCLASSES = 0x00000004, + DIGCF_PROFILE = 0x00000008, + DIGCF_DEVICEINTERFACE = 0x00000010, + } + + [Flags] + public enum InstallFlags : uint + { + INSTALLFLAG_FORCE = 0x00000001, + INSTALLFLAG_READONLY = 0x00000002, + INSTALLFLAG_NONINTERACTIVE = 0x00000004, + INSTALLFLAG_BITS = 0x00000007, + } + } + + public class NativeMethods + { + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiCallClassInstaller( + NativeHelpers.DifCodes InstallFunction, + SafeDeviceInfoSet DeviceInfoSet, + NativeHelpers.SP_DEVINFO_DATA DeviceInfoData); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern SafeDeviceInfoSet SetupDiCreateDeviceInfoList( + Guid ClassGuid, + IntPtr hwndParent); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiCreateDeviceInfoW( + SafeDeviceInfoSet DeviceInfoSet, + [MarshalAs(UnmanagedType.LPWStr)] string DeviceName, + Guid ClassGuid, + [MarshalAs(UnmanagedType.LPWStr)] string DeviceDescription, + IntPtr hwndParent, + NativeHelpers.DeviceInfoCreationFlags CreationFlags, + NativeHelpers.SP_DEVINFO_DATA DeviceInfoData); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiDestroyDeviceInfoList( + IntPtr DeviceInfoSet); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiEnumDeviceInfo( + SafeDeviceInfoSet DeviceInfoSet, + UInt32 MemberIndex, + NativeHelpers.SP_DEVINFO_DATA DeviceInfoData); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern SafeDeviceInfoSet SetupDiGetClassDevsW( + Guid ClassGuid, + [MarshalAs(UnmanagedType.LPWStr)] string Enumerator, + IntPtr hwndParent, + NativeHelpers.GetClassFlags Flags); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiGetDeviceRegistryPropertyW( + SafeDeviceInfoSet DeviceInfoSet, + NativeHelpers.SP_DEVINFO_DATA DeviceInfoData, + NativeHelpers.DeviceProperty Property, + out UInt32 PropertyRegDataType, + SafeMemoryBuffer PropertyBuffer, + UInt32 PropertyBufferSize, + ref UInt32 RequiredSize); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiGetINFClassW( + [MarshalAs(UnmanagedType.LPWStr)] string InfName, + ref Guid ClassGuid, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder ClassName, + UInt32 ClassNameSize, + ref UInt32 RequiredSize); + + [DllImport("Setupapi.dll", SetLastError = true)] + public static extern bool SetupDiSetDeviceRegistryPropertyW( + SafeDeviceInfoSet DeviceInfoSet, + NativeHelpers.SP_DEVINFO_DATA DeviceInfoData, + NativeHelpers.DeviceProperty Property, + SafeMemoryBuffer PropertyBuffer, + UInt32 PropertyBufferSize); + + [DllImport("Newdev.dll", SetLastError = true)] + public static extern bool UpdateDriverForPlugAndPlayDevicesW( + IntPtr hwndParent, + [MarshalAs(UnmanagedType.LPWStr)] string HardwareId, + [MarshalAs(UnmanagedType.LPWStr)] string FullInfPath, + NativeHelpers.InstallFlags InstallFlags, + ref bool bRebootRequired); + } + + public class SafeDeviceInfoSet : SafeHandleZeroOrMinusOneIsInvalid + { + public SafeDeviceInfoSet() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + return NativeMethods.SetupDiDestroyDeviceInfoList(handle); + } + } + + public class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid + { + public int Length = 0; + + public SafeMemoryBuffer() : base(true) { } + + public SafeMemoryBuffer(int cb) : base(true) + { + Length = cb; + base.SetHandle(Marshal.AllocHGlobal(cb)); + } + + public SafeMemoryBuffer(string sz) : base(true) + { + Length = sz.Length * sizeof(char); + base.SetHandle(Marshal.StringToHGlobalUni(sz)); + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + Marshal.FreeHGlobal(handle); + return true; + } + } + + public class DeviceUtil + { + public static string GetDeviceFriendlyName(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo) + { + string friendlyName = GetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_FRIENDLYNAME); + + // Older Windows versions may not have a friendly name set. This seems to be the case when the device has + // a unique description so we fallback to that value. + if (null == friendlyName) + friendlyName = GetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_DEVICEDESC); + + return friendlyName; + } + + public static void SetDeviceHardwareId(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo, + string hardwareId) + { + SetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_HARDWAREID, hardwareId); + } + + private static string GetDeviceStringProp(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo, + NativeHelpers.DeviceProperty property) + { + using (SafeMemoryBuffer memBuf = GetDeviceProperty(devInfoSet, devInfo, property)) + { + if (memBuf.IsInvalid) // Property does not exist so just return null. + return null; + + return Marshal.PtrToStringUni(memBuf.DangerousGetHandle()); + } + } + + private static SafeMemoryBuffer GetDeviceProperty(SafeDeviceInfoSet devInfoSet, + NativeHelpers.SP_DEVINFO_DATA devInfo, NativeHelpers.DeviceProperty property) + { + UInt32 requiredSize = 0; + UInt32 regDataType = 0; + if (!NativeMethods.SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfo, property, + out regDataType, new SafeMemoryBuffer(0), 0, ref requiredSize)) + { + int errCode = Marshal.GetLastWin32Error(); + if (errCode == 0x0000000D) // ERROR_INVALID_DATA + return new SafeMemoryBuffer(); // The FRIENDLYNAME property does not exist + else if (errCode != 0x0000007A) // ERROR_INSUFFICIENT_BUFFER + throw new Win32Exception(errCode); + } + + SafeMemoryBuffer memBuf = new SafeMemoryBuffer((int)requiredSize); + if (!NativeMethods.SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfo, property, + out regDataType, memBuf, requiredSize, ref requiredSize)) + { + int errCode = Marshal.GetLastWin32Error(); + memBuf.Dispose(); + + throw new Win32Exception(errCode); + } + + return memBuf; + } + + private static void SetDeviceStringProp(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo, + NativeHelpers.DeviceProperty property, string value) + { + using (SafeMemoryBuffer buffer = new SafeMemoryBuffer(value)) + SetDeviceProperty(devInfoSet, devInfo, property, buffer); + } + + private static void SetDeviceProperty(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo, + NativeHelpers.DeviceProperty property, SafeMemoryBuffer buffer) + { + if (!NativeMethods.SetupDiSetDeviceRegistryPropertyW(devInfoSet, devInfo, property, buffer, + (UInt32)buffer.Length)) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + } +} +'@ + +Function Get-Win32ErrorMessage { + Param ([System.Int32]$ErrorCode) + + $exp = New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $ErrorCode + return ("{0} (Win32 ErrorCode {1} - 0x{1:X8}" -f $exp.Message, $ErrorCode) +} + +# Determine if the device is already installed +$dev_info_set = [Ansible.Device.NativeMethods]::SetupDiGetClassDevsW( + [Guid]::Empty, + [NullString]::Value, + [System.IntPtr]::Zero, + [Ansible.Device.NativeHelpers+GetClassFlags]::DIGCF_ALLCLASSES +); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + +try { + if ($dev_info_set.IsInvalid) { + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to get device information set for installed devices: $msg") + } + + $dev_info = $null + if ($null -ne $name) { + # Loop through the set of all devices and compare the name + $idx = 0 + while ($true) { + $dev_info = New-Object -TypeName Ansible.Device.NativeHelpers+SP_DEVINFO_DATA + $res = [Ansible.Device.NativeMethods]::SetupDiEnumDeviceInfo( + $dev_info_set, + $idx, + $dev_info + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if (-not $res) { + $dev_info = $null + if ($err -eq 0x00000103) { # ERROR_NO_MORE_ITEMS + break + } + + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to enumerate device information set at index $($idx): $msg") + } + + $device_name = [Ansible.Device.DeviceUtil]::GetDeviceFriendlyName($dev_info_set, $dev_info) + if ($device_name -eq $name) { + break + } + + $dev_info = $null + $idx++ + } + } + + if ($state -eq "absent" -and $null -ne $dev_info) { + if (-not $module.CheckMode) { + $res = [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller( + [Ansible.Device.NativeHelpers+DifCodes]::DIF_REMOVE, + $dev_info_set, + $dev_info + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if (-not $res) { + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to remove device $($name): $msg") + } + } + + $module.Result.changed = $true + } elseif ($state -eq "present" -and $null -eq $dev_info) { + # Populate the class guid and display name if the path to an inf file was set. + $class_id = [Guid]::Empty + $class_name = $null + if ($path) { + if (-not (Test-Path -LiteralPath $path)) { + $module.FailJson("Could not find the inf file specified at '$path'") + } + + $class_name_sb = New-Object -TypeName System.Text.StringBuilder -ArgumentList 32 # MAX_CLASS_NAME_LEN + $required_size = 0 + $res = [Ansible.Device.NativeMethods]::SetupDiGetINFClassW( + $path, + [ref]$class_id, + $class_name_sb, + $class_name_sb.Capacity, + [ref]$required_size + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if (-not $res) { + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to parse driver inf at '$path': $msg") + } + + $class_name = $class_name_sb.ToString() + } + + # When creating a new device we want to start with a blank device information set. + $dev_info_set.Dispose() + + $dev_info_set = [Ansible.Device.NativeMethods]::SetupDiCreateDeviceInfoList( + $class_id, + [System.IntPtr]::Zero + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if ($dev_info_set.IsInvalid) { + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to create device info set for the class $($class_id): $msg") + } + + # Create the new device element and add it to the device info set + $dev_info = New-Object -TypeName Ansible.Device.NativeHelpers+SP_DEVINFO_DATA + $res = [Ansible.Device.NativeMethods]::SetupDiCreateDeviceInfoW( + $dev_info_set, + $class_name, + $class_id, + $null, + [System.IntPtr]::Zero, + [Ansible.Device.NativeHelpers+DeviceInfoCreationFlags]::DICD_GENERATE_ID, + $dev_info + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if (-not $res) { + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to create new device element for class $($class_name): $msg") + } + + # Set the hardware id of the new device so we can load the proper driver. + [Ansible.Device.DeviceUtil]::SetDeviceHardwareId($dev_info_set, $dev_info, $hardware_id) + + if (-not $module.CheckMode) { + # Install the device + $res = [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller( + [Ansible.Device.NativeHelpers+DifCodes]::DIF_REGISTERDEVICE, + $dev_info_set, + $dev_info + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if (-not $res) { + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to register new device for class $($class_name): $msg") + } + + # Load the drivers for the new device + $reboot_required = $false + $res = [Ansible.Device.NativeMethods]::UpdateDriverForPlugAndPlayDevicesW( + [System.IntPtr]::Zero, + $hardware_id, + $path, + [Ansible.Device.NativeHelpers+InstallFlags]'INSTALLFLAG_FORCE, INSTALLFLAG_NONINTERACTIVE', + [ref]$reboot_required + ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + + if (-not $res) { + # On a failure make sure we cleanup the "installed" device + [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller( + [Ansible.Device.NativeHelpers+DifCodes]::DIF_REMOVE, + $dev_info_set, + $dev_info + ) > $null + + $msg = Get-Win32ErrorMessage -ErrorCode $err + $module.FailJson("Failed to update device driver: $msg") + } + + $module.Result.reboot_required = $reboot_required + + # Now get the name of the newly created device which we return back to Ansible. + $name = [Ansible.Device.DeviceUtil]::GetDeviceFriendlyName($dev_info_set, $dev_info) + } else { + # Generate random name for check mode output + $name = "Check mode generated device for $($class_name)" + } + $module.Result.changed = $true + } +} finally { + $dev_info_set.Dispose() +} + +$module.Result.name = $name + +$module.ExitJson() + diff --git a/test/integration/targets/win_dns_client/tasks/main.yml b/test/integration/targets/win_dns_client/tasks/main.yml new file mode 100644 index 00000000000000..41660eefe6c71f --- /dev/null +++ b/test/integration/targets/win_dns_client/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: create dummy network adapter device + win_device: + path: '%WinDir%\Inf\netloop.inf' + hardware_id: '*msloop' + state: present + register: test_device_name + +- set_fact: + test_device_name: '{{ test_device_name.name }}' + +- block: + - name: get name of the dummy network adapter + win_shell: (Get-CimInstance -Class Win32_NetworkAdapter -Filter "Name='{{ test_device_name }}'").NetConnectionID + changed_when: False + register: test_adapter + + - set_fact: + test_adapter: '{{ test_adapter.stdout | trim }}' + + - name: run tests + include_tasks: tests.yml + + always: + - name: remove dummy network adapter device + win_device: + name: '{{ test_device_name }}' + state: absent diff --git a/test/integration/targets/win_dns_client/tasks/tests.yml b/test/integration/targets/win_dns_client/tasks/tests.yml new file mode 100644 index 00000000000000..29cf0813bc09d0 --- /dev/null +++ b/test/integration/targets/win_dns_client/tasks/tests.yml @@ -0,0 +1,178 @@ +--- +- set_fact: + get_ip_script: | + $adapter = Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "NetConnectionID='{{ test_adapter }}'" + $config = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=$($adapter.DeviceID)" + $ips = $config.DNSServerSearchOrder + if ($ips) { + $config.DNSServerSearchOrder[0] + $config.DNSServerSearchOrder[1] + } + +- name: set a single IPv4 address (check mode) + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: 192.168.34.5 + register: set_single_check + check_mode: yes + +- name: get result of set a single IPv4 address (check mode) + win_shell: '{{ get_ip_script }}' + changed_when: no + register: set_single_actual_check + +- name: assert set a single IPv4 address (check mode) + assert: + that: + - set_single_check is changed + - set_single_actual_check.stdout_lines == [] + +- name: set a single IPv4 address + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: 192.168.34.5 + register: set_single + +- name: get result of set a single IPv4 address + win_shell: '{{ get_ip_script }}' + changed_when: no + register: set_single_actual + +- name: assert set a single IPv4 address + assert: + that: + - set_single is changed + - set_single_actual.stdout_lines == ["192.168.34.5"] + +- name: set a single IPv4 address (idempotent) + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: 192.168.34.5 + register: set_single_again + +- name: assert set a single IPv4 address (idempotent) + assert: + that: + - not set_single_again is changed + +- name: change IPv4 address to another value (check mode) + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: 192.168.34.6 + register: change_single_check + check_mode: yes + +- name: get result of change IPv4 address to another value (check mode) + win_shell: '{{ get_ip_script }}' + changed_when: no + register: check_single_actual_check + +- name: assert change IPv4 address to another value (check mode) + assert: + that: + - change_single_check is changed + - check_single_actual_check.stdout_lines == ["192.168.34.5"] + +- name: change IPv4 address to another value + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: 192.168.34.6 + register: change_single + +- name: get result of change IPv4 address to another value + win_shell: '{{ get_ip_script }}' + changed_when: no + register: check_single_actual + +- name: assert change IPv4 address to another value + assert: + that: + - change_single is changed + - check_single_actual.stdout_lines == ["192.168.34.6"] + +- name: set multiple IPv4 addresses (check mode) + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: + - 192.168.34.7 + - 192.168.34.8 + register: set_multiple_check + check_mode: yes + +- name: get result of set multiple IPv4 addresses (check mode) + win_shell: '{{ get_ip_script }}' + changed_when: no + register: set_multiple_actual_check + +- name: assert set multiple IPv4 addresses (check mode) + assert: + that: + - set_multiple_check is changed + - set_multiple_actual_check.stdout_lines == ["192.168.34.6"] + +- name: set multiple IPv4 addresses + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: + - 192.168.34.7 + - 192.168.34.8 + register: set_multiple + +- name: get result of set multiple IPv4 addresses + win_shell: '{{ get_ip_script }}' + changed_when: no + register: set_multiple_actual + +- name: assert set multiple IPv4 addresses + assert: + that: + - set_multiple is changed + - set_multiple_actual.stdout_lines == ["192.168.34.7", "192.168.34.8"] + +- name: set multiple IPv4 addresses (idempotent) + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: + - 192.168.34.7 + - 192.168.34.8 + register: set_multiple_again + +- name: assert set multiple IPv4 addresses (idempotent) + assert: + that: + - not set_multiple_again is changed + +- name: reset IPv4 DNS back to DHCP (check mode) + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: [] + register: set_dhcp_check + check_mode: yes + +- name: get result of reset IPv4 DNS back to DHCP (check mode) + win_shell: '{{ get_ip_script }}' + changed_when: no + register: set_dhcp_actual_check + +- name: assert reset IPv4 DNS back to DHCP (check mode) + assert: + that: + - set_dhcp_check is changed + - set_dhcp_actual_check.stdout_lines == ["192.168.34.7", "192.168.34.8"] + +- name: reset IPv4 DNS back to DHCP + win_dns_client: + adapter_name: '{{ test_adapter }}' + ipv4_addresses: [] + register: set_dhcp + +- name: get result of reset IPv4 DNS back to DHCP + win_shell: '{{ get_ip_script }}' + changed_when: no + register: set_dhcp_actual + +- name: assert reset IPv4 DNS back to DHCP + assert: + that: + - set_dhcp is changed + - set_dhcp_actual.stdout_lines == []