* Add full IPv6 support to win_dns_client - Fixes #55962 * Fix missing cast * Add type to win_dns_client.py * Remove version_added again, to hopefully make ansibot happy. Even though it was added as a response to the bot... * Fix $params undefined error, that was introduced by fixing the "global variable" linting issue * Fix casting error * Fix inverted logic * Fix rebase error * Fix assignment to readonly variable * Fix "reset IPv4 DNS back to DHCP adapter_name" * Fix legacy windows server support (2008/2008R2) * Fix 2k8 * Remove unecessary pslint ignore * Added IPv6 tests, changelog fragment and further docs
This commit is contained in:
parent
480b106d65
commit
0efe5a666d
5 changed files with 127 additions and 88 deletions
2
changelogs/fragments/win_dns_client_ipv6.yaml
Normal file
2
changelogs/fragments/win_dns_client_ipv6.yaml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- win_dns_client - Added support for setting IPv6 DNS servers - https://github.com/ansible/ansible/issues/55962
|
|
@ -12,6 +12,21 @@ Set-StrictMode -Version 2
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
$ConfirmPreference = "None"
|
$ConfirmPreference = "None"
|
||||||
|
|
||||||
|
Set-Variable -Visibility Public -Option ReadOnly,AllScope,Constant -Name "AddressFamilies" -Value @(
|
||||||
|
[System.Net.Sockets.AddressFamily]::InterNetworkV6,
|
||||||
|
[System.Net.Sockets.AddressFamily]::InterNetwork
|
||||||
|
)
|
||||||
|
$result = @{changed=$false}
|
||||||
|
|
||||||
|
$params = Parse-Args -arguments $args -supports_check_mode $true
|
||||||
|
Set-Variable -Visibility Public -Option ReadOnly,AllScope,Constant -Name "log_path" -Value (
|
||||||
|
Get-AnsibleParam $params "log_path"
|
||||||
|
)
|
||||||
|
$adapter_names = Get-AnsibleParam $params "adapter_names" -Default "*"
|
||||||
|
$dns_servers = Get-AnsibleParam $params "dns_servers" -aliases "ipv4_addresses","ip_addresses","addresses" -FailIfEmpty $result
|
||||||
|
$check_mode = Get-AnsibleParam $params "_ansible_check_mode" -Default $false
|
||||||
|
|
||||||
|
|
||||||
Function Write-DebugLog {
|
Function Write-DebugLog {
|
||||||
Param(
|
Param(
|
||||||
[string]$msg
|
[string]$msg
|
||||||
|
@ -23,10 +38,6 @@ Function Write-DebugLog {
|
||||||
$msg = "$date_str $msg"
|
$msg = "$date_str $msg"
|
||||||
|
|
||||||
Write-Debug $msg
|
Write-Debug $msg
|
||||||
|
|
||||||
$log_path = $null
|
|
||||||
$log_path = Get-AnsibleParam -obj $params -name "log_path"
|
|
||||||
|
|
||||||
if($log_path) {
|
if($log_path) {
|
||||||
Add-Content $log_path $msg
|
Add-Content $log_path $msg
|
||||||
}
|
}
|
||||||
|
@ -74,7 +85,7 @@ Function Get-DnsClientServerAddressLegacy {
|
||||||
return @(
|
return @(
|
||||||
# IPv4 values
|
# IPv4 values
|
||||||
[PSCustomObject]@{InterfaceAlias=$InterfaceAlias;InterfaceIndex=$idx;AddressFamily=2;ServerAddresses=$adapter_config.DNSServerSearchOrder};
|
[PSCustomObject]@{InterfaceAlias=$InterfaceAlias;InterfaceIndex=$idx;AddressFamily=2;ServerAddresses=$adapter_config.DNSServerSearchOrder};
|
||||||
# IPv6, only here for completeness since we don't support it yet
|
# IPv6 values
|
||||||
[PSCustomObject]@{InterfaceAlias=$InterfaceAlias;InterfaceIndex=$idx;AddressFamily=23;ServerAddresses=@()};
|
[PSCustomObject]@{InterfaceAlias=$InterfaceAlias;InterfaceIndex=$idx;AddressFamily=23;ServerAddresses=@()};
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -99,7 +110,7 @@ Function Set-DnsClientServerAddressLegacy {
|
||||||
$arguments = @{}
|
$arguments = @{}
|
||||||
}
|
}
|
||||||
Else {
|
Else {
|
||||||
$arguments = @{ DNSServerSearchOrder = $ServerAddresses }
|
$arguments = @{ DNSServerSearchOrder = [string[]]$ServerAddresses }
|
||||||
}
|
}
|
||||||
$res = Invoke-CimMethod -InputObject $adapter_config -MethodName SetDNSServerSearchOrder -Arguments $arguments
|
$res = Invoke-CimMethod -InputObject $adapter_config -MethodName SetDNSServerSearchOrder -Arguments $arguments
|
||||||
|
|
||||||
|
@ -112,40 +123,47 @@ If(-not $(Get-Command Set-DnsClientServerAddress -ErrorAction SilentlyContinue))
|
||||||
New-Alias Set-DnsClientServerAddress Set-DnsClientServerAddressLegacy
|
New-Alias Set-DnsClientServerAddress Set-DnsClientServerAddressLegacy
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Get-DnsClientMatch {
|
Function Test-DnsClientMatch {
|
||||||
Param(
|
Param(
|
||||||
[string] $adapter_name,
|
[string] $adapter_name,
|
||||||
[string[]] $ipv4_addresses
|
[System.Net.IPAddress[]] $dns_servers
|
||||||
)
|
)
|
||||||
|
|
||||||
Write-DebugLog ("Getting DNS config for adapter {0}" -f $adapter_name)
|
Write-DebugLog ("Getting DNS config for adapter {0}" -f $adapter_name)
|
||||||
|
|
||||||
$current_dns_all = Get-DnsClientServerAddress -InterfaceAlias $adapter_name
|
$current_dns = ([System.Net.IPAddress[]](
|
||||||
|
(Get-DnsClientServerAddress -InterfaceAlias $adapter_name).ServerAddresses) | Where-Object {
|
||||||
|
(Assert-IPAddress $_) -and ($_.AddressFamily -in $AddressFamilies)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Write-DebugLog ("Current DNS settings: {0}" -f ([string[]]$dns_servers -join ", "))
|
||||||
|
|
||||||
Write-DebugLog ("Current DNS settings: " + $($current_dns_all | Out-String))
|
if(($null -eq $current_dns) -and ($null -eq $dns_servers)) {
|
||||||
|
Write-DebugLog "Neither are dns servers configured nor specified within the playbook."
|
||||||
$current_dns_v4 = ($current_dns_all | Where-Object AddressFamily -eq 2 <# IPv4 #>).ServerAddresses
|
return $true
|
||||||
|
} elseif ($null -eq $current_dns) {
|
||||||
If (($null -eq $current_dns_v4) -and ($null -eq $ipv4_addresses)) {
|
Write-DebugLog "There are currently no dns servers specified, but they should be present."
|
||||||
$v4_match = $True
|
return $false
|
||||||
|
} elseif ($null -eq $dns_servers) {
|
||||||
|
Write-DebugLog "There are currently dns servers specified, but they should be absent."
|
||||||
|
return $false
|
||||||
}
|
}
|
||||||
|
foreach($address in $current_dns) {
|
||||||
ElseIf (($null -eq $current_dns_v4) -or ($null -eq $ipv4_addresses)) {
|
if($address -notin $dns_servers) {
|
||||||
$v4_match = $False
|
Write-DebugLog "There are currently fewer dns servers present than specified within the playbook."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
foreach($address in $dns_servers) {
|
||||||
Else {
|
if($address -notin $current_dns) {
|
||||||
$v4_match = @(Compare-Object $current_dns_v4 $ipv4_addresses -SyncWindow 0).Count -eq 0
|
Write-DebugLog "There are currently further dns servers present than specified within the playbook."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Write-DebugLog ("Current DNS settings match ({0})." -f ([string[]]$dns_servers -join ", "))
|
||||||
# TODO: implement IPv6
|
return $true
|
||||||
|
|
||||||
Write-DebugLog ("Current DNS settings match ({0}) : {1}" -f ($ipv4_addresses -join ", "), $v4_match)
|
|
||||||
|
|
||||||
return $v4_match
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Validate-IPAddress {
|
Function Assert-IPAddress {
|
||||||
Param([string] $address)
|
Param([string] $address)
|
||||||
|
|
||||||
$addrout = $null
|
$addrout = $null
|
||||||
|
@ -157,72 +175,54 @@ Function Set-DnsClientAddresses
|
||||||
{
|
{
|
||||||
Param(
|
Param(
|
||||||
[string] $adapter_name,
|
[string] $adapter_name,
|
||||||
[string[]] $ipv4_addresses
|
[System.Net.IPAddress[]] $dns_servers
|
||||||
)
|
)
|
||||||
|
|
||||||
Write-DebugLog ("Setting DNS addresses for adapter {0} to ({1})" -f $adapter_name, ($ipv4_addresses -join ", "))
|
Write-DebugLog ("Setting DNS addresses for adapter {0} to ({1})" -f $adapter_name, ([string[]]$dns_servers -join ", "))
|
||||||
|
|
||||||
If ($null -eq $ipv4_addresses) {
|
If ($dns_servers) {
|
||||||
|
Set-DnsClientServerAddress -InterfaceAlias $adapter_name -ServerAddresses $dns_servers
|
||||||
|
} Else {
|
||||||
Set-DnsClientServerAddress -InterfaceAlias $adapter_name -ResetServerAddress
|
Set-DnsClientServerAddress -InterfaceAlias $adapter_name -ResetServerAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
Else {
|
|
||||||
# this silently ignores invalid IPs, so we validate parseability ourselves up front...
|
|
||||||
Set-DnsClientServerAddress -InterfaceAlias $adapter_name -ServerAddresses $ipv4_addresses
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: implement IPv6
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = @{changed=$false}
|
if($dns_servers -is [string]) {
|
||||||
|
if($dns_servers.Length -gt 0) {
|
||||||
$params = Parse-Args -arguments $args -supports_check_mode $true
|
$dns_servers = @($dns_servers)
|
||||||
|
} else {
|
||||||
$adapter_names = Get-AnsibleParam $params "adapter_names" -Default "*"
|
$dns_servers = @()
|
||||||
$ipv4_addresses = Get-AnsibleParam $params "ipv4_addresses" -FailIfEmpty $result
|
|
||||||
|
|
||||||
If($ipv4_addresses -is [string]) {
|
|
||||||
If($ipv4_addresses.Length -gt 0) {
|
|
||||||
$ipv4_addresses = @($ipv4_addresses)
|
|
||||||
}
|
|
||||||
Else {
|
|
||||||
$ipv4_addresses = @()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Using object equals here, to check for exact match (without implicit type conversion)
|
||||||
|
if([System.Object]::Equals($adapter_names, "*")) {
|
||||||
|
$adapter_names = Get-NetAdapter | Select-Object -ExpandProperty Name
|
||||||
|
}
|
||||||
|
if($adapter_names -is [string]) {
|
||||||
|
$adapter_names = @($adapter_names)
|
||||||
|
}
|
||||||
|
|
||||||
$check_mode = Get-AnsibleParam $params "_ansible_check_mode" -Default $false
|
|
||||||
|
|
||||||
Try {
|
Try {
|
||||||
|
|
||||||
Write-DebugLog ("Validating adapter name {0}" -f $adapter_names)
|
Write-DebugLog ("Validating IP addresses ({0})" -f ($dns_servers -join ", "))
|
||||||
|
$invalid_addresses = @($dns_servers | Where-Object { -not (Assert-IPAddress $_) })
|
||||||
$adapters = @($adapter_names)
|
if($invalid_addresses.Count -gt 0) {
|
||||||
|
|
||||||
If($adapter_names -eq "*") {
|
|
||||||
$adapters = Get-NetAdapter | Select-Object -ExpandProperty Name
|
|
||||||
}
|
|
||||||
# TODO: add support for an actual list of adapter names
|
|
||||||
# validate network adapter names
|
|
||||||
ElseIf(@(Get-NetAdapter | Where-Object Name -eq $adapter_names).Count -eq 0) {
|
|
||||||
throw "Invalid network adapter name: {0}" -f $adapter_names
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-DebugLog ("Validating IP addresses ({0})" -f ($ipv4_addresses -join ", "))
|
|
||||||
|
|
||||||
$invalid_addresses = @($ipv4_addresses | Where-Object { -not (Validate-IPAddress $_) })
|
|
||||||
|
|
||||||
If($invalid_addresses.Count -gt 0) {
|
|
||||||
throw "Invalid IP address(es): ({0})" -f ($invalid_addresses -join ", ")
|
throw "Invalid IP address(es): ({0})" -f ($invalid_addresses -join ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
ForEach($adapter_name in $adapters) {
|
foreach($adapter_name in $adapter_names) {
|
||||||
$result.changed = $result.changed -or (-not (Get-DnsClientMatch $adapter_name $ipv4_addresses))
|
Write-DebugLog ("Validating adapter name {0}" -f $adapter_name)
|
||||||
|
if(-not (Get-DnsClientServerAddress -InterfaceAlias $adapter_name)) {
|
||||||
If($result.changed) {
|
# TODO: add support for an actual list of adapter names
|
||||||
If(-not $check_mode) {
|
# validate network adapter names
|
||||||
Set-DnsClientAddresses $adapter_name $ipv4_addresses
|
throw "Invalid network adapter name: {0}" -f $adapter_name
|
||||||
}
|
}
|
||||||
Else {
|
if(-not (Test-DnsClientMatch $adapter_name $dns_servers)) {
|
||||||
|
$result.changed = $true
|
||||||
|
if(-not $check_mode) {
|
||||||
|
Set-DnsClientAddresses $adapter_name $dns_servers
|
||||||
|
} else {
|
||||||
Write-DebugLog "Check mode, skipping"
|
Write-DebugLog "Check mode, skipping"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,18 @@ options:
|
||||||
adapter_names:
|
adapter_names:
|
||||||
description:
|
description:
|
||||||
- Adapter name or list of adapter names for which to manage DNS settings ('*' is supported as a wildcard value).
|
- Adapter name or list of adapter names for which to manage DNS settings ('*' is supported as a wildcard value).
|
||||||
- The adapter name used is the connection caption in the Network Control Panel or via C(Get-NetAdapter), eg C(Local Area Connection).
|
- The adapter name used is the connection caption in the Network Control Panel or the InterfaceAlias of C(Get-DnsClientServerAddress).
|
||||||
type: str
|
type: list
|
||||||
required: yes
|
required: yes
|
||||||
ipv4_addresses:
|
dns_servers:
|
||||||
description:
|
description:
|
||||||
- Single or ordered list of DNS server IPv4 addresses to configure for lookup. An empty list will configure the adapter to use the
|
- Single or ordered list of DNS servers (IPv4 and IPv6 addresses) to configure for lookup. An empty list will configure the adapter to use the
|
||||||
DHCP-assigned values on connections where DHCP is enabled, or disable DNS lookup on statically-configured connections.
|
DHCP-assigned values on connections where DHCP is enabled, or disable DNS lookup on statically-configured connections.
|
||||||
type: str
|
- IPv6 DNS servers can only be set on Windows Server 2012 or newer, older hosts can only set IPv4 addresses.
|
||||||
|
- Before 2.10 use ipv4_addresses instead.
|
||||||
|
type: list
|
||||||
required: yes
|
required: yes
|
||||||
|
aliases: [ "ipv4_addresses", "ip_addresses", "addresses" ]
|
||||||
notes:
|
notes:
|
||||||
- When setting an empty list of DNS server addresses on an adapter with DHCP enabled, a change will always be registered, since it is not possible to
|
- When setting an empty list of DNS server addresses on an adapter with DHCP enabled, a change will always be registered, since it is not possible to
|
||||||
detect the difference between a DHCP-sourced server value and one that is statically set.
|
detect the difference between a DHCP-sourced server value and one that is statically set.
|
||||||
|
@ -39,20 +42,27 @@ EXAMPLES = r'''
|
||||||
- name: Set a single address on the adapter named Ethernet
|
- name: Set a single address on the adapter named Ethernet
|
||||||
win_dns_client:
|
win_dns_client:
|
||||||
adapter_names: Ethernet
|
adapter_names: Ethernet
|
||||||
ipv4_addresses: 192.168.34.5
|
dns_servers: 192.168.34.5
|
||||||
|
|
||||||
- name: Set multiple lookup addresses on all visible adapters (usually physical adapters that are in the Up state), with debug logging to a file
|
- name: Set multiple lookup addresses on all visible adapters (usually physical adapters that are in the Up state), with debug logging to a file
|
||||||
win_dns_client:
|
win_dns_client:
|
||||||
adapter_names: '*'
|
adapter_names: '*'
|
||||||
ipv4_addresses:
|
dns_servers:
|
||||||
- 192.168.34.5
|
- 192.168.34.5
|
||||||
- 192.168.34.6
|
- 192.168.34.6
|
||||||
log_path: C:\dns_log.txt
|
log_path: C:\dns_log.txt
|
||||||
|
|
||||||
|
- name: Set IPv6 DNS servers on the adapter named Ethernet
|
||||||
|
win_dns_client:
|
||||||
|
adapter_names: Ethernet
|
||||||
|
dns_servers:
|
||||||
|
- '2001:db8::2'
|
||||||
|
- '2001:db8::3'
|
||||||
|
|
||||||
- name: Configure all adapters whose names begin with Ethernet to use DHCP-assigned DNS values
|
- name: Configure all adapters whose names begin with Ethernet to use DHCP-assigned DNS values
|
||||||
win_dns_client:
|
win_dns_client:
|
||||||
adapter_names: 'Ethernet*'
|
adapter_names: 'Ethernet*'
|
||||||
ipv4_addresses: []
|
dns_servers: []
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = r'''
|
RETURN = r'''
|
||||||
|
|
|
@ -176,3 +176,31 @@
|
||||||
that:
|
that:
|
||||||
- set_dhcp is changed
|
- set_dhcp is changed
|
||||||
- set_dhcp_actual.stdout_lines == []
|
- set_dhcp_actual.stdout_lines == []
|
||||||
|
|
||||||
|
# Legacy WMI does not support setting IPv6 addresses so we can only test this on newer hosts that have the new cmdlets
|
||||||
|
- name: check if server supports IPv6
|
||||||
|
win_shell: if (Get-Command -Name Get-NetAdapter -ErrorAction SilentlyContinue) { $true } else { $false }
|
||||||
|
changed_when: no
|
||||||
|
register: new_os
|
||||||
|
|
||||||
|
- name: run IPv6 tests
|
||||||
|
when: new_os.stdout | trim | bool
|
||||||
|
block:
|
||||||
|
- name: set IPv6 DNS address
|
||||||
|
win_dns_client:
|
||||||
|
adapter_names: '{{ network_adapter_name }}'
|
||||||
|
dns_servers:
|
||||||
|
- 2001:db8::1
|
||||||
|
- 2001:db8::2
|
||||||
|
register: set_ipv6
|
||||||
|
|
||||||
|
- name: get result of set IPv6 DNS address
|
||||||
|
win_shell: (Get-DnsClientServerAddress -InterfaceAlias '{{ network_adapter_name }}' -AddressFAmily IPv6).ServerAddresses
|
||||||
|
changed_when: no
|
||||||
|
register: set_ipv6_actual
|
||||||
|
|
||||||
|
- name: assert set IPv6 DNS address
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- set_ipv6 is changed
|
||||||
|
- set_ipv6_actual.stdout_lines == ['2001:db8::1', '2001:db8::2']
|
||||||
|
|
|
@ -4987,7 +4987,6 @@ lib/ansible/modules/windows/win_copy.ps1 pslint:PSUseApprovedVerbs
|
||||||
lib/ansible/modules/windows/win_credential.ps1 pslint:PSCustomUseLiteralPath
|
lib/ansible/modules/windows/win_credential.ps1 pslint:PSCustomUseLiteralPath
|
||||||
lib/ansible/modules/windows/win_credential.ps1 validate-modules:parameter-type-not-in-doc
|
lib/ansible/modules/windows/win_credential.ps1 validate-modules:parameter-type-not-in-doc
|
||||||
lib/ansible/modules/windows/win_dns_client.ps1 pslint:PSCustomUseLiteralPath
|
lib/ansible/modules/windows/win_dns_client.ps1 pslint:PSCustomUseLiteralPath
|
||||||
lib/ansible/modules/windows/win_dns_client.ps1 pslint:PSUseApprovedVerbs
|
|
||||||
lib/ansible/modules/windows/win_domain.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
|
lib/ansible/modules/windows/win_domain.ps1 pslint:PSAvoidUsingEmptyCatchBlock # Keep
|
||||||
lib/ansible/modules/windows/win_domain.ps1 pslint:PSUseApprovedVerbs
|
lib/ansible/modules/windows/win_domain.ps1 pslint:PSUseApprovedVerbs
|
||||||
lib/ansible/modules/windows/win_domain_controller.ps1 pslint:PSAvoidGlobalVars # New PR
|
lib/ansible/modules/windows/win_domain_controller.ps1 pslint:PSAvoidGlobalVars # New PR
|
||||||
|
|
Loading…
Reference in a new issue