Add diff for both file contents and file attributes to lineinfile

Using the difflist feature added in ansible/ansible@c337293 we can add
two diffs to the `diff` dict returned as JSON: A `before` and `after` pair of
changed file contents and the diff of the file attributes.

n.b.: the difflist handling from the above commit is logically broken.
PR will follow.

Example output:

    TASK [change line and mode] ************************************************************
    changed: [localhost]
    --- before: /tmp/sshd_config (content)
    +++ after: /tmp/sshd_config (content)
    @@ -65,21 +65,21 @@
     X11DisplayOffset 10
     PrintMotd no
     PrintLastLog yes
     TCPKeepAlive yes
     #UseLogin no

     #MaxStartups 10:30:60
     #Banner /etc/issue.net

     # Allow client to pass locale environment variables
    -AcceptEnv LANG LC_*
    +AcceptEnv        LANG LC_* GF_ENV_*

     Subsystem sftp /usr/lib/openssh/sftp-server

     # Set this to 'yes' to enable PAM authentication, account processing,
     # and session processing. If this is enabled, PAM authentication will
     # be allowed through the ChallengeResponseAuthentication and
     # PasswordAuthentication.  Depending on your PAM configuration,
     # PAM authentication via ChallengeResponseAuthentication may bypass
     # the setting of "PermitRootLogin without-password".
     # If you just want the PAM account and session checks to run without

    --- before: /tmp/sshd_config (file attributes)
    +++ after: /tmp/sshd_config (file attributes)
    @@ -1,3 +1,3 @@
     {
    -    "mode": "0700"
    +    "mode": "0644"
     }
This commit is contained in:
Tobias Wolf 2016-01-27 12:33:24 +01:00 committed by Matt Clay
parent d9a071089b
commit 1ecc8544f6

View file

@ -166,10 +166,10 @@ def write_changes(module,lines,dest):
if valid:
module.atomic_move(tmpfile, os.path.realpath(dest))
def check_file_attrs(module, changed, message):
def check_file_attrs(module, changed, message, diff):
file_args = module.load_file_common_arguments(module.params)
if module.set_fs_attributes_if_different(file_args, False):
if module.set_fs_attributes_if_different(file_args, False, diff=diff):
if changed:
message += " and "
@ -182,6 +182,11 @@ def check_file_attrs(module, changed, message):
def present(module, dest, regexp, line, insertafter, insertbefore, create,
backup, backrefs):
diff = {'before': '',
'after': '',
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}
if not os.path.exists(dest):
if not create:
module.fail_json(rc=257, msg='Destination %s does not exist !' % dest)
@ -194,7 +199,8 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
lines = f.readlines()
f.close()
msg = ""
if module._diff:
diff['before'] = ''.join(lines)
if regexp is not None:
mre = re.compile(regexp)
@ -270,6 +276,9 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
msg = 'line added'
changed = True
if module._diff:
diff['after'] = ''.join(lines)
backupdest = ""
if changed and not module.check_mode:
if backup and os.path.exists(dest):
@ -277,10 +286,16 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create,
write_changes(module, lines, dest)
if module.check_mode and not os.path.exists(dest):
module.exit_json(changed=changed, msg=msg, backup=backupdest)
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=diff)
msg, changed = check_file_attrs(module, changed, msg)
module.exit_json(changed=changed, msg=msg, backup=backupdest)
attr_diff = {}
msg, changed = check_file_attrs(module, changed, msg, attr_diff)
attr_diff['before_header'] = '%s (file attributes)' % dest
attr_diff['after_header'] = '%s (file attributes)' % dest
difflist = [diff, attr_diff]
module.exit_json(changed=changed, msg=msg, backup=backupdest, diff=difflist)
def absent(module, dest, regexp, line, backup):
@ -288,11 +303,19 @@ def absent(module, dest, regexp, line, backup):
if not os.path.exists(dest):
module.exit_json(changed=False, msg="file not present")
msg = ""
msg = ''
diff = {'before': '',
'after': '',
'before_header': '%s (content)' % dest,
'after_header': '%s (content)' % dest}
f = open(dest, 'rb')
lines = f.readlines()
f.close()
if module._diff:
diff['before'] = ''.join(lines)
if regexp is not None:
cre = re.compile(regexp)
found = []
@ -308,6 +331,10 @@ def absent(module, dest, regexp, line, backup):
lines = filter(matcher, lines)
changed = len(found) > 0
if module._diff:
diff['after'] = ''.join(lines)
backupdest = ""
if changed and not module.check_mode:
if backup:
@ -317,8 +344,15 @@ def absent(module, dest, regexp, line, backup):
if changed:
msg = "%s line(s) removed" % len(found)
msg, changed = check_file_attrs(module, changed, msg)
module.exit_json(changed=changed, found=len(found), msg=msg, backup=backupdest)
attr_diff = {}
msg, changed = check_file_attrs(module, changed, msg, attr_diff)
attr_diff['before_header'] = '%s (file attributes)' % dest
attr_diff['after_header'] = '%s (file attributes)' % dest
difflist = [diff, attr_diff]
module.exit_json(changed=changed, found=len(found), msg=msg, backup=backupdest, diff=difflist)
def main():