win_stat - add follow option and fix broken tests (#51522)

* win_stat - add follow option and fix broken tests

* fix docs issues
This commit is contained in:
Jordan Borean 2019-01-31 15:56:06 +10:00 committed by GitHub
parent a9b459e406
commit 6a2aac487d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 138 additions and 19 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- win_stat - added the ``follow`` module option to follow ``path`` when getting the file or directory info

View file

@ -7,7 +7,7 @@
#Requires -Module Ansible.ModuleUtils.FileUtil
#Requires -Module Ansible.ModuleUtils.LinkUtil
function DateTo-Timestamp($start_date, $end_date) {
function ConvertTo-Timestamp($start_date, $end_date) {
if ($start_date -and $end_date) {
return (New-TimeSpan -Start $start_date -End $end_date).TotalSeconds
}
@ -33,12 +33,34 @@ function Get-FileChecksum($path, $algorithm) {
return $hash
}
function Get-FileInfo {
param([String]$Path, [Switch]$Follow)
$info = Get-AnsibleItem -Path $Path -ErrorAction SilentlyContinue
$link_info = $null
if ($null -ne $info) {
try {
$link_info = Get-Link -link_path $info.FullName
} catch {
$module.Warn("Failed to check/get link info for file: $($_.Exception.Message)")
}
# If follow=true we want to follow the link all the way back to root object
if ($Follow -and $null -ne $link_info -and $link_info.Type -in @("SymbolicLink", "JunctionPoint")) {
$info, $link_info = Get-FileInfo -Path $link_info.AbsolutePath -Follow
}
}
return $info, $link_info
}
$spec = @{
options = @{
path = @{ type='path'; required=$true; aliases=@( 'dest', 'name' ) }
get_checksum = @{ type='bool'; default=$true }
checksum_algorithm = @{ type='str'; default='sha1'; choices=@( 'md5', 'sha1', 'sha256', 'sha384', 'sha512' ) }
get_md5 = @{ type='bool'; default=$false; removed_in_version='2.9' }
follow = @{ type='bool'; default=$false }
}
supports_check_mode = $true
}
@ -49,10 +71,12 @@ $path = $module.Params.path
$get_md5 = $module.Params.get_md5
$get_checksum = $module.Params.get_checksum
$checksum_algorithm = $module.Params.checksum_algorithm
$follow = $module.Params.follow
$module.Result.stat = @{ exists=$false }
$info = Get-AnsibleItem -Path $path -ErrorAction SilentlyContinue
Load-LinkUtils
$info, $link_info = Get-FileInfo -Path $path -Follow:$follow
If ($null -ne $info) {
$epoch_date = Get-Date -Date "01/01/1970"
$attributes = @()
@ -77,9 +101,9 @@ If ($null -ne $info) {
# lnk_target = islnk or isjunction Target of the symlink. Note that relative paths remain relative
# lnk_source = islnk os isjunction Target of the symlink normalized for the remote filesystem
hlnk_targets = @()
creationtime = (DateTo-Timestamp -start_date $epoch_date -end_date $info.CreationTime)
lastaccesstime = (DateTo-Timestamp -start_date $epoch_date -end_date $info.LastAccessTime)
lastwritetime = (DateTo-Timestamp -start_date $epoch_date -end_date $info.LastWriteTime)
creationtime = (ConvertTo-Timestamp -start_date $epoch_date -end_date $info.CreationTime)
lastaccesstime = (ConvertTo-Timestamp -start_date $epoch_date -end_date $info.LastAccessTime)
lastwritetime = (ConvertTo-Timestamp -start_date $epoch_date -end_date $info.LastWriteTime)
# size = a file and directory - calculated below
path = $info.FullName
filename = $info.Name
@ -100,8 +124,8 @@ If ($null -ne $info) {
# values that are set according to the type of file
if ($info.Attributes.HasFlag([System.IO.FileAttributes]::Directory)) {
$stat.isdir = $true
$share_info = Get-WmiObject -Class Win32_Share -Filter "Path='$($stat.path -replace '\\', '\\')'"
if ($share_info -ne $null) {
$share_info = Get-CimInstance -ClassName Win32_Share -Filter "Path='$($stat.path -replace '\\', '\\')'"
if ($null -ne $share_info) {
$stat.isshared = $true
$stat.sharename = $share_info.Name
}
@ -137,13 +161,7 @@ If ($null -ne $info) {
}
# Get symbolic link, junction point, hard link info
Load-LinkUtils
try {
$link_info = Get-Link -link_path $info.FullName
} catch {
$module.Warn("Failed to check/get link info for file: $($_.Exception.Message)")
}
if ($link_info -ne $null) {
if ($null -ne $link_info) {
switch ($link_info.Type) {
"SymbolicLink" {
$stat.islnk = $true
@ -175,3 +193,4 @@ If ($null -ne $info) {
}
$module.ExitJson()

View file

@ -52,6 +52,14 @@ options:
default: sha1
choices: [ md5, sha1, sha256, sha384, sha512 ]
version_added: "2.3"
follow:
description:
- Whether to follow symlinks or junction points.
- In the case of C(path) pointing to another link, then that will
be followed until no more links are found.
type: bool
default: no
version_added: "2.8"
seealso:
- module: stat
- module: win_file

View file

@ -509,7 +509,7 @@ class ActionBase(with_metaclass(ABCMeta, object)):
path=path,
follow=follow,
get_checksum=checksum,
checksum_algo='sha1',
checksum_algorithm='sha1',
)
mystat = self._execute_module(module_name='stat', module_args=module_args, task_vars=all_vars,
wrap_async=False)

View file

@ -54,6 +54,7 @@
cmd.exe /c mklink /H "{{win_stat_dir}}\nested\hard-link.ps1" "{{win_stat_dir}}\nested\hard-target.txt"
cmd.exe /c mklink /J "{{win_stat_dir}}\junction-link" "{{win_stat_dir}}\junction-dest"
cmd.exe /c mklink /D "{{win_stat_dir}}\nested\nested\link-rel" "..\..\link-dest"
cmd.exe /c mklink /D "{{win_stat_dir}}\outer-link" "{{win_stat_dir}}\nested\nested\link-rel"
$date = Get-Date -Year 2016 -Month 11 -Day 1 -Hour 7 -Minute 10 -Second 5 -Millisecond 0
Get-ChildItem -Path "{{win_stat_dir}}" -Recurse | ForEach-Object {

View file

@ -140,6 +140,7 @@
- name: test win_stat on hard link file
win_stat:
path: '{{win_stat_dir}}\nested\hard-link.ps1'
follow: True # just verifies we don't do any weird follow logic for hard links
register: stat_hard_link
- name: check actual for hard link file
@ -386,6 +387,37 @@
- stat_file_symlink.stat.owner == 'BUILTIN\\Administrators'
- stat_file_symlink.stat.path == win_stat_dir + '\\file-link.txt'
- name: test win_stat of file symlink with follow
win_stat:
path: '{{win_stat_dir}}\file-link.txt'
follow: True
register: stat_file_symlink_follow
- name: assert file system with follow actual
assert:
that:
- stat_file_symlink_follow.stat.attributes == 'Archive'
- stat_file_symlink_follow.stat.checksum == 'a9993e364706816aba3e25717850c26c9cd0d89d'
- stat_file_symlink_follow.stat.creationtime is defined
- stat_file_symlink_follow.stat.exists == True
- stat_file_symlink_follow.stat.extension == '.ps1'
- stat_file_symlink_follow.stat.filename == 'file.ps1'
- stat_file_symlink_follow.stat.hlnk_targets == []
- stat_file_symlink_follow.stat.isarchive == True
- stat_file_symlink_follow.stat.isdir == False
- stat_file_symlink_follow.stat.ishidden == False
- stat_file_symlink_follow.stat.isjunction == False
- stat_file_symlink_follow.stat.islnk == False
- stat_file_symlink_follow.stat.isreadonly == False
- stat_file_symlink_follow.stat.isreg == True
- stat_file_symlink_follow.stat.isshared == False
- stat_file_symlink_follow.stat.lastaccesstime is defined
- stat_file_symlink_follow.stat.lastwritetime is defined
- stat_file_symlink_follow.stat.md5 is not defined
- stat_file_symlink_follow.stat.nlink == 1
- stat_file_symlink_follow.stat.owner == 'BUILTIN\\Administrators'
- stat_file_symlink_follow.stat.path == win_stat_dir + '\\nested\\file.ps1'
- name: test win_stat on relative symlink
win_stat:
path: '{{win_stat_dir}}\nested\nested\link-rel'
@ -417,6 +449,36 @@
- stat_rel_symlink.stat.checksum is not defined
- stat_rel_symlink.stat.md5 is not defined
- name: test win_stat on relative multiple symlink with follow
win_stat:
path: '{{win_stat_dir}}\outer-link'
follow: True
register: stat_symlink_follow
- name: assert directory relative symlink actual
assert:
that:
- stat_symlink_follow.stat.attributes == 'Directory'
- stat_symlink_follow.stat.creationtime is defined
- stat_symlink_follow.stat.exists == True
- stat_symlink_follow.stat.filename == 'link-dest'
- stat_symlink_follow.stat.hlnk_targets == []
- stat_symlink_follow.stat.isarchive == False
- stat_symlink_follow.stat.isdir == True
- stat_symlink_follow.stat.ishidden == False
- stat_symlink_follow.stat.isjunction == False
- stat_symlink_follow.stat.islnk == False
- stat_symlink_follow.stat.isreadonly == False
- stat_symlink_follow.stat.isreg == False
- stat_symlink_follow.stat.isshared == False
- stat_symlink_follow.stat.lastaccesstime is defined
- stat_symlink_follow.stat.lastwritetime is defined
- stat_symlink_follow.stat.nlink == 1
- stat_symlink_follow.stat.owner == 'BUILTIN\\Administrators'
- stat_symlink_follow.stat.path == win_stat_dir + '\\link-dest'
- stat_symlink_follow.stat.checksum is not defined
- stat_symlink_follow.stat.md5 is not defined
- name: test win_stat on junction
win_stat:
path: '{{win_stat_dir}}\junction-link'
@ -447,6 +509,35 @@
- stat_junction_point.stat.path == win_stat_dir + '\\junction-link'
- stat_junction_point.stat.size == 0
- name: test win_stat on junction with follow
win_stat:
path: '{{win_stat_dir}}\junction-link'
follow: True
register: stat_junction_point_follow
- name: assert junction with follow actual
assert:
that:
- stat_junction_point_follow.stat.attributes == 'Directory'
- stat_junction_point_follow.stat.creationtime is defined
- stat_junction_point_follow.stat.exists == True
- stat_junction_point_follow.stat.filename == 'junction-dest'
- stat_junction_point_follow.stat.hlnk_targets == []
- stat_junction_point_follow.stat.isarchive == False
- stat_junction_point_follow.stat.isdir == True
- stat_junction_point_follow.stat.ishidden == False
- stat_junction_point_follow.stat.isjunction == False
- stat_junction_point_follow.stat.islnk == False
- stat_junction_point_follow.stat.isreadonly == False
- stat_junction_point_follow.stat.isreg == False
- stat_junction_point_follow.stat.isshared == False
- stat_junction_point_follow.stat.lastaccesstime is defined
- stat_junction_point_follow.stat.lastwritetime is defined
- stat_junction_point_follow.stat.nlink == 1
- stat_junction_point_follow.stat.owner == 'BUILTIN\\Administrators'
- stat_junction_point_follow.stat.path == win_stat_dir + '\\junction-dest'
- stat_junction_point_follow.stat.size == 0
- name: test win_stat module non-existent path
win_stat:
path: '{{win_stat_dir}}\this_file_should_not_exist'

View file

@ -66,8 +66,6 @@ lib/ansible/modules/windows/win_security_policy.ps1 PSUseApprovedVerbs
lib/ansible/modules/windows/win_security_policy.ps1 PSUseDeclaredVarsMoreThanAssignments
lib/ansible/modules/windows/win_shell.ps1 PSAvoidUsingCmdletAliases
lib/ansible/modules/windows/win_shell.ps1 PSUseApprovedVerbs
lib/ansible/modules/windows/win_stat.ps1 PSAvoidUsingWMICmdlet
lib/ansible/modules/windows/win_stat.ps1 PSUseApprovedVerbs
lib/ansible/modules/windows/win_unzip.ps1 PSAvoidUsingCmdletAliases
lib/ansible/modules/windows/win_unzip.ps1 PSUseApprovedVerbs
lib/ansible/modules/windows/win_uri.ps1 PSAvoidUsingEmptyCatchBlock