changed to enable windows temp path override (#34967)
This commit is contained in:
parent
5b52bfad6d
commit
8edd1cf182
2 changed files with 81 additions and 29 deletions
|
@ -232,7 +232,7 @@ class ActionModule(ActionBase):
|
||||||
return content_tempfile
|
return content_tempfile
|
||||||
|
|
||||||
def _create_zip_tempfile(self, files, directories):
|
def _create_zip_tempfile(self, files, directories):
|
||||||
tmpdir = tempfile.mkdtemp()
|
tmpdir = tempfile.mkdtemp(dir=C.DEFAULT_LOCAL_TMP)
|
||||||
zip_file_path = os.path.join(tmpdir, "win_copy.zip")
|
zip_file_path = os.path.join(tmpdir, "win_copy.zip")
|
||||||
zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_STORED, True)
|
zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_STORED, True)
|
||||||
|
|
||||||
|
@ -259,14 +259,13 @@ class ActionModule(ActionBase):
|
||||||
if content is not None:
|
if content is not None:
|
||||||
os.remove(content_tempfile)
|
os.remove(content_tempfile)
|
||||||
|
|
||||||
def _copy_single_file(self, local_file, dest, source_rel, task_vars):
|
def _copy_single_file(self, local_file, dest, source_rel, task_vars, tmp):
|
||||||
if self._play_context.check_mode:
|
if self._play_context.check_mode:
|
||||||
module_return = dict(changed=True)
|
module_return = dict(changed=True)
|
||||||
return module_return
|
return module_return
|
||||||
|
|
||||||
# copy the file across to the server
|
# copy the file across to the server
|
||||||
tmp_path = self._make_tmp_path()
|
tmp_src = self._connection._shell.join_path(tmp, 'source')
|
||||||
tmp_src = self._connection._shell.join_path(tmp_path, 'source')
|
|
||||||
self._transfer_file(local_file, tmp_src)
|
self._transfer_file(local_file, tmp_src)
|
||||||
|
|
||||||
copy_args = self._task.args.copy()
|
copy_args = self._task.args.copy()
|
||||||
|
@ -280,14 +279,20 @@ class ActionModule(ActionBase):
|
||||||
)
|
)
|
||||||
copy_args.pop('content', None)
|
copy_args.pop('content', None)
|
||||||
|
|
||||||
copy_result = self._execute_module(module_name="copy", module_args=copy_args, task_vars=task_vars)
|
copy_result = self._execute_module(module_name="copy",
|
||||||
self._remove_tmp_path(tmp_path)
|
module_args=copy_args,
|
||||||
|
task_vars=task_vars,
|
||||||
|
tmp=tmp)
|
||||||
|
|
||||||
return copy_result
|
return copy_result
|
||||||
|
|
||||||
def _copy_zip_file(self, dest, files, directories, task_vars):
|
def _copy_zip_file(self, dest, files, directories, task_vars, tmp):
|
||||||
# create local zip file containing all the files and directories that
|
# create local zip file containing all the files and directories that
|
||||||
# need to be copied to the server
|
# need to be copied to the server
|
||||||
|
if self._play_context.check_mode:
|
||||||
|
module_return = dict(changed=True)
|
||||||
|
return module_return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
zip_file = self._create_zip_tempfile(files, directories)
|
zip_file = self._create_zip_tempfile(files, directories)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -301,15 +306,9 @@ class ActionModule(ActionBase):
|
||||||
|
|
||||||
zip_path = self._loader.get_real_file(zip_file)
|
zip_path = self._loader.get_real_file(zip_file)
|
||||||
|
|
||||||
if self._play_context.check_mode:
|
# send zip file to remote, file must end in .zip so
|
||||||
module_return = dict(changed=True)
|
# Com Shell.Application works
|
||||||
os.remove(zip_path)
|
tmp_src = self._connection._shell.join_path(tmp, 'source.zip')
|
||||||
os.removedirs(os.path.dirname(zip_path))
|
|
||||||
return module_return
|
|
||||||
|
|
||||||
# send zip file to remote, file must end in .zip so Com Shell.Application works
|
|
||||||
tmp_path = self._make_tmp_path()
|
|
||||||
tmp_src = self._connection._shell.join_path(tmp_path, 'source.zip')
|
|
||||||
self._transfer_file(zip_path, tmp_src)
|
self._transfer_file(zip_path, tmp_src)
|
||||||
|
|
||||||
# run the explode operation of win_copy on remote
|
# run the explode operation of win_copy on remote
|
||||||
|
@ -323,10 +322,12 @@ class ActionModule(ActionBase):
|
||||||
)
|
)
|
||||||
copy_args.pop('content', None)
|
copy_args.pop('content', None)
|
||||||
os.remove(zip_path)
|
os.remove(zip_path)
|
||||||
os.removedirs(os.path.dirname(zip_path))
|
|
||||||
|
|
||||||
module_return = self._execute_module(module_args=copy_args, task_vars=task_vars)
|
module_return = self._execute_module(module_name='copy',
|
||||||
self._remove_tmp_path(tmp_path)
|
module_args=copy_args,
|
||||||
|
task_vars=task_vars,
|
||||||
|
tmp=tmp)
|
||||||
|
os.removedirs(os.path.dirname(zip_path))
|
||||||
return module_return
|
return module_return
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
def run(self, tmp=None, task_vars=None):
|
||||||
|
@ -480,17 +481,23 @@ class ActionModule(ActionBase):
|
||||||
query_args.pop('src', None)
|
query_args.pop('src', None)
|
||||||
|
|
||||||
query_args.pop('content', None)
|
query_args.pop('content', None)
|
||||||
query_return = self._execute_module(module_args=query_args, task_vars=task_vars)
|
query_return = self._execute_module(module_args=query_args,
|
||||||
|
task_vars=task_vars,
|
||||||
|
tmp=tmp)
|
||||||
|
|
||||||
if query_return.get('failed') is True:
|
if query_return.get('failed') is True:
|
||||||
result.update(query_return)
|
result.update(query_return)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
if len(query_return['files']) > 0 or len(query_return['directories']) > 0 and tmp is None:
|
||||||
|
tmp = self._make_tmp_path()
|
||||||
|
|
||||||
if len(query_return['files']) == 1 and len(query_return['directories']) == 0:
|
if len(query_return['files']) == 1 and len(query_return['directories']) == 0:
|
||||||
# we only need to copy 1 file, don't mess around with zips
|
# we only need to copy 1 file, don't mess around with zips
|
||||||
file_src = query_return['files'][0]['src']
|
file_src = query_return['files'][0]['src']
|
||||||
file_dest = query_return['files'][0]['dest']
|
file_dest = query_return['files'][0]['dest']
|
||||||
copy_result = self._copy_single_file(file_src, dest, file_dest, task_vars)
|
copy_result = self._copy_single_file(file_src, dest, file_dest,
|
||||||
|
task_vars, tmp)
|
||||||
|
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
if copy_result.get('failed') is True:
|
if copy_result.get('failed') is True:
|
||||||
|
@ -500,13 +507,16 @@ class ActionModule(ActionBase):
|
||||||
# either multiple files or directories need to be copied, compress
|
# either multiple files or directories need to be copied, compress
|
||||||
# to a zip and 'explode' the zip on the server
|
# to a zip and 'explode' the zip on the server
|
||||||
# TODO: handle symlinks
|
# TODO: handle symlinks
|
||||||
result.update(self._copy_zip_file(dest, source_files['files'], source_files['directories'], task_vars))
|
result.update(self._copy_zip_file(dest, source_files['files'],
|
||||||
|
source_files['directories'],
|
||||||
|
task_vars, tmp))
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
else:
|
else:
|
||||||
# no operations need to occur
|
# no operations need to occur
|
||||||
result['failed'] = False
|
result['failed'] = False
|
||||||
result['changed'] = False
|
result['changed'] = False
|
||||||
|
|
||||||
# remove the content temp file if it was created
|
# remove the content temp file and remote tmp file if it was created
|
||||||
self._remove_tempfile_if_content_defined(content, content_tempfile)
|
self._remove_tempfile_if_content_defined(content, content_tempfile)
|
||||||
|
self._remove_tmp_path(tmp)
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -10,8 +10,41 @@ DOCUMENTATION = '''
|
||||||
version_added: ""
|
version_added: ""
|
||||||
short_description: Windows Powershell
|
short_description: Windows Powershell
|
||||||
description:
|
description:
|
||||||
- The only option whne using 'winrm' as a connection plugin
|
- The only option when using 'winrm' as a connection plugin
|
||||||
|
options:
|
||||||
|
remote_temp:
|
||||||
|
description:
|
||||||
|
- Temporary directory to use on targets when copying files to the host.
|
||||||
|
default: '%TEMP%'
|
||||||
|
ini:
|
||||||
|
- section: powershell
|
||||||
|
key: remote_tmp
|
||||||
|
vars:
|
||||||
|
- name: ansible_remote_tmp
|
||||||
|
admin_users:
|
||||||
|
description:
|
||||||
|
- List of users to be expected to have admin privileges, this is unused
|
||||||
|
in the PowerShell plugin
|
||||||
|
type: list
|
||||||
|
default: []
|
||||||
|
set_module_language:
|
||||||
|
description:
|
||||||
|
- Controls if we set the locale for moduels when executing on the
|
||||||
|
target.
|
||||||
|
- Windows only supports C(no) as an option.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
choices:
|
||||||
|
- 'no'
|
||||||
|
environment:
|
||||||
|
description:
|
||||||
|
- Dictionary of environment variables and their values to use when
|
||||||
|
executing commands.
|
||||||
|
type: dict
|
||||||
|
default: {}
|
||||||
'''
|
'''
|
||||||
|
# FIXME: admin_users and set_module_language don't belong here but must be set
|
||||||
|
# so they don't failk when someone get_option('admin_users') on this plugin
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
|
@ -19,7 +52,8 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_text
|
||||||
|
from ansible.plugins.shell import ShellBase
|
||||||
|
|
||||||
|
|
||||||
_common_args = ['PowerShell', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Unrestricted']
|
_common_args = ['PowerShell', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Unrestricted']
|
||||||
|
@ -1692,7 +1726,7 @@ Function Run($payload) {
|
||||||
from ansible.plugins import AnsiblePlugin
|
from ansible.plugins import AnsiblePlugin
|
||||||
|
|
||||||
|
|
||||||
class ShellModule(AnsiblePlugin):
|
class ShellModule(ShellBase):
|
||||||
|
|
||||||
# Common shell filenames that this plugin handles
|
# Common shell filenames that this plugin handles
|
||||||
# Powershell is handled differently. It's selected when winrm is the
|
# Powershell is handled differently. It's selected when winrm is the
|
||||||
|
@ -1766,10 +1800,18 @@ class ShellModule(AnsiblePlugin):
|
||||||
else:
|
else:
|
||||||
return self._encode_script('''Remove-Item "%s" -Force;''' % path)
|
return self._encode_script('''Remove-Item "%s" -Force;''' % path)
|
||||||
|
|
||||||
def mkdtemp(self, basefile, system=False, mode=None, tmpdir=None):
|
def mkdtemp(self, basefile=None, system=False, mode=None, tmpdir=None):
|
||||||
|
# Windows does not have an equivalent for the system temp files, so
|
||||||
|
# the param is ignored
|
||||||
basefile = self._escape(self._unquote(basefile))
|
basefile = self._escape(self._unquote(basefile))
|
||||||
# FIXME: Support system temp path and passed in tmpdir!
|
basetmpdir = tmpdir if tmpdir else self.get_option('remote_temp')
|
||||||
return self._encode_script('''(New-Item -Type Directory -Path $env:temp -Name "%s").FullName | Write-Host -Separator '';''' % basefile)
|
|
||||||
|
script = '''
|
||||||
|
$tmp_path = [System.Environment]::ExpandEnvironmentVariables('%s')
|
||||||
|
$tmp = New-Item -Type Directory -Path $tmp_path -Name '%s'
|
||||||
|
$tmp.FullName | Write-Host -Separator ''
|
||||||
|
''' % (basetmpdir, basefile)
|
||||||
|
return self._encode_script(script.strip())
|
||||||
|
|
||||||
def expand_user(self, user_home_path, username=''):
|
def expand_user(self, user_home_path, username=''):
|
||||||
# PowerShell only supports "~" (not "~username"). Resolve-Path ~ does
|
# PowerShell only supports "~" (not "~username"). Resolve-Path ~ does
|
||||||
|
|
Loading…
Reference in a new issue