win_hosts to use Ansible.Basic CSharp Util and better diff support (#58600)
* switch win_hosts to use csharp util * update win_hosts doc to match doc guide * changed linking format for option values
This commit is contained in:
parent
015119df8c
commit
74598b212e
2 changed files with 59 additions and 92 deletions
|
@ -3,36 +3,39 @@
|
||||||
# Copyright: (c) 2018, Micah Hunsberger (@mhunsber)
|
# Copyright: (c) 2018, Micah Hunsberger (@mhunsber)
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
#AnsibleRequires -CSharpUtil Ansible.Basic
|
||||||
|
|
||||||
Set-StrictMode -Version 2
|
Set-StrictMode -Version 2
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
$params = Parse-Args -arguments $args -supports_check_mode $true
|
$spec = @{
|
||||||
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
|
options = @{
|
||||||
$diff_mode = Get-AnsibleParam -obj $params -name "_ansible_diff" -type "bool" -default $false
|
state = @{ type = "str"; choices = "absent", "present"; default = "present" }
|
||||||
|
aliases = @{ type = "list"; elements = "str" }
|
||||||
|
canonical_name = @{ type = "str" }
|
||||||
|
ip_address = @{ type = "str" }
|
||||||
|
action = @{ type = "str"; choices = "add", "remove", "set"; default = "set" }
|
||||||
|
}
|
||||||
|
required_if = @(,@( "state", "present", @("canonical_name", "ip_address")))
|
||||||
|
supports_check_mode = $true
|
||||||
|
}
|
||||||
|
|
||||||
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "absent","present"
|
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
|
||||||
$aliases = Get-AnsibleParam -obj $params -name "aliases" -type "list" -failifempty $false
|
|
||||||
$canonical_name = Get-AnsibleParam -obj $params -name "canonical_name" -type "str" -failifempty ($state -eq 'present')
|
$state = $module.Params.state
|
||||||
$ip_address = Get-AnsibleParam -obj $params -name "ip_address" -type "str" -default "" -failifempty ($state -eq 'present')
|
$aliases = $module.Params.aliases
|
||||||
$action = Get-AnsibleParam -obj $params -name "action" -type "str" -default "set" -validateset "add","remove","set"
|
$canonical_name = $module.Params.canonical_name
|
||||||
|
$ip_address = $module.Params.ip_address
|
||||||
|
$action = $module.Params.action
|
||||||
|
|
||||||
$tmp = [ipaddress]::None
|
$tmp = [ipaddress]::None
|
||||||
if($ip_address -and -not [ipaddress]::TryParse($ip_address, [ref]$tmp)){
|
if($ip_address -and -not [ipaddress]::TryParse($ip_address, [ref]$tmp)){
|
||||||
Fail-Json -obj @{} -message "win_hosts: Argument ip_address needs to be a valid ip address, but was $ip_address"
|
$module.FailJson("win_hosts: Argument ip_address needs to be a valid ip address, but was $ip_address")
|
||||||
}
|
}
|
||||||
$ip_address_type = $tmp.AddressFamily
|
$ip_address_type = $tmp.AddressFamily
|
||||||
|
|
||||||
$hosts_file = Get-Item -LiteralPath "$env:SystemRoot\System32\drivers\etc\hosts"
|
$hosts_file = Get-Item -LiteralPath "$env:SystemRoot\System32\drivers\etc\hosts"
|
||||||
|
|
||||||
$result = @{
|
|
||||||
changed = $false
|
|
||||||
diff = @{
|
|
||||||
prepared = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Function Get-CommentIndex($line) {
|
Function Get-CommentIndex($line) {
|
||||||
$c_index = $line.IndexOf('#')
|
$c_index = $line.IndexOf('#')
|
||||||
if($c_index -lt 0) {
|
if($c_index -lt 0) {
|
||||||
|
@ -79,30 +82,14 @@ Function Find-HostName($line, $name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Remove-HostEntry($list, $idx) {
|
Function Remove-HostEntry($list, $idx) {
|
||||||
$result.changed = $true
|
$module.Result.changed = $true
|
||||||
$removed = $false
|
$list.RemoveAt($idx)
|
||||||
|
|
||||||
if($diff_mode) {
|
|
||||||
$result.diff.prepared += "`n-[$($list[$idx])]`n"
|
|
||||||
}
|
|
||||||
|
|
||||||
if(-not $check_mode) {
|
|
||||||
$list.RemoveAt($idx)
|
|
||||||
$removed = $true
|
|
||||||
}
|
|
||||||
|
|
||||||
return $removed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Add-HostEntry($list, $cname, $aliases, $ip) {
|
Function Add-HostEntry($list, $cname, $aliases, $ip) {
|
||||||
$result.changed = $true
|
$module.Result.changed = $true
|
||||||
$line = "$ip $cname $($aliases -join ' ')"
|
$line = "$ip $cname $($aliases -join ' ')"
|
||||||
if($diff_mode) {
|
$list.Add($line) | Out-Null
|
||||||
$result.diff.prepared += "`n+[$line]`n"
|
|
||||||
}
|
|
||||||
if(-not $check_mode) {
|
|
||||||
$list.Add($line) | Out-Null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Remove-HostnamesFromEntry($list, $idx, $aliases) {
|
Function Remove-HostnamesFromEntry($list, $idx, $aliases) {
|
||||||
|
@ -115,13 +102,8 @@ Function Remove-HostnamesFromEntry($list, $idx, $aliases) {
|
||||||
$line = $line.Remove($match.Index + 1, $match.Length -1)
|
$line = $line.Remove($match.Index + 1, $match.Length -1)
|
||||||
# was this the last alias? (check for space characters after trimming)
|
# was this the last alias? (check for space characters after trimming)
|
||||||
if($line.Substring(0,(Get-CommentIndex -line $line)).Trim() -inotmatch "\s") {
|
if($line.Substring(0,(Get-CommentIndex -line $line)).Trim() -inotmatch "\s") {
|
||||||
if($diff_mode){
|
$list.RemoveAt($idx)
|
||||||
$result.diff.prepared += "`n-[$($list[$idx])]`n"
|
$line_removed = $true
|
||||||
}
|
|
||||||
if(-not $check_mode) {
|
|
||||||
$list.RemoveAt($idx)
|
|
||||||
$line_removed = $true
|
|
||||||
}
|
|
||||||
# we're done
|
# we're done
|
||||||
return @{
|
return @{
|
||||||
line_removed = $line_removed
|
line_removed = $line_removed
|
||||||
|
@ -130,13 +112,8 @@ Function Remove-HostnamesFromEntry($list, $idx, $aliases) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($line -ne $list[$idx]){
|
if($line -ne $list[$idx]){
|
||||||
$result.changed = $true
|
$module.Result.changed = $true
|
||||||
if($diff_mode) {
|
$list[$idx] = $line
|
||||||
$result.diff.prepared += "`n-[$($list[$idx])]`n+[$line]`n"
|
|
||||||
}
|
|
||||||
if(-not $check_mode) {
|
|
||||||
$list[$idx] = $line
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return @{
|
return @{
|
||||||
line_removed = $line_removed
|
line_removed = $line_removed
|
||||||
|
@ -153,19 +130,15 @@ Function Add-AliasesToEntry($list, $idx, $aliases) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($line -ne $list[$idx]){
|
if($line -ne $list[$idx]){
|
||||||
$result.changed = $true
|
$module.Result.changed = $true
|
||||||
if($diff_mode) {
|
$list[$idx] = $line
|
||||||
$result.diff.prepared += "`n-[$($list[$idx])]`n+[$line]`n"
|
|
||||||
}
|
|
||||||
if(-not $check_mode) {
|
|
||||||
$list[$idx] = $line
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$hosts_lines = New-Object System.Collections.ArrayList
|
$hosts_lines = New-Object System.Collections.ArrayList
|
||||||
|
|
||||||
Get-Content -LiteralPath $hosts_file.FullName | ForEach-Object { $hosts_lines.Add($_) } | Out-Null
|
Get-Content -LiteralPath $hosts_file.FullName | ForEach-Object { $hosts_lines.Add($_) } | Out-Null
|
||||||
|
$module.Diff.before = ($hosts_lines -join "`n") + "`n"
|
||||||
|
|
||||||
if ($state -eq 'absent') {
|
if ($state -eq 'absent') {
|
||||||
# go through and remove canonical_name and ip
|
# go through and remove canonical_name and ip
|
||||||
|
@ -200,11 +173,9 @@ if($state -eq 'present') {
|
||||||
$aliases_to_remove = @()
|
$aliases_to_remove = @()
|
||||||
if($entry_parts.ip_address -eq $ip_address) {
|
if($entry_parts.ip_address -eq $ip_address) {
|
||||||
if($entry_parts.canonical_name -eq $canonical_name) {
|
if($entry_parts.canonical_name -eq $canonical_name) {
|
||||||
# don't need to worry about line being removed since canonical_name is present
|
|
||||||
$entry_idx = $idx
|
$entry_idx = $idx
|
||||||
|
|
||||||
if($action -eq 'set') {
|
if($action -eq 'set') {
|
||||||
# remove the entry's aliases that are not in $aliases
|
|
||||||
$aliases_to_remove = $entry_parts.aliases | Where-Object { $aliases -notcontains $_ }
|
$aliases_to_remove = $entry_parts.aliases | Where-Object { $aliases -notcontains $_ }
|
||||||
} elseif($action -eq 'remove') {
|
} elseif($action -eq 'remove') {
|
||||||
$aliases_to_remove = $aliases
|
$aliases_to_remove = $aliases
|
||||||
|
@ -220,41 +191,31 @@ if($state -eq 'present') {
|
||||||
# this is not the ip_address we are looking for
|
# this is not the ip_address we are looking for
|
||||||
if ($ip_address_type -eq $entry_parts.ip_type) {
|
if ($ip_address_type -eq $entry_parts.ip_type) {
|
||||||
if ($entry_parts.canonical_name -eq $canonical_name) {
|
if ($entry_parts.canonical_name -eq $canonical_name) {
|
||||||
# remove the entry
|
Remove-HostEntry -list $hosts_lines -idx $idx
|
||||||
if (Remove-HostEntry -list $hosts_lines -idx $idx){
|
$idx = $idx - 1
|
||||||
# keep index correct if we removed the line
|
|
||||||
$idx = $idx - 1
|
|
||||||
}
|
|
||||||
if ($action -ne "set") {
|
if ($action -ne "set") {
|
||||||
# keep old aliases intact
|
# keep old aliases intact
|
||||||
$aliases_to_keep += $entry_parts.aliases | Where-Object { ($aliases + $aliases_to_keep + $canonical_name) -notcontains $_ }
|
$aliases_to_keep += $entry_parts.aliases | Where-Object { ($aliases + $aliases_to_keep + $canonical_name) -notcontains $_ }
|
||||||
}
|
}
|
||||||
} elseif ($action -eq "remove") {
|
} elseif ($action -eq "remove") {
|
||||||
# just remove canonical_name. user may want alias(es) mapped to this canonical name
|
|
||||||
$aliases_to_remove = $canonical_name
|
$aliases_to_remove = $canonical_name
|
||||||
} elseif ($aliases -contains $entry_parts.canonical_name) {
|
} elseif ($aliases -contains $entry_parts.canonical_name) {
|
||||||
# remove the entry
|
Remove-HostEntry -list $hosts_lines -idx $idx
|
||||||
if (Remove-HostEntry -list $hosts_lines -idx $idx) {
|
$idx = $idx - 1
|
||||||
# keep index correct if we removed the line
|
|
||||||
$idx = $idx - 1
|
|
||||||
}
|
|
||||||
if ($action -eq "add") {
|
if ($action -eq "add") {
|
||||||
# keep old aliases intact
|
# keep old aliases intact
|
||||||
$aliases_to_keep += $entry_parts.aliases | Where-Object { ($aliases + $aliases_to_keep + $canonical_name) -notcontains $_ }
|
$aliases_to_keep += $entry_parts.aliases | Where-Object { ($aliases + $aliases_to_keep + $canonical_name) -notcontains $_ }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
# ensure canonical_name and aliases removed from this entry
|
|
||||||
$aliases_to_remove = $aliases + $canonical_name
|
$aliases_to_remove = $aliases + $canonical_name
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
# Just ignore if the types don't match.
|
|
||||||
# TODO: Better ipv6 support. There is odd behavior for when an alias can be used for both ipv6 and ipv4
|
# TODO: Better ipv6 support. There is odd behavior for when an alias can be used for both ipv6 and ipv4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($aliases_to_remove) {
|
if($aliases_to_remove) {
|
||||||
if((Remove-HostnamesFromEntry -list $hosts_lines -idx $idx -aliases $aliases_to_remove).line_removed) {
|
if((Remove-HostnamesFromEntry -list $hosts_lines -idx $idx -aliases $aliases_to_remove).line_removed) {
|
||||||
# keep index correct if we removed the line
|
|
||||||
$idx = $idx - 1
|
$idx = $idx - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,14 +224,11 @@ if($state -eq 'present') {
|
||||||
}
|
}
|
||||||
|
|
||||||
if($entry_idx -ge 0) {
|
if($entry_idx -ge 0) {
|
||||||
# we found the entry
|
|
||||||
$aliases_to_add = @()
|
$aliases_to_add = @()
|
||||||
$entry_parts = Get-HostEntryParts -line $hosts_lines[$entry_idx]
|
$entry_parts = Get-HostEntryParts -line $hosts_lines[$entry_idx]
|
||||||
if($action -eq 'remove') {
|
if($action -eq 'remove') {
|
||||||
# just preserve any previously removed aliases
|
|
||||||
$aliases_to_add = $aliases_to_keep | Where-Object { $entry_parts.aliases -notcontains $_ }
|
$aliases_to_add = $aliases_to_keep | Where-Object { $entry_parts.aliases -notcontains $_ }
|
||||||
} else {
|
} else {
|
||||||
# we want to add provided aliases and previously removed aliases that are not already in the list
|
|
||||||
$aliases_to_add = ($aliases + $aliases_to_keep) | Where-Object { $entry_parts.aliases -notcontains $_ }
|
$aliases_to_add = ($aliases + $aliases_to_keep) | Where-Object { $entry_parts.aliases -notcontains $_ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,8 +249,9 @@ if($state -eq 'present') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( $result.changed -and -not $check_mode ) {
|
$module.Diff.after = ($hosts_lines -join "`n") + "`n"
|
||||||
|
if( $module.Result.changed -and -not $module.CheckMode ) {
|
||||||
Set-Content -LiteralPath $hosts_file.FullName -Value $hosts_lines
|
Set-Content -LiteralPath $hosts_file.FullName -Value $hosts_lines
|
||||||
}
|
}
|
||||||
|
|
||||||
Exit-Json $result
|
$module.ExitJson()
|
||||||
|
|
|
@ -18,62 +18,70 @@ version_added: '2.8'
|
||||||
short_description: Manages hosts file entries on Windows.
|
short_description: Manages hosts file entries on Windows.
|
||||||
description:
|
description:
|
||||||
- Manages hosts file entries on Windows.
|
- Manages hosts file entries on Windows.
|
||||||
- Maps IPv4 or IPv6 addresses to canonical names
|
- Maps IPv4 or IPv6 addresses to canonical names.
|
||||||
- Adds, removes, or sets cname records for ip and hostname pairs
|
- Adds, removes, or sets cname records for ip and hostname pairs.
|
||||||
- Modifies %windir%\system32\drivers\etc\hosts.
|
- Modifies %windir%\\system32\\drivers\\etc\\hosts.
|
||||||
options:
|
options:
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- Whether the entry should be present or absent.
|
- Whether the entry should be present or absent.
|
||||||
- If only C(canonical_name) is provided when C(state=absent), then
|
- If only I(canonical_name) is provided when C(state=absent), then
|
||||||
all hosts entries with the canonical name of I(canonical_name)
|
all hosts entries with the canonical name of I(canonical_name)
|
||||||
will be removed.
|
will be removed.
|
||||||
- If only C(ip_address) is provided when C(state=absent), then all
|
- If only I(ip_address) is provided when C(state=absent), then all
|
||||||
hosts entries with the ip address of I(ip_address) will be removed.
|
hosts entries with the ip address of I(ip_address) will be removed.
|
||||||
- If C(ip_address) and C(canonical_name) are both omitted when
|
- If I(ip_address) and I(canonical_name) are both omitted when
|
||||||
C(state=absent), then all hosts entries will be removed.
|
C(state=absent), then all hosts entries will be removed.
|
||||||
choices:
|
choices:
|
||||||
- absent
|
- absent
|
||||||
- present
|
- present
|
||||||
default: present
|
default: present
|
||||||
|
type: str
|
||||||
canonical_name:
|
canonical_name:
|
||||||
description:
|
description:
|
||||||
- A canonical name for the host entry.
|
- A canonical name for the host entry.
|
||||||
- required for C(state=present).
|
- required for C(state=present).
|
||||||
|
type: str
|
||||||
ip_address:
|
ip_address:
|
||||||
description:
|
description:
|
||||||
- The ip address for the host entry.
|
- The ip address for the host entry.
|
||||||
- Can be either IPv4 (A record) or IPv6 (AAAA record).
|
- Can be either IPv4 (A record) or IPv6 (AAAA record).
|
||||||
- Required for C(state=present).
|
- Required for C(state=present).
|
||||||
|
type: str
|
||||||
aliases:
|
aliases:
|
||||||
description:
|
description:
|
||||||
- A list of additional names (cname records) for the host entry.
|
- A list of additional names (cname records) for the host entry.
|
||||||
- Only applicable when C(state=present).
|
- Only applicable when C(state=present).
|
||||||
|
type: list
|
||||||
action:
|
action:
|
||||||
choices:
|
choices:
|
||||||
- add
|
- add
|
||||||
- remove
|
- remove
|
||||||
- set
|
- set
|
||||||
description:
|
description:
|
||||||
- Controls the behavior of C(aliases).
|
- Controls the behavior of I(aliases).
|
||||||
- Only applicable when C(state=present).
|
- Only applicable when C(state=present).
|
||||||
- If C(add), each alias in I(aliases) will be added to the host entry.
|
- If C(add), each alias in I(aliases) will be added to the host entry.
|
||||||
- If C(set), each alias in I(aliases) will be added to the host entry,
|
- If C(set), each alias in I(aliases) will be added to the host entry,
|
||||||
and other aliases will be removed from the entry.
|
and other aliases will be removed from the entry.
|
||||||
default: set
|
default: set
|
||||||
|
type: str
|
||||||
author:
|
author:
|
||||||
- Micah Hunsberger (@mhunsber)
|
- Micah Hunsberger (@mhunsber)
|
||||||
notes:
|
notes:
|
||||||
- Each canonical name can only be mapped to one IPv4 and one IPv6 address.
|
- Each canonical name can only be mapped to one IPv4 and one IPv6 address.
|
||||||
If C(canonical_name) is provided with C(state=present) and is found
|
If I(canonical_name) is provided with C(state=present) and is found
|
||||||
to be mapped to another IP address that is the same type as, but unique
|
to be mapped to another IP address that is the same type as, but unique
|
||||||
from C(ip_address), then C(canonical_name) and all C(aliases) will
|
from I(ip_address), then I(canonical_name) and all I(aliases) will
|
||||||
be removed from the entry and added to an entry with the provided IP address.
|
be removed from the entry and added to an entry with the provided IP address.
|
||||||
- Each alias can only be mapped to one canonical name. If C(aliases) is provided
|
- Each alias can only be mapped to one canonical name. If I(aliases) is provided
|
||||||
with C(state=present) and an alias is found to be mapped to another canonical
|
with C(state=present) and an alias is found to be mapped to another canonical
|
||||||
name, then the alias will be removed from the entry and added to or removed
|
name, then the alias will be removed from the entry and either added to or removed
|
||||||
from (based on I(action)) an entry with the provided canonical name.
|
from (depending on I(action)) an entry with the provided canonical name.
|
||||||
- See also M(win_template), M(win_file), M(win_copy)
|
seealso:
|
||||||
|
- module: win_template
|
||||||
|
- module: win_file
|
||||||
|
- module: win_copy
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = r'''
|
EXAMPLES = r'''
|
||||||
|
|
Loading…
Reference in a new issue