diff --git a/lib/ansible/runner/action_plugins/copy.py b/lib/ansible/runner/action_plugins/copy.py index f017b5e1f5..6452d27e3a 100644 --- a/lib/ansible/runner/action_plugins/copy.py +++ b/lib/ansible/runner/action_plugins/copy.py @@ -111,7 +111,7 @@ class ActionModule(object): return ReturnData(conn=conn, result=dict(changed=True), diff=diff) # transfer the file to a remote tmp location - tmp_src = tmp + os.path.basename(source) + tmp_src = tmp + 'source' conn.put_file(source, tmp_src) if content is not None: os.remove(tmp_content) @@ -120,7 +120,7 @@ class ActionModule(object): self.runner._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp) # run the copy module - module_args = "%s src=%s" % (module_args, pipes.quote(tmp_src)) + module_args = "%s src=%s original_basename=%s" % (module_args, pipes.quote(tmp_src), pipes.quote(os.path.basename(source))) return self.runner._execute_module(conn, tmp, 'copy', module_args, inject=inject, complex_args=complex_args) else: diff --git a/lib/ansible/runner/action_plugins/template.py b/lib/ansible/runner/action_plugins/template.py index a4c9bdd4ab..0f7b49352c 100644 --- a/lib/ansible/runner/action_plugins/template.py +++ b/lib/ansible/runner/action_plugins/template.py @@ -105,7 +105,7 @@ class ActionModule(object): self.runner._low_level_exec_command(conn, "chmod a+r %s" % xfered, tmp) # run the copy module - module_args = "%s src=%s dest=%s" % (module_args, pipes.quote(xfered), pipes.quote(dest)) + module_args = "%s src=%s dest=%s original_basename=%s" % (module_args, pipes.quote(xfered), pipes.quote(dest), pipes.quote(os.path.basename(source))) if self.runner.check: return ReturnData(conn=conn, comm_ok=True, result=dict(changed=True), diff=dict(before_header=dest, after_header=source, before=dest_contents, after=resultant)) diff --git a/library/copy b/library/copy index d8d5410b8a..b1b95bf2df 100644 --- a/library/copy +++ b/library/copy @@ -82,11 +82,12 @@ def main(): module = AnsibleModule( # not checking because of daisy chain to file module argument_spec = dict( - src = dict(required=False), - content = dict(required=False), - dest = dict(required=True), - backup = dict(default=False, type='bool'), - force = dict(default=True, aliases=['thirsty'], type='bool'), + src = dict(required=False), + original_basename = dict(required=False), # used to handle 'dest is a directory' via template, a slight hack + content = dict(required=False), + dest = dict(required=True), + backup = dict(default=False, type='bool'), + force = dict(default=True, aliases=['thirsty'], type='bool'), ), add_file_common_args=True, ) @@ -95,6 +96,7 @@ def main(): dest = os.path.expanduser(module.params['dest']) backup = module.params['backup'] force = module.params['force'] + original_basename = module.params.get('original_basename',None) if not os.path.exists(src): module.fail_json(msg="Source %s failed to transfer" % (src)) @@ -109,6 +111,8 @@ def main(): module.exit_json(msg="file already exists", src=src, dest=dest, changed=False) if (os.path.isdir(dest)): basename = os.path.basename(src) + if original_basename: + basename = original_basename dest = os.path.join(dest, basename) if os.access(dest, os.R_OK): md5sum_dest = module.md5(dest) @@ -128,7 +132,7 @@ def main(): if os.path.islink(dest): os.unlink(dest) open(dest, 'w').close() - #TODO:pid + epoch should avoid most collisions, hostname/mac for those using nfs? + # TODO:pid + epoch should avoid most collisions, hostname/mac for those using nfs? # might be an issue with exceeding path length dest_tmp = "%s.%s.%s.tmp" % (dest,os.getpid(),time.time()) shutil.copyfile(src, dest_tmp)