From c7c7a63ee5db622a6136f644142f082efb0c0d49 Mon Sep 17 00:00:00 2001 From: Patrick Pelletier Date: Mon, 4 Mar 2013 11:32:25 -0500 Subject: [PATCH] Add support to directly set content in copy module --- lib/ansible/runner/action_plugins/copy.py | 30 +++++++++++++++++++++-- library/copy | 12 ++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/ansible/runner/action_plugins/copy.py b/lib/ansible/runner/action_plugins/copy.py index 60e29ff885..50851a0548 100644 --- a/lib/ansible/runner/action_plugins/copy.py +++ b/lib/ansible/runner/action_plugins/copy.py @@ -22,6 +22,7 @@ from ansible import errors from ansible.runner.return_data import ReturnData import base64 import stat +import tempfile class ActionModule(object): @@ -37,10 +38,14 @@ class ActionModule(object): options.update(complex_args) options.update(utils.parse_kv(module_args)) source = options.get('src', None) + content = options.get('content', None) dest = options.get('dest', None) - if (source is None and not 'first_available_file' in inject) or dest is None: - result=dict(failed=True, msg="src and dest are required") + if (source is None and content is None and not 'first_available_file' in inject) or dest is None: + result=dict(failed=True, msg="src or content and dest are required") + return ReturnData(conn=conn, result=result) + elif (source is not None or 'first_available_file' in inject) and content is not None: + result=dict(failed=True, msg="src and content are mutually exclusive") return ReturnData(conn=conn, result=result) # if we have first_available_file in our vars @@ -57,6 +62,17 @@ class ActionModule(object): if not found: results=dict(failed=True, msg="could not find src in first_available_file list") return ReturnData(conn=conn, result=results) + elif content is not None: + fd, tmp_content = tempfile.mkstemp() + f = os.fdopen(fd, 'w') + try: + f.write(content) + except Exception, err: + os.remove(tmp_content) + result = dict(failed=True, msg="could not write content temp file: %s" % err) + return ReturnData(conn=conn, result=result) + f.close() + source = tmp_content else: source = utils.template(self.runner.basedir, source, inject) source = utils.path_dwim(self.runner.basedir, source) @@ -73,6 +89,10 @@ class ActionModule(object): remote_md5 = self.runner._remote_md5(conn, tmp, dest) if remote_md5 == '3': # Destination is a directory + if content is not None: + os.remove(tmp_content) + result = dict(failed=True, msg="can not use content with a dir as dest") + return ReturnData(conn=conn, result=result) dest = os.path.join(dest, os.path.basename(source)) remote_md5 = self.runner._remote_md5(conn, tmp, dest) @@ -85,11 +105,15 @@ class ActionModule(object): diff = {} if self.runner.check: + if content is not None: + os.remove(tmp_content) 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) conn.put_file(source, tmp_src) + if content is not None: + os.remove(tmp_content) # fix file permissions when the copy is done as a different user if self.runner.sudo and self.runner.sudo_user != 'root': self.runner._low_level_exec_command(conn, "chmod a+r %s" % tmp_src, tmp) @@ -102,6 +126,8 @@ class ActionModule(object): # no need to transfer the file, already correct md5, but still need to call # the file module in case we want to change attributes + if content is not None: + os.remove(tmp_content) tmp_src = tmp + os.path.basename(source) module_args = "%s src=%s" % (module_args, tmp_src) if self.runner.check: diff --git a/library/copy b/library/copy index c57e95cbc2..88047635ea 100644 --- a/library/copy +++ b/library/copy @@ -31,10 +31,15 @@ description: options: src: description: - - Local path to a file to copy to the remote server; can be absolute or relative. - required: true + - Local path to a file to copy to the remote server; can be absolute or relative. Mutually exclusive with content. + required: false default: null aliases: [] + content: + description: + - Creates and/or set content of a file on the remote server. Mutually exclusive with content. + required: false + default: null dest: description: - Remote absolute path where the file should be copied to. @@ -76,7 +81,8 @@ def main(): module = AnsibleModule( # not checking because of daisy chain to file module argument_spec = dict( - src=dict(required=True), + src=dict(required=False), + content=dict(required=False), dest=dict(required=True), backup=dict(default=False, type='bool'), force = dict(default='yes', aliases=['thirsty'], type='bool'),