win_copy: fix for copying encrypted file without pass (#31084)
* win_copy: fix for copying encrypted file without pass * fix pep8 issue * reduced the diff and fixed some minor issues
This commit is contained in:
parent
72237b63e7
commit
bba941cd5b
5 changed files with 63 additions and 10 deletions
|
@ -15,14 +15,14 @@ import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError, AnsibleFileNotFound
|
||||||
from ansible.module_utils._text import to_bytes, to_native, to_text
|
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean
|
from ansible.module_utils.parsing.convert_bool import boolean
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.hashing import checksum
|
from ansible.utils.hashing import checksum
|
||||||
|
|
||||||
|
|
||||||
def _walk_dirs(topdir, base_path=None, local_follow=False, trailing_slash_detector=None, checksum_check=False):
|
def _walk_dirs(topdir, loader, base_path=None, local_follow=False, trailing_slash_detector=None, checksum_check=False):
|
||||||
"""
|
"""
|
||||||
Walk a filesystem tree returning enough information to copy the files.
|
Walk a filesystem tree returning enough information to copy the files.
|
||||||
This is similar to the _walk_dirs function in ``copy.py`` but returns
|
This is similar to the _walk_dirs function in ``copy.py`` but returns
|
||||||
|
@ -30,6 +30,7 @@ def _walk_dirs(topdir, base_path=None, local_follow=False, trailing_slash_detect
|
||||||
a local file if wanted.
|
a local file if wanted.
|
||||||
|
|
||||||
:arg topdir: The directory that the filesystem tree is rooted at
|
:arg topdir: The directory that the filesystem tree is rooted at
|
||||||
|
:arg loader: The self._loader object from ActionBase
|
||||||
:kwarg base_path: The initial directory structure to strip off of the
|
:kwarg base_path: The initial directory structure to strip off of the
|
||||||
files for the destination directory. If this is None (the default),
|
files for the destination directory. If this is None (the default),
|
||||||
the base_path is set to ``top_dir``.
|
the base_path is set to ``top_dir``.
|
||||||
|
@ -100,7 +101,7 @@ def _walk_dirs(topdir, base_path=None, local_follow=False, trailing_slash_detect
|
||||||
|
|
||||||
if os.path.islink(filepath):
|
if os.path.islink(filepath):
|
||||||
# Dereference the symlnk
|
# Dereference the symlnk
|
||||||
real_file = os.path.realpath(filepath)
|
real_file = loader.get_real_file(os.path.realpath(filepath), decrypt=True)
|
||||||
if local_follow and os.path.isfile(real_file):
|
if local_follow and os.path.isfile(real_file):
|
||||||
# Add the file pointed to by the symlink
|
# Add the file pointed to by the symlink
|
||||||
r_files['files'].append(
|
r_files['files'].append(
|
||||||
|
@ -115,11 +116,12 @@ def _walk_dirs(topdir, base_path=None, local_follow=False, trailing_slash_detect
|
||||||
r_files['symlinks'].append({"src": os.readlink(filepath), "dest": dest_filepath})
|
r_files['symlinks'].append({"src": os.readlink(filepath), "dest": dest_filepath})
|
||||||
else:
|
else:
|
||||||
# Just a normal file
|
# Just a normal file
|
||||||
|
real_file = loader.get_real_file(filepath, decrypt=True)
|
||||||
r_files['files'].append(
|
r_files['files'].append(
|
||||||
{
|
{
|
||||||
"src": filepath,
|
"src": real_file,
|
||||||
"dest": dest_filepath,
|
"dest": dest_filepath,
|
||||||
"checksum": _get_local_checksum(checksum_check, filepath)
|
"checksum": _get_local_checksum(checksum_check, real_file)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -336,7 +338,7 @@ class ActionModule(ActionBase):
|
||||||
content = self._task.args.get('content', None)
|
content = self._task.args.get('content', None)
|
||||||
dest = self._task.args.get('dest', None)
|
dest = self._task.args.get('dest', None)
|
||||||
remote_src = boolean(self._task.args.get('remote_src', False), strict=False)
|
remote_src = boolean(self._task.args.get('remote_src', False), strict=False)
|
||||||
follow = boolean(self._task.args.get('follow', False), strict=False)
|
local_follow = boolean(self._task.args.get('local_follow', False), strict=False)
|
||||||
force = boolean(self._task.args.get('force', True), strict=False)
|
force = boolean(self._task.args.get('force', True), strict=False)
|
||||||
|
|
||||||
result['src'] = source
|
result['src'] = source
|
||||||
|
@ -412,7 +414,7 @@ class ActionModule(ActionBase):
|
||||||
result['operation'] = 'folder_copy'
|
result['operation'] = 'folder_copy'
|
||||||
|
|
||||||
# Get a list of the files we want to replicate on the remote side
|
# Get a list of the files we want to replicate on the remote side
|
||||||
source_files = _walk_dirs(source, local_follow=follow,
|
source_files = _walk_dirs(source, self._loader, local_follow=local_follow,
|
||||||
trailing_slash_detector=self._connection._shell.path_has_trailing_slash,
|
trailing_slash_detector=self._connection._shell.path_has_trailing_slash,
|
||||||
checksum_check=force)
|
checksum_check=force)
|
||||||
|
|
||||||
|
@ -426,6 +428,14 @@ class ActionModule(ActionBase):
|
||||||
else:
|
else:
|
||||||
result['operation'] = 'file_copy'
|
result['operation'] = 'file_copy'
|
||||||
|
|
||||||
|
# If the local file does not exist, get_real_file() raises AnsibleFileNotFound
|
||||||
|
try:
|
||||||
|
source_full = self._loader.get_real_file(source, decrypt=True)
|
||||||
|
except AnsibleFileNotFound as e:
|
||||||
|
result['failed'] = True
|
||||||
|
result['msg'] = "could not find src=%s, %s" % (source_full, to_text(e))
|
||||||
|
return result
|
||||||
|
|
||||||
original_basename = os.path.basename(source)
|
original_basename = os.path.basename(source)
|
||||||
result['original_basename'] = original_basename
|
result['original_basename'] = original_basename
|
||||||
|
|
||||||
|
@ -440,16 +450,16 @@ class ActionModule(ActionBase):
|
||||||
filename = os.path.basename(unix_path)
|
filename = os.path.basename(unix_path)
|
||||||
check_dest = os.path.dirname(unix_path)
|
check_dest = os.path.dirname(unix_path)
|
||||||
|
|
||||||
file_checksum = _get_local_checksum(force, source)
|
file_checksum = _get_local_checksum(force, source_full)
|
||||||
source_files['files'].append(
|
source_files['files'].append(
|
||||||
dict(
|
dict(
|
||||||
src=source,
|
src=source_full,
|
||||||
dest=filename,
|
dest=filename,
|
||||||
checksum=file_checksum
|
checksum=file_checksum
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result['checksum'] = file_checksum
|
result['checksum'] = file_checksum
|
||||||
result['size'] = os.path.getsize(to_bytes(source, errors='surrogate_or_strict'))
|
result['size'] = os.path.getsize(to_bytes(source_full, errors='surrogate_or_strict'))
|
||||||
|
|
||||||
# find out the files/directories/symlinks that we need to copy to the server
|
# find out the files/directories/symlinks that we need to copy to the server
|
||||||
query_args = self._task.args.copy()
|
query_args = self._task.args.copy()
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
65653164323866373138353632323531393664393563633665373635623763353561386431373366
|
||||||
|
3232353263363034313136663062623336663463373966320a333763323032646463386432626161
|
||||||
|
36386330356637666362396661653935653064623038333031653335626164376465353235303636
|
||||||
|
3335616231663838620a303632343938326538656233393562303162343261383465623261646664
|
||||||
|
33613932343461626339333832363930303962633364303736376634396364643861
|
5
test/integration/targets/win_copy/files-vault/readme.txt
Normal file
5
test/integration/targets/win_copy/files-vault/readme.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
This directory contains some files that have been encrypted with ansible-vault.
|
||||||
|
|
||||||
|
This is to test out the decrypt parameter in win_copy.
|
||||||
|
|
||||||
|
The password is: password
|
6
test/integration/targets/win_copy/files-vault/vault-file
Normal file
6
test/integration/targets/win_copy/files-vault/vault-file
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
30353665333635633433356261616636356130386330363962386533303566313463383734373532
|
||||||
|
3933643234323638623939613462346361313431363939370a303532656338353035346661353965
|
||||||
|
34656231633238396361393131623834316262306533663838336362366137306562646561383766
|
||||||
|
6363373965633337640a373666336461613337346131353564383134326139616561393664663563
|
||||||
|
3431
|
|
@ -26,6 +26,32 @@
|
||||||
register: fail_missing_parent_dir
|
register: fail_missing_parent_dir
|
||||||
failed_when: "'Destination directory ' + test_win_copy_path + '\\missing-dir does not exist' not in fail_missing_parent_dir.msg"
|
failed_when: "'Destination directory ' + test_win_copy_path + '\\missing-dir does not exist' not in fail_missing_parent_dir.msg"
|
||||||
|
|
||||||
|
- name: fail to copy an encrypted file without the password set
|
||||||
|
win_copy:
|
||||||
|
src: '{{role_path}}/files-vault/vault-file'
|
||||||
|
dest: '{{test_win_copy_path}}\file'
|
||||||
|
register: fail_copy_encrypted_file
|
||||||
|
ignore_errors: yes # weird failed_when doesn't work in this case
|
||||||
|
|
||||||
|
- name: assert failure message when copying an encrypted file without the password set
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- fail_copy_encrypted_file|failed
|
||||||
|
- fail_copy_encrypted_file.msg == 'A vault password or secret must be specified to decrypt {{role_path}}/files-vault/vault-file'
|
||||||
|
|
||||||
|
- name: fail to copy a directory with an encrypted file without the password
|
||||||
|
win_copy:
|
||||||
|
src: '{{role_path}}/files-vault'
|
||||||
|
dest: '{{test_win_copy_path}}'
|
||||||
|
register: fail_copy_directory_with_enc_file
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: assert failure message when copying a directory that contains an encrypted file without the password set
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- fail_copy_directory_with_enc_file|failed
|
||||||
|
- fail_copy_directory_with_enc_file.msg == 'A vault password or secret must be specified to decrypt {{role_path}}/files-vault/vault-file'
|
||||||
|
|
||||||
- name: copy with content (check mode)
|
- name: copy with content (check mode)
|
||||||
win_copy:
|
win_copy:
|
||||||
content: a
|
content: a
|
||||||
|
|
Loading…
Reference in a new issue