I've been meaning to look into Ansible for a long time now, but somehow never got around to it.

SaltStack has been my automation/orchestration tool of choice since about 2013 and I can usually get stuff done with it without glancing at the docs too much.

However, the security history of Salt isn't great: there's been a bunch of security issues in it that got me thinking that maybe I should look at alternatives. (For example, this was a very good one... and there's been a bunch of authentication bypass too which do not inspire confidence)

Anyways, I started tinkering with Ansible to automate some stuff on my workstation.

The following is a collection of short notes and weirdness I encountered so far, to save my future self some time when I encounter them again.

I'm learning ansible, so I'm most likely doing stuff backwards :-)

Printing all facts and variables

- name: "Print all known variables and facts"
  debug:
    var: vars
    verbosity: 2  # So it runs only with -vv and above

Was useful to try and understand if var files were automagically loaded by ansible.

Running a single task file from a playbook

ansible -m include_tasks -a file=./TASKFILE.yml NODE

Of course this only works for task files that do not rely on many variables.

Using tags is another way to achieve this, but for quick testing it seemed more convenient to simply run the single task file.

Pacman module diff is broken if VerbosePkgList is enabled

If VerbosePkgList is set in /etc/pacman.conf, the "diff" output of the pacman module will be wrong.

For example, a simple task like this:

- name: workstation pkgs
  community.general.pacman:
    name:
      - plasma-firewall

Would output this:

TASK [common : workstation pkgs]
--- before
+++ after
@@ -0,0 +1,4 @@
+New
+Version
+Net
+Change

changed: [localhost]

It turns out that the pacman module simply can't cope with the verbose output. Since it isn't possible to turn off that pacman feature from the command line, I ended up having to string up the following pipeline to turn it off:

/usr/bin/pacman-conf | /bin/grep -v '^VerbosePkgLists$' | /usr/bin/pacman --config /dev/stdin "$@"

The above incantation can then be used as follows by the pacman module:

- name: pacman-noverbosepkglist
  copy:
    content: |
        #!/bin/sh
        /usr/bin/pacman-conf | /bin/grep -v '^VerbosePkgLists$' | /usr/bin/pacman --config /dev/stdin "$@"
    dest:  /usr/local/bin/pacman-noverbosepkglists
    owner: root
    group: root
    mode: 0555
- name: workstation pkgs
  community.general.pacman:
    executable: /usr/local/bin/pacman-noverbosepkglists
    name:
      - plasma-firewall

This is clearly a kludge and it would be much simpler if pacman could output the informations using a stable / structured format (for example json), but that's a task for another day :-)

The whole thing has been reported upstream, but so far it is mostly for documentation purposes.

Update 2022-01-15: I ended up rewriting the pacman module in a way that works regardless of the VerbosePkgLists option. It is also much faster when using the latest state. See the https://github.com/ansible-collections/community.general/pull/3907. It is not merged yet, but I've been using it for a month :-)

Unarchive module and its unhelpful error output

Update 2021-01-15: Well my PR was merged, so the following is mostly historical.

I was doing something seemingly simple enough: extract a single file from a tar archive. But it failed with the following message:

localhost | FAILED! => {
    "changed": false,
    "msg": "Failed to find handler for \"/home/jean/.ansible/tmp/ansible-tmp-1637940813.994855-70648-53920273278880/source\". Make sure the required command to extract the file is installed. Command \"/bin/tar\" could not handle archive. Command \"/bin/unzip\" could not handle archive."
}

I was left staring at the terminal, wondering how it could be possible that /bin/tar could not handle a tar.gz file.

After digging around in the code to sprinkle some debugging printfs, I realized that I had made an error in the include parameter of the unarchive module:

- ansible.builtin.unarchive:
    include: b
    dest: /tmp/
    src: ./patate.tar.gz

The b file is not present in the archive. Of course, that's easy to fix, but figuring out what was wrong took way longer than it should have.

What happens if that the unarchive module is smart and tries to list the files in the archive using a few unarchivers (zip, tar z, plain tar, tar bzip2, tar xz, tar zstd), choosing the first one that can read it. If an error occurs, unarchive assumes the program can't handle the archive and silences the error.

That behavior is quite surprising and hard to debug for newcomers (and honestly I'm not sure how seasoned users deal with errors from this module). There's an issue with very few comments describing the problem (opened in 2017), and there's also a bunch of issues describing various situation in which the could not handle archive message was seen (corrupted archive, wrong arguments in extra_opts, etc...), but there seems to be no effort to try and fix the underlying problem.

I made a simple PR to try to move this forward, but it is quite rough and verbose. (I'm secretly hoping someone will be shocked by the crudeness of it and decide to fix it properly)

For the time being, I think I'll be avoiding the unarchive module and use tar directly in order to avoid having to go printf debugging everytime I make a typo somewhere in the module config. prints to the code everytime something breaks.