#!/usr/bin/python # -*- coding: utf-8 -*- # (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 . import os import shutil import time def backuplocal(fn): """make a date-marked backup of the specified file, return True or False on success or failure""" # backups named basename-YYYY-MM-DD@HH:MM~ ext = time.strftime("%Y-%m-%d@%H:%M~", time.localtime(time.time())) backupdest = '%s.%s' % (fn, ext) try: shutil.copy2(fn, backupdest) except shutil.Error, e: return False, 'Could not make backup of %s to %s: %s' % (fn, backupdest, e) return True, backupdest def main(): module = AnsibleModule( # not checking because of daisy chain to file module check_invalid_arguments = False, argument_spec = dict( src=dict(required=True), dest=dict(required=True), backup=dict(default=False, choices=BOOLEANS), ) ) src = os.path.expanduser(module.params['src']) dest = os.path.expanduser(module.params['dest']) backup = module.boolean(module.params.get('backup', False)) if not os.path.exists(src): module.fail_json(msg="Source %s failed to transfer" % (src)) if not os.access(src, os.R_OK): module.fail_json(msg="Source %s not readable" % (src)) md5sum_src = module.md5(src) md5sum_dest = None if os.path.exists(dest): if not os.access(dest, os.W_OK): module.fail_json(msg="Destination %s not writable" % (dest)) if not os.access(dest, os.R_OK): module.fail_json(msg="Destination %s not readable" % (dest)) # Allow dest to be directory without compromising md5 check if (os.path.isdir(dest)): module.fail_json(msg="Destination %s cannot be a directory" % (dest)) md5sum_dest = module.md5(dest) else: if not os.access(os.path.dirname(dest), os.W_OK): module.fail_json(msg="Destination %s not writable" % (os.path.dirname(dest))) backup_file = None if md5sum_src != md5sum_dest: try: if backup: if os.path.exists(dest): success, msg = backuplocal(dest) if not success: module.fail_jason(msg=msg) else: backup_file = msg shutil.copyfile(src, dest) except shutil.Error: module.fail_json(msg="failed to copy: %s and %s are the same" % (src, dest)) except IOError: module.fail_json(msg="failed to copy: %s to %s" % (src, dest)) changed = True else: changed = False res_args = { 'dest':dest, 'src':src, 'md5sum':md5sum_src, 'changed':changed } if backup_file: res_args['backup_file'] = backup_file module.exit_json(**res_args) # this is magic, see lib/ansible/module_common.py #<> main()