Help with Ansible loop

So I have a directory on a rhel 8 server, that has directories in it, that result from a role that does a fetch from workstations (flat: true) so the directories are named for the hosts two files come from. I’m pulling over a “hostname”.req file and a “hostname”.csr file. I’m trying to loop through each of these directories (and to make it easier and quicker I’ve cut down the number of host directories to just two for now.) and run a shell command. Below is the playbook that eventually I’ll configure as a role within a much larger playbook.

Note: Any spelling mistakes or indentation mistakes are just from typing. The playbook runs on a closed network.

  • name: Get directory names
    ansbible.builtin.find:
    paths: /etc/cert_dir/workstations
    file_type: directory
    register: hostname

The above I hope to use later in the play to name a created crt file {{ hostname }}.crt But for now I’m satisfied that ansible can descend into the main dir and enumerate the two host dirs. I have another play after this that uses "set_fact: dir_name: “{{ hostname.files | map(attribute=‘path’) |map(‘basename’) | list }}” This is just experimenting with saving/using variables.

  • name: Print hostname
    ansible.builtin.debug
    msg: "the hostnames are: {{ hostname }} ## Comment: so far so good. Just a sanity check
    that ansible can descend into my main folder
    and enumerate the directories there.

  • name: Find CSR files
    ansible.builtin.find:
    paths: /etc/cert_dir/workstations
    file_type: file
    patterns: “*.csr”
    recurse: yes
    register: csr

I have another section that prints the csr files found. It works. it shows host1.csr and host2.csr (not in a list like I thought it would be, but in a comma-separted paragraph. Ok, that works). This will be removed later since it’s just a sanity check for me - can ansible find all these files? Yes it can - ok all good.

Here’s the part I’m having trouble with:

  • name: Test variable usage against the found csr files
    ansible.builtin.shell:
    cmd: openssl req -text -noout -verify -in {{ csr }} {{ item.path }}
    with_items: “{{ csr.files }}”
    register: command_output # So I can see the output of the openssl verify command. Following this is just a simple print “command_output” to the display

I get a big block of red text for the two csr files. It’s too much to type here, that whole error message. Part of it is: /etc/cert_dir/workstations/host1.csr, ‘mode’: 0777, isdir: False, 'ischr: False… and it just goes on and on for awhile listing things that don’t seem useful. I just don’t get what I’m doing wrong.

I’ve tried several different ways of coding the last part of the play above. At first I was using:
loop: {{ csr.files |map(attribute=‘path’) }}" ## same result though.

I’ve been trying to read and understand what this does: {{ item.path }} and whether it should go in the play just like that, or whether I need to replace that with the path to my files?

I’ve realized what I’m doing wrong, still trying to fix it.

I realized that these plays:

  • name: Find CSR files
    ansible.builtin.find:
    paths: /etc/cert_dir/workstations
    file_type: file
    patterns: “*.csr”
    recurse: yes
    register: csr

  • name: Print csr variable
    debug:
    msg: Print result of CSR search: {{ csr }}

This produces a paragraph for each csr file name, but also includes a lot of file attributes which I realized is probably being passed into the shell command.

So I added this:

  • name: Find CSR files
    ansible.builtin.find:
    paths: /etc/cert_dir/workstations
    file_type: file
    patterns: “*.csr”
    recurse: yes
    register: csr

  • name: csr file names into new variable
    set_fact:
    CSR: “{{csr.files | map(attribute=‘path’) | map(‘basename’) | list }}”

  • name: Print csr variable
    debug:
    msg: Print result of CSR search: {{ CSR }}

Now I get just the two files names, without all the attributes. But if I pass this new variable “CSR” to my openssl verify command, I’m getting "the task includes an option with an undefined variable. This is after I’ve replaced “csr” in the shell command with “CSR”

I’m not sure why CSR would be undefined without more context. The snippet seems fine. If you use ``` on the line before and after a block of tasks, it will make it easier to read.

In your original post, why are you passing in csr to the openssl command? Couldn’t you just use the loop item?

    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ item.path }}
      with_items: "{{ csr.files }}"
      register: command_output

I’ve tried it both ways: without the “with_items” line and replaced with…
loop: {{ csr.files | map(attribute=‘path’) | map(‘basename’) | | list }}"
I’ve also tried:
loop: {{CSR}}

The loop looks fine. The issue is the command you’re passing to openssl, can you try my suggestion?

I’m not sure what you mean when you say “loop item”

It’s the dynamic value provided by the loop/with_* keyword, which requires a list. A list is made up of items.

Your original task looks like:

    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ csr }} {{ item.path }}
      with_items: "{{ csr.files }}"
      register: command_output

There’s nothing wrong with the loop, only the cmd argument, try:

    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ item.path }}
        # or maybe
        # cmd: openssl req -text -noout -verify -in {{ item.path | basename }}
      with_items: "{{ csr.files }}"
      register: command_output

Typically the loop variable is called “item”, but you can configure this:

    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ csr_item.path }}
      loop: "{{ csr.files }}"
      loop_control:
        loop_var: csr_item
      register: command_output

Check out Loops — Ansible Community Documentation for more loop features.

1 Like