ansible.windows icon indicating copy to clipboard operation
ansible.windows copied to clipboard

win_template: diff output is not produced

Open jborean93 opened this issue 4 years ago • 26 comments

From @mr-fIErcE on Dec 25, 2017 20:45

ISSUE TYPE
  • Bug Report
COMPONENT NAME

win_template

ANSIBLE VERSION
ansible 2.4.2.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/sd/ansible']
  ansible python module location = /usr/lib/python2.6/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.6.6 (r266:84292, Oct 12 2012, 14:23:48) [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)]
CONFIGURATION

DEFAULT_HOST_LIST(/etc/ansible/ansible.cfg) = [u'/sd/ansible/hosts'] DEFAULT_MODULE_PATH(/etc/ansible/ansible.cfg) = [u'/sd/ansible']

OS / ENVIRONMENT

ansible server: RHEL 6.4 managed host: Windows Server 2008 R2 / Windows Server 2012 R2

SUMMARY

win_template module does not produce diff output when ansible-playbook is invoked with --diff option

STEPS TO REPRODUCE

difftest.j2:

{{ var }}

difftest.yml:

- name: diff test
  hosts: aes-virt
  gather_facts: False
  tasks:
   - name: get random value
     set_fact:
       var: "{{ 100 | random }}"
   - name: test template
     win_template:
       src: /sd/ansible/difftest.j2
       dest: C:\test.txt
EXPECTED RESULTS

Changes in file produced by win_template module are shown as a diff, similar to following:

TASK [difftest : test template] *************************************************************************************************************************************************************************************************************
--- before: /tmp/testfile
+++ after: /tmp/tmpLCgbUU/t.j2
@@ -1,1 +1,1 @@
-93
+6

changed: [aes-virt -> localhost]
ACTUAL RESULTS

Diff is not produced.

root@fond1:/sd/ansible # ansible-playbook difftest.yml --diff -vvvv
ansible-playbook 2.4.2.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/sd/ansible']
  ansible python module location = /usr/lib/python2.6/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 2.6.6 (r266:84292, Oct 12 2012, 14:23:48) [GCC 4.4.6 20120305 (Red Hat 4.4.6-4)]
Using /etc/ansible/ansible.cfg as config file
setting up inventory plugins
Parsed /sd/ansible/hosts inventory source with ini plugin
Loading callback plugin default of type stdout, v2.0 from /usr/lib/python2.6/site-packages/ansible/plugins/callback/__init__.pyc

PLAYBOOK: difftest.yml ********************************************************************************************************************************************************************************************************************************************************
1 plays in difftest.yml

PLAY [diff test] **************************************************************************************************************************************************************************************************************************************************************
META: ran handlers

TASK [get random value] *******************************************************************************************************************************************************************************************************************************************************
task path: /sd/ansible/difftest.yml:5
ok: [aes-virt] => {
    "ansible_facts": {
        "var": "29"
    },
    "changed": false
}

TASK [test template] **********************************************************************************************************************************************************************************************************************************************************
task path: /sd/ansible/difftest.yml:8
<172.22.10.12> ESTABLISH WINRM CONNECTION FOR USER: adminaes on PORT 5986 TO 172.22.10.12
EXEC (via pipeline wrapper)
EXEC (via pipeline wrapper)
Using module file /usr/lib/python2.6/site-packages/ansible/modules/windows/win_stat.ps1
EXEC (via pipeline wrapper)
Using module file /usr/lib/python2.6/site-packages/ansible/modules/windows/win_file.ps1
EXEC (via pipeline wrapper)
Using module file /usr/lib/python2.6/site-packages/ansible/modules/windows/slurp.ps1
EXEC (via pipeline wrapper)
<172.22.10.12> PUT "/tmp/tmp5f86Nc/difftest.j2" TO "C:\Users\adminaes\AppData\Local\Temp\ansible-tmp-1514234201.16-102084777883269\source"
Using module file /usr/lib/python2.6/site-packages/ansible/modules/windows/win_copy.ps1
EXEC (via pipeline wrapper)
changed: [aes-virt] => {
    "changed": true,
    "checksum": "ef2781bbe133c16adb6600f5d01c3683f584384e",
    "diff": {}
}
META: ran handlers
META: ran handlers

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************************************
aes-virt                   : ok=2    changed=1    unreachable=0    failed=0

Copied from original issue: ansible/ansible#34226

jborean93 avatar Mar 11 '20 06:03 jborean93

From @mr-fIErcE on Dec 25, 2017 20:52

totally forgot to mention that it worked as expected in ansible 2.3.0

jborean93 avatar Mar 11 '20 06:03 jborean93

From @maxamillion on Jan 02, 2018 16:11

!needs_triage

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Jan 10, 2018 08:25

I have (sort of) reproduced this. I can get diff output from win_template, but it appears that no output is produced if the template destination does not already exist. So on subsequent runs I see diff output. I will investigate further.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Jan 11, 2018 08:16

My previous comment is wrong - I was testing with ansible 2.3.0.0. I can reproduce this behaviour with latest devel branch.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jborean93 on Jan 11, 2018 11:09

This is due to the change from sharing the copy action plugin with the posix side to now our own special windows variant in the 2.4. Unfortunately in this process the diff mode was missed and has to be readers.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Jan 12, 2018 17:42

Thanks @jborean93

I took a look at the win_copy action plugin to see if I could re-add the diff support, and made the following change. Although it seems to put the diff info into the results, for some reason the diff still isn't displayed. I am not yet sure if this is the only place it might need adding (due to win copy's zip mode - not sure what an appropriate diff for a compressed file set would be - probably just a message saying 'binary files differ' or 'compressed files differ').

I will dig in some more next week.



diff --git a/lib/ansible/plugins/action/win_copy.py b/lib/ansible/plugins/action/wi
index b501381..2a36072 100644
--- a/lib/ansible/plugins/action/win_copy.py
+++ b/lib/ansible/plugins/action/win_copy.py
@@ -492,6 +492,8 @@ class ActionModule(ActionBase):
             copy_result = self._copy_single_file(file_src, dest, file_dest, task_v

             result['changed'] = True
+            if self._play_context.diff and not raw:
+               result['diff'].append(self._get_diff_data(dest, file_src, task_vars
             if copy_result.get('failed') is True:
                 result['failed'] = True
                 result['msg'] = "failed to copy file %s: %s" % (file_src, copy_res

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Jan 14, 2018 17:07

here's my reproducer, by the way.

---

- name: diff test
  hosts: "10,"
  gather_facts: False

  tasks:
   - name: clean windows destination
     win_file:
       state: absent
       path: C:\test.txt
     tags: ['clean']

   - name: clean linux destination
     file:
       state: absent
       path: /tmp/test.txt
     delegate_to: localhost
     connection: local
     tags: ['clean']

   - name: make random var
     set_fact:
        var: "{{ 100 | random }}"

   - name: localize var
     set_fact:
        var: "{{hostvars[groups['10'][0]]['var']}}"

   - name: test win template
     win_template:
       src: difftest.j2
       dest: C:\test.txt

   - name: test linux template
     template:
       src: difftest.j2
       dest: /tmp/test.txt
     delegate_to: localhost
     connection: local

jborean93 avatar Mar 11 '20 06:03 jborean93

From @dagwieers on Jan 16, 2018 22:00

So you need to either return: diff.prepared, or both diff.before and diff.after. I guess the latter is preferred unless the output could become huge (e.g. 2 huge files only having 1 line different). So it basically depends on the exact use-case.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Jan 18, 2018 17:38

Thanks, slowly making progress on this. I can get diff output from win_template provided I am running in check mode at the moment. need to get it working not in check mode and handle zip case etc.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Jan 27, 2018 22:58

I haven't succeeded in making this work in 'diff' mode without 'check' mode.

I have put what I have done so far in this branch of my fork here https://github.com/jhawkesworth/ansible/tree/win-template-diff-experiment

This needs someone with more patience, insight or both than I have right now to fix, so I'm going to park this for now.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @mr-fIErcE on Feb 18, 2018 14:25

@jhawkesworth Thank you for your effort! I did a little digging of my own, basing on your work, and this is what I found:

  • win_copy.py does not seem to be used in win_template action - changes to this file don't make any difference in ansible-playbook behavior (I used the playbook from the original bug report). Even adding raise AnsibleError to the first lines of ActionModule.run does not break playbook execution...
  • diff output is produced by in copy.py by _get_diff_data call, but later it is overwritten by result.update from an empty diff output, produced by copy module execution. This little patch enables diff output for normal usage (check mode is off):
[user@centos7 action]$ git diff copy.py
diff --git a/lib/ansible/plugins/action/copy.py b/lib/ansible/plugins/action/copy.py
index a9901a4..cdd8ca4 100644
--- a/lib/ansible/plugins/action/copy.py
+++ b/lib/ansible/plugins/action/copy.py
@@ -335,8 +335,9 @@ class ActionModule(ActionBase):
 
         if not module_return.get('checksum'):
             module_return['checksum'] = local_checksum
-
+        save_diff = result['diff']
         result.update(module_return)
+        result['diff'] = save_diff
         return result
 
     def _get_file_args(self):
  • However, ansible 2.3.0 sets after_header with the same string for every call - dynamically generated. Latter versions set it with path to a temp file, containing template result (for example /home/user/.ansible/tmp/ansible-local-28563Tu9ZSp/tmpkUko8y/difftest.j2). This may become critical if you try to parse these diffs with some automated tool. Not sure how to fix this yet.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @ThoreKr on Jan 29, 2019 09:33

What is the status of this issue?

Still seeing no diff output on Windows with Ansible 2.5 or 2.7.

jborean93 avatar Mar 11 '20 06:03 jborean93

From @crossan007 on Dec 18, 2019 22:07

I think I'm still seeing this in Ansible 2.8.5

jborean93 avatar Mar 11 '20 06:03 jborean93

From @dssdss on Feb 10, 2020 16:17

2.8.7 Still not working! Are you forgot about this bug?!

jborean93 avatar Mar 11 '20 06:03 jborean93

From @jhawkesworth on Feb 10, 2020 19:57

@dssdss pull requests to fix this are welcome!

jborean93 avatar Mar 11 '20 06:03 jborean93

This is also seen in ansible 2.9.7.

Examples:

--diff (without --check) does not show the diff even though the file is changed

$ ansible-playbook -i production windows-server.yml --limit gta-v-dc-04.contoso.local --ask-pass --ask-vault-pass --diff
SSH password:
Vault password:

PLAY [windows_monitored_hosts] ********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************
ok: [gta-v-dc-04.contoso.local]

TASK [zabbix-agent : Copy Zabbix config] **********************************************************************************************
changed: [gta-v-dc-04.contoso.local]

PLAY RECAP ****************************************************************************************************************************
gta-v-dc-04.contoso.local      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Running --diff and --check results in the entire file being displayed

It looks like the diff command is not finding the original file (note that --- before is empty) and thus assumes that it's a new file.

$ ansible-playbook -i production windows-server.yml --limit gta-v-dc-04.contoso.local --ask-pass --ask-vault-pass --diff --check
SSH password:
Vault password:

PLAY [windows_monitored_hosts] ********************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************
ok: [gta-v-dc-04.contoso.local]

TASK [zabbix-agent : Copy Zabbix config] **********************************************************************************************
--- before
+++ after: /home/dthor/.ansible/tmp/ansible-local-6973wuow_cx4/tmpvr2gtinl/zabbix_agentd-win.conf.j2
@@ -0,0 +1,359 @@
+# This is a configuration file for Zabbix agent service (Windows)
+# To get more information about Zabbix, visit http://www.zabbix.com
+
+############ GENERAL PARAMETERS #################
...
...
... entire file is displayed
...
...
+### Option: TLSPSKFile
+#      Full pathname of a file containing the pre-shared key.
+#
+# Mandatory: no
+# Default:
+# TLSPSKFile=

changed: [gta-v-dc-04.contoso.local]

PLAY RECAP ****************************************************************************************************************************
gta-v-dc-04.contoso.local      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

dougthor42 avatar Apr 28 '20 18:04 dougthor42

I did a little digging into this.

In ansible-2.9.* the problem is that the return value of win_file module does not contain the state key. _get_diff_data in lib/ansible/plugins/action/init.py checks for it.

After adding $result.state = 'file' at the end of lib/ansible/modules/windows/win_file.ps1 I get the desired diff output.

In ansible.windows you also need to add a call to _get_diff_data at the appropriate location. For example before line 505 of plugins/action/win_copy.py add something like

if self._play_context.diff:
                result['diff'] = self._get_diff_data(dest, file_src, task_vars)

A quick and dirty fix is here

EDIT: Fixed commit: https://github.com/amhn/ansible.windows/commit/959fb223fcf0dddf8b89aa3bc270093294e1074e

amhn avatar Jan 06 '21 13:01 amhn

I did a little digging into this.

In ansible-2.9.* the problem is that the return value of win_file module does not contain the state key. _get_diff_data in lib/ansible/plugins/action/init.py checks for it.

After adding $result.state = 'file' at the end of lib/ansible/modules/windows/win_file.ps1 I get the desired diff output.

In ansible.windows you also need to add a call to _get_diff_data at the appropriate location. For example before line 505 of plugins/action/win_copy.py add something like

if self._play_context.diff:
                result['diff'] = self._get_diff_data(dest, file_src, task_vars)

A quick and dirty fix is here

Tried your quick and dirty solution on Ansible 2.7. The module win_file.ps1 is not at the same location for 2.7 and the original code differs a bit, but it seems to work for me so far. Thanks for the tip!

Your win_copy.py solution in the fix link is missing the closing bracket at the end of the line.

Hopefully I can manage to do something similar for the win_acl module - it has a similar issues with showing permission diffs.

cveto avatar Jan 12 '21 10:01 cveto

ansible 2.13.1 have still the problem. is there an update when it will be fixed?

globi84 avatar Jul 20 '22 06:07 globi84

ansible 2.13.1 have still the problem. is there an update when it will be fixed?

2.13 probably won't be getting anymore support. 2.9 is the latest of the previous release. Get it from EPEL repository or if using RHEL, enable proper repo to get the 2.9 version. (Red Hat Ansible Engine 2.9)

cveto avatar Jul 20 '22 07:07 cveto

2.13 probably won't be getting anymore support. 2.9 is the latest of the previous release. Get it from EPEL repository or if using RHEL, enable proper repo to get the 2.9 version. (Red Hat Ansible Engine 2.9)

Ok thanks for your quick answer. but with 2.9, I see the whole file as diff. so it is no solution for it.

what do you mean 2.13 will have no support? this is the latest version of ansible. at the ansible docu is 2.9 EOL. so I am confused right now.

regards

globi84 avatar Jul 20 '22 09:07 globi84

Pardon me, I didn't realize they put any Ansible out past 2.9 I know Ansible 3.0, then 4.0., then 5.0 and now Ansible 6.0 is out. And the latest supported release for RHEL is Ansible 2.9, so that's what we are using.

Regarding the fact that the full page shows as diff.. after modifying the module as from mt previous post make sure that:

On Linux, both source and destination file are EOF fir Linux.

And for Windows target machine, both have to be in Windows EOL format (so the soruce ans dest).

Annoying, but it is possible to make it work.

cveto avatar Jul 20 '22 11:07 cveto

Pardon me, I didn't realize they put any Ansible out past 2.9 I know Ansible 3.0, then 4.0., then 5.0 and now Ansible 6.0 is out. And the latest supported release for RHEL is Ansible 2.9, so that's what we are using.

Sorry I'm not sure if I understand. I'm using Ansible straight out of EPEL repos:

$ rpm -q ansible-core
ansible-core-2.13.2-1.el9.x86_64

And I still see the issue. Is this fixed in any branch/release?

scaronni avatar Sep 08 '22 08:09 scaronni

We weren't using EPEL, only RHEL signed packages.

I got it working with 2.9, but not perfect.

All unix files, both on ansible host as well as thw source files had to be in EOL Unix. Windows files had to be in EOL Windows.

Didn't work any other way.

On Thu, 8 Sep 2022, 10:36 Simone Caronni, @.***> wrote:

Pardon me, I didn't realize they put any Ansible out past 2.9 I know Ansible 3.0, then 4.0., then 5.0 and now Ansible 6.0 is out. And the latest supported release for RHEL is Ansible 2.9, so that's what we are using.

Sorry I'm not sure if I understand. I'm using Ansible straight out of EPEL repos:

$ rpm -q ansible-core ansible-core-2.13.2-1.el9.x86_64

And I still see the issue. Is this fixed in any branch/release?

— Reply to this email directly, view it on GitHub https://github.com/ansible-collections/ansible.windows/issues/16#issuecomment-1240405112, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACAFNZWU4EKQGJUDCVHPRI3V5GQQVANCNFSM4LFO5Y3A . You are receiving this because you commented.Message ID: @.***>

cveto avatar Sep 11 '22 08:09 cveto

Hi Any updates?

i use right now ansible-7.4.0 ansible-core-2.14.4 and the problem still exist.

so what i can see is, that the powershell script win_copy never get the content of the file in check mode just the hash from it. maybe this is this the problem.

globi84 avatar Apr 19 '23 14:04 globi84

@jborean93 Do you see any possibility of tackling this anytime soon? :-)

Yannik avatar May 31 '23 15:05 Yannik