From 11b50671ba5b0998efe64b96fa5c0d19266e3c06 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Thu, 24 Aug 2017 15:35:53 +0200 Subject: [PATCH] win_robocopy: Check-mode support, improved return code and docs (#25410) * win_robocopy: Cleanup logic, check-mode support * win_robocopy: Cleanup logic, check-mode support This PR includes: - Improved check-mode support - Clean up documentation - Clean up code structure - Add warnings in special cases * minor fix for typo --- lib/ansible/modules/windows/win_robocopy.ps1 | 133 ++++++++----------- lib/ansible/modules/windows/win_robocopy.py | 77 +++++------ 2 files changed, 92 insertions(+), 118 deletions(-) diff --git a/lib/ansible/modules/windows/win_robocopy.ps1 b/lib/ansible/modules/windows/win_robocopy.ps1 index d7f928738f..3e3c9861bf 100644 --- a/lib/ansible/modules/windows/win_robocopy.ps1 +++ b/lib/ansible/modules/windows/win_robocopy.ps1 @@ -1,40 +1,26 @@ #!powershell -# This file is part of Ansible # # Copyright 2015, Corwin Brown -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # WANT_JSON # POWERSHELL_COMMON $params = Parse-Args $args -supports_check_mode $true - $check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false $src = Get-AnsibleParam -obj $params -name "src" -type "path" -failifempty $true $dest = Get-AnsibleParam -obj $params -name "dest" -type "path" -failifempty $true $purge = Get-AnsibleParam -obj $params -name "purge" -type "bool" -default $false $recurse = Get-AnsibleParam -obj $params -name "recurse" -type "bool" -default $false -$flags = Get-AnsibleParam -obj $params -name "flags" -type "string" -default $null +$flags = Get-AnsibleParam -obj $params -name "flags" -type "string" $result = @{ - src = $src - dest = $dest - recurse = $recurse - purge = $purge changed = $false + dest = $dest + purge = $purge + recurse = $recurse + src = $src } # Search for an Error Message @@ -43,7 +29,7 @@ Function SearchForError($cmd_output, $default_msg) { $separator_count = 0 $error_msg = $default_msg ForEach ($line in $cmd_output) { - if (-Not $line) { + if (-not $line) { continue } @@ -51,9 +37,8 @@ Function SearchForError($cmd_output, $default_msg) { if (Select-String -InputObject $line -pattern "^(\s+)?(\-+)(\s+)?$") { $separator_count += 1 } - } - Else { - If (Select-String -InputObject $line -pattern "error") { + } else { + if (Select-String -InputObject $line -pattern "error") { $error_msg = $line break } @@ -63,15 +48,16 @@ Function SearchForError($cmd_output, $default_msg) { return $error_msg } -# Build Arguments -$robocopy_opts = @() - -if (-Not (Test-Path $src)) { +if (-not (Test-Path -Path $src)) { Fail-Json $result "$src does not exist!" } -$robocopy_opts += $src -$robocopy_opts += $dest +# Build Arguments +$robocopy_opts = @($src, $dest) + +if ($check_mode) { + $robocopy_opts += "/l" +} if ($flags -eq $null) { if ($purge) { @@ -81,85 +67,80 @@ if ($flags -eq $null) { if ($recurse) { $robocopy_opts += "/e" } -} -Else { +} else { ForEach ($f in $flags.split(" ")) { $robocopy_opts += $f } } $result.flags = $flags +$result.cmd = "$robocopy $robocopy_opts" -$robocopy_output = "" -$rc = 0 -If ($check_mode -eq $true) { - $robocopy_output = "Would have copied the contents of $src to $dest" - $rc = 0 -} -Else { - Try { - &robocopy $robocopy_opts | Tee-Object -Variable robocopy_output | Out-Null - $rc = $LASTEXITCODE - } - Catch { - $ErrorMessage = $_.Exception.Message - Fail-Json $result "Error synchronizing $src to $dest! Msg: $ErrorMessage" - } +Try { + $robocopy_output = &robocopy $robocopy_opts + $rc = $LASTEXITCODE +} Catch { + Fail-Json $result "Error synchronizing $src to $dest! Msg: $($_.Exception.Message)" } -$result.return_code = $rc +$result.msg = "Success" $result.output = $robocopy_output +$result.return_code = $rc # Backward compatibility +$result.rc = $rc + +switch ($rc) { -$cmd_msg = "Success" -$changed = $false -switch ($rc) -{ 0 { - $cmd_msg = "No files copied." + $result.msg = "No files copied." } 1 { - $cmd_msg = "Files copied successfully!" - $changed = $true + $result.msg = "Files copied successfully!" + $result.changed = $true + $result.failed = $false } 2 { - $cmd_msg = "Some Extra files or directories were detected. No files were copied." - $changed = $true + $result.msg = "Some Extra files or directories were detected. No files were copied." + Add-Warning $result $result.msg + $result.failed = $false } 3 { - $cmd_msg = "(2+1) Some files were copied. Additional files were present." - $changed = $true + $result.msg = "(2+1) Some files were copied. Additional files were present." + Add-Warning $result $result.msg + $result.changed = $true + $result.failed = $false } 4 { - $cmd_msg = "Some mismatched files or directories were detected. Housekeeping might be required!" - $changed = $true + $result.msg = "Some mismatched files or directories were detected. Housekeeping might be required!" + Add-Warning $result $result.msg + $result.changed = $true + $result.failed = $false } 5 { - $cmd_msg = "(4+1) Some files were copied. Some files were mismatched." - $changed = $true + $result.msg = "(4+1) Some files were copied. Some files were mismatched." + Add-Warning $result $result.msg + $result.changed = $true + $result.failed = $false } 6 { - $cmd_msg = "(4+2) Additional files and mismatched files exist. No files were copied." - $changed = $true + $result.msg = "(4+2) Additional files and mismatched files exist. No files were copied." + $result.failed = $false } 7 { - $cmd_msg = "(4+1+2) Files were copied, a file mismatch was present, and additional files were present." - $changed = $true + $result.msg = "(4+1+2) Files were copied, a file mismatch was present, and additional files were present." + Add-Warning $result $result.msg + $result.changed = $true + $result.failed = $false } 8 { - $error_msg = SearchForError $robocopy_output "Some files or directories could not be copied!" - Fail-Json $result $error_msg + Fail-Json $result (SearchForError $robocopy_output "Some files or directories could not be copied!") } { @(9, 10, 11, 12, 13, 14, 15) -contains $_ } { - $error_msg = SearchForError $robocopy_output "Fatal error. Check log message!" - Fail-Json $result $error_msg + Fail-Json $result (SearchForError $robocopy_output "Fatal error. Check log message!") } 16 { - $error_msg = SearchForError $robocopy_output "Serious Error! No files were copied! Do you have permissions to access $src and $dest?" - Fail-Json $result $error_msg + Fail-Json $result (SearchForError $robocopy_output "Serious Error! No files were copied! Do you have permissions to access $src and $dest?") } + } -$result.msg = $cmd_msg -$result.changed = $changed - Exit-Json $result diff --git a/lib/ansible/modules/windows/win_robocopy.py b/lib/ansible/modules/windows/win_robocopy.py index a5aa50a3fb..23eb495c88 100644 --- a/lib/ansible/modules/windows/win_robocopy.py +++ b/lib/ansible/modules/windows/win_robocopy.py @@ -25,52 +25,45 @@ ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} - DOCUMENTATION = r''' --- module: win_robocopy -version_added: "2.2" -short_description: Synchronizes the contents of two directories using Robocopy. +version_added: '2.2' +short_description: Synchronizes the contents of two directories using Robocopy description: - - Synchronizes the contents of two directories on the remote machine. Under the hood this just calls out to RoboCopy, since that should be available - on most modern Windows Systems. +- Synchronizes the contents of two directories on the remote machine. +- Under the hood this just calls out to RoboCopy, since that should be available + on most modern Windows Systems. options: src: description: - - Source file/directory to sync. + - Source file/directory to sync. required: true dest: description: - - Destination file/directory to sync (Will receive contents of src). + - Destination file/directory to sync (Will receive contents of src). required: true recurse: description: - - Includes all subdirectories (Toggles the `/e` flag to RoboCopy). If "flags" is set, this will be ignored. - choices: - - true - - false - default: false - required: false + - Includes all subdirectories (Toggles the C(/e) flag to RoboCopy). + - If C(flags) is set, this will be ignored. + type: bool + default: 'no' purge: description: - - Deletes any files/directories found in the destination that do not exist in the source (Toggles the `/purge` flag to RoboCopy). If "flags" is - set, this will be ignored. - choices: - - true - - false - default: false - required: false + - Deletes any files/directories found in the destination that do not exist in the source. + - Toggles the C(/purge) flag to RoboCopy. If C(flags) is set, this will be ignored. + type: bool + default: 'no' flags: description: - - Directly supply Robocopy flags. If set, purge and recurse will be ignored. - default: None - required: false -author: Corwin Brown (@blakfeld) + - Directly supply Robocopy flags. If set, C(purge) and C(recurse) will be ignored. +author: +- Corwin Brown (@blakfeld) notes: - - This is not a complete port of the "synchronize" module. Unlike the "synchronize" module this only performs the sync/copy on the remote machine, - not from the master to the remote machine. - - This module does not currently support all Robocopy flags. - - Works on Windows 7, Windows 8, Windows Server 2k8, and Windows Server 2k12 +- This is not a complete port of the M(synchronize) module. Unlike the M(synchronize) module this only performs the sync/copy on the remote machine, + not from the master to the remote machine. +- This module does not currently support all Robocopy flags. ''' EXAMPLES = r''' @@ -83,22 +76,22 @@ EXAMPLES = r''' win_robocopy: src: C:\DirectoryOne dest: C:\DirectoryTwo - recurse: True + recurse: yes - name: Sync the contents of one directory to another, and remove any files/directories found in destination that do not exist in the source win_robocopy: src: C:\DirectoryOne dest: C:\DirectoryTwo - purge: True + purge: yes - name: Sync content in recursive mode, removing any files/directories found in destination that do not exist in the source win_robocopy: src: C:\DirectoryOne dest: C:\DirectoryTwo - recurse: True - purge: True + recurse: yes + purge: yes -- name: Sync Two Directories in recursive and purging mode, specifying additional special flags +- name: Sync two directories in recursive and purging mode, specifying additional special flags win_robocopy: src: C:\DirectoryOne dest: C:\DirectoryTwo @@ -106,16 +99,21 @@ EXAMPLES = r''' ''' RETURN = r''' +cmd: + description: The used command line + returned: always + type: string + sample: robocopy C:\DirectoryOne C:\DirectoryTwo /e /purge src: description: The Source file/directory of the sync. returned: always type: string - sample: c:\Some\Path + sample: C:\Some\Path dest: description: The Destination file/directory of the sync. returned: always type: string - sample: c:\Some\Path + sample: C:\Some\Path recurse: description: Whether or not the recurse flag was toggled. returned: always @@ -130,9 +128,9 @@ flags: description: Any flags passed in by the user. returned: always type: string - sample: "/e /purge" + sample: /e /purge rc: - description: The return code retuned by robocopy. + description: The return code returned by robocopy. returned: success type: int sample: 1 @@ -146,9 +144,4 @@ msg: returned: always type: string sample: No files copied! -changed: - description: Whether or not any changes were made. - returned: always - type: bool - sample: False '''