ansiblemolecule

Ansible Molecule test can't pass bash command which always create/delete lock file


I have an Ansible role to install/activate Trendmicro. In the task, there's one action did that activation by calling a bash command

- name: Execute /opt/imal/bin/dsupdstat.sh
  ansible.builtin.command: /opt/imal/bin/dsupdstat.sh
  changed_when: true
  failed_when: false

But since this dsupdstat.sh always needs to create a lock file at beginning and delete it at the end. So the Ansible Molecule test keeps failing on it with a "idempotence" error... But that lock file creation/deletion is inevitable. So it looks that no hope to pass this Molecule test even if I marked that action with changed_when: true.

Now I have to use this to ignore running that action in molecule test --

- name: Execute /opt/imal/bin/dsupdstat.sh
  ansible.builtin.command: /opt/imal/bin/dsupdstat.sh
  when: not lookup('env', 'MOLECULE_SCENARIO') is defined
  changed_when: true
  failed_when: false

Is there any better method to let molecule understand this action must do system changes and let it pass?


Solution

  • The problem is not your command creating/deleting a lock file but the presence of changed_when: true in you task options. This will always report changed and will never pass an idempotency check (whatever the command you play).

    Note that command/shell reports changed by default since ansible can't guess what you are doing exactly. Ideally, you should implement a test based on the registered command execution to tell whether something has changed or not (using e.g. the output, the return code ....). A proto example would look like:

    - name: A command which changes or not
      command: some_command
      register: run_cmd
      failed_when: run_cmd.rc not in [0,2] or run_cmd.stdout is search('error')
      changed_when: run_cmd.stdout is search('Configuration updated')
    

    Meanwhile if you are 100% sure your task can't pass idempotency in any way, there is a workaround to fool molecule test. You can read this PR thread for more information (I did not find any clear reference in the documentation with my quick search).

    The solution takes advantage of molecule setting the ansible_skip_tags variable before it runs ansible (you are welcome to debug it in your playbooks to see its full content).

    - name: Execute /opt/imal/bin/dsupdstat.sh
      ansible.builtin.command: /opt/imal/bin/dsupdstat.sh
      changed_when: "'molecule-idempotence-notest' not in ansible_skip_tags"
      failed_when: some_condition # Using false as in your question is really a bad idea...
    

    This will report changed: false when run in a molecule idempotency check and changed: true otherwise. Note that you can also add the tag to your task to totally skip it during idempotence phase (but your command will not play)