* 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"
|
||||
$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 {
|
||||
Param(
|
||||
[string]$msg
|
||||
|
@ -23,10 +38,6 @@ Function Write-DebugLog {
|
|||
$msg = "$date_str $msg"
|
||||
|
||||
Write-Debug $msg
|
||||
|
||||
$log_path = $null
|
||||
$log_path = Get-AnsibleParam -obj $params -name "log_path"
|
||||
|
||||
if($log_path) {
|
||||
Add-Content $log_path $msg
|
||||
}
|
||||
|
@ -74,7 +85,7 @@ Function Get-DnsClientServerAddressLegacy {
|
|||
return @(
|
||||
# IPv4 values
|
||||
[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=@()};
|
||||
)
|
||||
}
|
||||
|
@ -99,7 +110,7 @@ Function Set-DnsClientServerAddressLegacy {
|
|||
$arguments = @{}
|
||||
}
|
||||
Else {
|
||||
$arguments = @{ DNSServerSearchOrder = $ServerAddresses }
|
||||
$arguments = @{ DNSServerSearchOrder = [string[]]$ServerAddresses }
|
||||
}
|
||||
$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
|
||||
}
|
||||
|
||||
Function Get-DnsClientMatch {
|
||||
Function Test-DnsClientMatch {
|
||||
Param(
|
||||
[string] $adapter_name,
|
||||
[string[]] $ipv4_addresses
|
||||
[System.Net.IPAddress[]] $dns_servers
|
||||
)
|
||||
|
||||
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))
|
||||
|
||||
$current_dns_v4 = ($current_dns_all | Where-Object AddressFamily -eq 2 <# IPv4 #>).ServerAddresses
|
||||
|
||||
If (($null -eq $current_dns_v4) -and ($null -eq $ipv4_addresses)) {
|
||||
$v4_match = $True
|
||||
if(($null -eq $current_dns) -and ($null -eq $dns_servers)) {
|
||||
Write-DebugLog "Neither are dns servers configured nor specified within the playbook."
|
||||
return $true
|
||||
} elseif ($null -eq $current_dns) {
|
||||
Write-DebugLog "There are currently no dns servers specified, but they should be present."
|
||||
return $false
|
||||
} elseif ($null -eq $dns_servers) {
|
||||
Write-DebugLog "There are currently dns servers specified, but they should be absent."
|
||||
return $false
|
||||
}
|
||||
|
||||
ElseIf (($null -eq $current_dns_v4) -or ($null -eq $ipv4_addresses)) {
|
||||
$v4_match = $False
|
||||
foreach($address in $current_dns) {
|
||||
if($address -notin $dns_servers) {
|
||||
Write-DebugLog "There are currently fewer dns servers present than specified within the playbook."
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
Else {
|
||||
$v4_match = @(Compare-Object $current_dns_v4 $ipv4_addresses -SyncWindow 0).Count -eq 0
|
||||
foreach($address in $dns_servers) {
|
||||
if($address -notin $current_dns) {
|
||||
Write-DebugLog "There are currently further dns servers present than specified within the playbook."
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# TODO: implement IPv6
|
||||
|
||||
Write-DebugLog ("Current DNS settings match ({0}) : {1}" -f ($ipv4_addresses -join ", "), $v4_match)
|
||||
|
||||
return $v4_match
|
||||
Write-DebugLog ("Current DNS settings match ({0})." -f ([string[]]$dns_servers -join ", "))
|
||||
return $true
|
||||
}
|
||||
|
||||
Function Validate-IPAddress {
|
||||
Function Assert-IPAddress {
|
||||
Param([string] $address)
|
||||
|
||||
$addrout = $null
|
||||
|
@ -157,72 +175,54 @@ Function Set-DnsClientAddresses
|
|||
{
|
||||
Param(
|
||||
[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
|
||||
}
|
||||
|
||||
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}
|
||||
|
||||
$params = Parse-Args -arguments $args -supports_check_mode $true
|
||||
|
||||
$adapter_names = Get-AnsibleParam $params "adapter_names" -Default "*"
|
||||
$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 = @()
|
||||
if($dns_servers -is [string]) {
|
||||
if($dns_servers.Length -gt 0) {
|
||||
$dns_servers = @($dns_servers)
|
||||
} else {
|
||||
$dns_servers = @()
|
||||
}
|
||||
}
|
||||
# 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 {
|
||||
|
||||
Write-DebugLog ("Validating adapter name {0}" -f $adapter_names)
|
||||
|
||||
$adapters = @($adapter_names)
|
||||
|
||||
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) {
|
||||
Write-DebugLog ("Validating IP addresses ({0})" -f ($dns_servers -join ", "))
|
||||
$invalid_addresses = @($dns_servers | Where-Object { -not (Assert-IPAddress $_) })
|
||||
if($invalid_addresses.Count -gt 0) {
|
||||
throw "Invalid IP address(es): ({0})" -f ($invalid_addresses -join ", ")
|
||||
}
|
||||
|
||||
ForEach($adapter_name in $adapters) {
|
||||
$result.changed = $result.changed -or (-not (Get-DnsClientMatch $adapter_name $ipv4_addresses))
|
||||
|
||||
If($result.changed) {
|
||||
If(-not $check_mode) {
|
||||
Set-DnsClientAddresses $adapter_name $ipv4_addresses
|
||||
}
|
||||
Else {
|
||||
foreach($adapter_name in $adapter_names) {
|
||||
Write-DebugLog ("Validating adapter name {0}" -f $adapter_name)
|
||||
if(-not (Get-DnsClientServerAddress -InterfaceAlias $adapter_name)) {
|
||||
# TODO: add support for an actual list of adapter names
|
||||
# validate network adapter names
|
||||
throw "Invalid network adapter name: {0}" -f $adapter_name
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,18 @@ options:
|
|||
adapter_names:
|
||||
description:
|
||||
- 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).
|
||||
type: str
|
||||
- The adapter name used is the connection caption in the Network Control Panel or the InterfaceAlias of C(Get-DnsClientServerAddress).
|
||||
type: list
|
||||
required: yes
|
||||
ipv4_addresses:
|
||||
dns_servers:
|
||||
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.
|
||||
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
|
||||
aliases: [ "ipv4_addresses", "ip_addresses", "addresses" ]
|
||||
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
|
||||
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
|
||||
win_dns_client:
|
||||
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
|
||||
win_dns_client:
|
||||
adapter_names: '*'
|
||||
ipv4_addresses:
|
||||
dns_servers:
|
||||
- 192.168.34.5
|
||||
- 192.168.34.6
|
||||
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
|
||||
win_dns_client:
|
||||
adapter_names: 'Ethernet*'
|
||||
ipv4_addresses: []
|
||||
dns_servers: []
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
|
|
|
@ -176,3 +176,31 @@
|
|||
that:
|
||||
- set_dhcp is changed
|
||||
- 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 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:PSUseApprovedVerbs
|
||||
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_controller.ps1 pslint:PSAvoidGlobalVars # New PR
|
||||
|
|
Loading…
Reference in a new issue