diff --git a/lib/ansible/connection.py b/lib/ansible/connection.py index 11faac402bd..e33e7e0e312 100755 --- a/lib/ansible/connection.py +++ b/lib/ansible/connection.py @@ -142,6 +142,15 @@ class ParamikoConnection(object): raise errors.AnsibleError("failed to transfer file to %s" % out_path) sftp.close() + def fetch_file(self, in_path, out_path): + sftp = self.ssh.open_sftp() + try: + sftp.get(in_path, out_path) + except IOError: + traceback.print_exc() + raise errors.AnsibleError("failed to transfer file from %s" % in_path) + sftp.close() + def close(self): ''' terminate the connection ''' @@ -184,6 +193,10 @@ class LocalConnection(object): traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path) + def fetch_file(self, in_path, out_path): + ''' fetch a file from local to local -- for copatibility ''' + self.put_file(in_path, out_path) + def close(self): ''' terminate the connection; nothing to do here ''' diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index b2cf3518b99..e112081cf2f 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -460,6 +460,48 @@ class Runner(object): # ***************************************************** + def _execute_fetch(self, conn, host, tmp): + ''' handler for fetch operations ''' + + #load up options + options = utils.parse_kv(self.module_args) + source = options['src'] + dest = options['dest'] + + changed = False + failed = None + ok = True + error = None + + #get old md5 + local_md5 = None + if os.path.exists(dest): + local_md5 = os.popen("md5sum %s" % dest).read().split()[0] + + #get new md5 + remote_md5 = self._exec_command(conn, "md5sum %s" % source, tmp, True)[0].split()[0] + + if remote_md5 != local_md5: + #fetch the file and check for changes + conn.fetch_file(source, dest) + new_md5 = os.popen("md5sum %s" % dest).read().split()[0] + changed = (new_md5 != local_md5) + if new_md5 != remote_md5: + error = "new md5 does not match remote md5" + else: + new_md5 = local_md5 + + if error: + ok = False + failed = True + data = {'msg': error, 'failed': True, 'md5sum': new_md5, 'changed': changed} + else: + data = {'changed': changed, 'md5sum': new_md5} + + return (host, ok, data, failed) + + # ***************************************************** + def _chain_file_module(self, conn, tmp, data, err, options, executed): ''' handles changing file attribs after copy/template operations ''' @@ -549,6 +591,8 @@ class Runner(object): if self.module_name == 'copy': result = self._execute_copy(conn, host, tmp) + elif self.module_name == 'fetch': + result = self._execute_fetch(conn, host, tmp) elif self.module_name == 'template': result = self._execute_template(conn, host, tmp) else: diff --git a/library/fetch b/library/fetch new file mode 100755 index 00000000000..f26337a490a --- /dev/null +++ b/library/fetch @@ -0,0 +1,24 @@ +#!/usr/bin/python + +# (c) 2012, Michael DeHaan +# +# This file is part of Ansible +# +# 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 . +# + +### THIS FILE IS FOR REFERENCE OR FUTURE USE ### + +# See lib/ansible/runner.py for implementation of the fetch functionality # +