4

In my Ansible playbook I have this:

- name: "A: Check to see if we need to run task B"
  [... implementation omitted, not relevant ...]
  register: task_a_result
  check_mode: no  # even run in check mode
  changed_when: no  # this only reads/checks stuff

- name: "B: Write x to file"
  shell: "echo {{ my_var|quote }} > /path/to/file"
  when: task_a_result.stdout_lines[0].startswith('ABCDEF')
  changed_when: yes  # when run, it always changes the state

I do not want to run B in check mode (hence, no check_mode: no), but I want to report it as changed if it would have been run in non-check mode. I want this behaviour, because I do not want surprises when running in non-check mode. However, despite having changed_when: yes and having set a conditional myself, Ansible keeps showing the task as skipped and thus unchanged to me:

skipping: [myhost] => changed=false 
  msg: skipped, running in check mode

(The above in check mode, and it reports 'changed' in regular non-check mode.)

I found this bug report that appears misinterpreted and closed inappropriately: 14950, but I cannot comment on that any longer.

Am I overlooking something basic? Other modules usually report a "would have changed" status perfectly fine in Ansible, but is this also possible for shell/command?

Using Ansible 2.7.12 and 2.8.2 yields the same results.

I am hoping to avoid nasty hacks in the command itself like:

- name: "B: Write x to file"
  shell: "echo {{ my_var|quote }} {{ '>' if task_a_result.stdout_lines[0].startswith('ABCDEF') else '' }} /path/to/file"
  when: task_a_result.stdout_lines[0].startswith('ABCDEF')
  changed_when: yes

And yes I know I can write to a file with the copy/template modules, but I can't seem to overwrite files with it, e.g. echo 1234 > /sys/module/zfs/parameters/zfs_arc_max, because copy/template would attempt to replace the file it seems and setting a kernel parameter wouldn't work like that. And no, this kernel module parameter is not exposed through sysctl on Linux.

gertvdijk
  • 3,504
  • 4
  • 30
  • 46
  • Why does it matter? – Michael Hampton Jul 24 '19 at 00:41
  • @MichaelHampton Because in a check mode, I'd like to know if something would change if I run it in non-check mode. IOW, without Ansible, if you would run `cmd --dry-run` which outputs "nothing changed" and you would then do `cmd`, and it *would* change something, this would be a bug. – gertvdijk Jul 24 '19 at 12:12
  • But you've set the play to always report changed even if nothing changed (which is redundant). It certainly looks like the actual result is irrelevant, doubly so in check mode. What is missing here? – Michael Hampton Jul 24 '19 at 15:07
  • @MichaelHampton `when: my_conditional_var` determines whether the task is going to run, and if it runs, it will change. I want to see that in check mode. Perhaps I could improve the wording in the Q? It's basically check mode reports "I'm not going to change anything" and in non-check mode it *will* change stuff. That's what I want to fix. – gertvdijk Jul 25 '19 at 00:16
  • In the example you gave, it doesn't actually matter! You can just ignore it. Are you doing something else? – Michael Hampton Jul 25 '19 at 06:04
  • @MichaelHampton I don't quite get what seems to be lost from my head to my post then. :) Anyway, updated the question again (rev 2) with more explicit wording. Thanks. – gertvdijk Jul 25 '19 at 09:07

2 Answers2

3

I know this is kind of old, but I'm looking for the solution to this problem. I'm also tired of surprises with command module as OP.

What if we change the 'command' part so that it executes a different command in check mode. And we run the task always, even in check mode.

Note: Before you complain, I know this is a bad example. I know there is a 'creates' option in 'command' module. This is just to give an example.

This is my solution so far:

- name: Get some info
  stat: {path: /tmp/somefile}
  register: file_info

- name: Run the command conditionally
  command:
    "{{ 'true' if (file_info['stat']['exists'] or ansible_check_mode)
    else 'touch /tmp/somefile' }}"
  changed_when: not file_info['stat']['exists']
  check_mode: false

It works, but is bloated.

Please tell me if there are better solutions.

  • Yes, thanks, meanwhile I always add a `--dry-run` argument conditionally if the command executed supports that. If the command supports it, it's even better, because it could test for failures and reduce the level of surprise when run in non-check mode. However, I'm still disappointed I haven't found a way to report-changed-but-not-run as task in Ansible check mode. – gertvdijk Apr 27 '21 at 19:14
0

I have a similar need. I would like to see if the command would be run so that I get no surprises when not run in check mode.

As a workaround I added a debug task reporting that there would be a change and used the when condition from the command task to set changed_when on the debug task, i.e.

- name: "Report pending change"
  debug:
    msg: "Change pending"
  changed_when: task_a_result.stdout_lines[0].startswith('ABCDEF')
  when: ansible_check_mode|bool
subie
  • 101
  • 2