0

I'm trying to create a playbook that incorporates the following 2 commands and due to their special characters, i cant get it to work. Is there a list of special characters i need to account for in ansible using a bash command?

    - name: If file exists compare new users.txt
      shell: >
        diff -q users.txt  <(getent passwd | awk -F: '{ print $1 }') 1>/dev/null; error="$?"
        getent passwd | awk -F: '{ print $1 }' > users.txt

The error is

fatal: [localhost]: FAILED! => {
    "changed": true,
    "cmd": "diff -q users.txt  <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"\n",
    "delta": "0:00:00.002893",
    "end": "2022-08-19 23:43:07.324939",
    "invocation": {
        "module_args": {
            "_raw_params": "diff -q users.txt  <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"\n",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true,
            "warn": true
        }
    },
    "msg": "non-zero return code",
    "rc": 1,
    "start": "2022-08-19 23:43:07.322046",
    "stderr": "/bin/sh: -c: line 0: syntax error near unexpected token `('\n/bin/sh: -c: line 0: `diff -q users.txt  <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"'",
    "stderr_lines": [
        "/bin/sh: -c: line 0: syntax error near unexpected token `('",
        "/bin/sh: -c: line 0: `diff -q users.txt  <(getent passwd | awk -F: '{ print $1}') 1>/dev/null; error=\"$?\"'"
    ],
    "stdout": "",
    "stdout_lines": []
}
druffin
  • 163
  • 2
  • 15

1 Answers1

2

Q: "Update the list of users in /tmp/users.txt if the list differs from those in /etc/passwd."

A: Use the module getent to read /etc/passwd. For example,

    - name: Create dictionary ansible_facts.getent_passwd
      ansible.builtin.getent:
        database: passed

Next, read the file. Set changed_when: false to keep the play idempotent

    - name: Create list users.stdout_lines from /tmp/users.txt
      command: cat /tmp/users.txt
      register: users
      changed_when: false

Compare the lists and update the file if needed

    - copy:
        dest: /tmp/users.txt
        content: |
          {% for user in ansible_facts.getent_passwd.keys() %}
          {{ user }}
          {% endfor %}
      when: diff|length > 0
      vars:
        diff: ansible_facts.getent_passwd.keys()|list|
              difference(users.stdout_lines)

Example of a complete playbook for testing

- hosts: localhost
  tasks:
    - name: Create dictionary ansible_facts.getent_passwd
      ansible.builtin.getent:
        database: passwd
    - ansible.builtin.debug:
        var: ansible_facts.getent_passwd.keys()|list
      when: debug|d(false)|bool

    - name: Create list users.stdout_lines from /tmp/users.txt
      command: cat /tmp/users.txt
      register: users
      changed_when: false
    - ansible.builtin.debug:
        var: users.stdout_lines
      when: debug|d(false)|bool

    - name: Update /tmp/users.txt
      copy:
        dest: /tmp/users.txt
        content: |
          {% for user in ansible_facts.getent_passwd.keys() %}
          {{ user }}
          {% endfor %}
      when: new_users|length > 0
      vars:
        new_users: "{{ ansible_facts.getent_passwd.keys()|
                       difference(users.stdout_lines) }}"

Example of the update

If I remove the users admin, user1, and user2 from the file, the play gives (abridged) in --diff mode

shell> ansible-playbook pb.yml -CD

TASK [Update /tmp/users.txt] ************************************************
--- before: /tmp/users.txt
+++ after: /home/tester/.ansible/tmp/ansible-local-903563m7yp2ywc/tmpvm5fd7j2
@@ -50,4 +50,7 @@
 libvirt-qemu
 libvirt-dnsmasq
 asadmin
+admin
+user1
+user2
 _chrony

changed: [localhost]

Q: "Detect new users that were added."

A: Report new users in the block. For example,

- hosts: localhost
  gather_facts: false
  tasks:
    - name: Create dictionary ansible_facts.getent_passwd
      ansible.builtin.getent:
        database: passwd
    - ansible.builtin.debug:
        var: ansible_facts.getent_passwd.keys()|list
      when: debug|d(false)|bool

    - name: Create list users.stdout_lines from /tmp/users.txt
      command: cat /tmp/users.txt
      register: users
      changed_when: false
    - ansible.builtin.debug:
        var: users.stdout_lines
      when: debug|d(false)|bool

    - name: Report new users and update file
      block:
        - name: Report new users
          debug:
            msg: "New users: {{ new_users }}"
        - name: Update /tmp/users.txt
          copy:
            dest: /tmp/users.txt
            content: |
              {% for user in ansible_facts.getent_passwd.keys() %}
              {{ user }}
              {% endfor %}
      when: new_users|length > 0
      vars:
        new_users: "{{ ansible_facts.getent_passwd.keys()|
                       difference(users.stdout_lines) }}"
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • This is close but im trying to compare the file (that was created previously) agasint the current user list. Im trying to only report users that werent on the original. Basically, my boss wants the script to detect new users that were added (since the last time the script was ran and the users.txt file was created) and only display the new users – druffin Aug 20 '22 at 07:26
  • Add a report to the block. I added an example. You should see it despite the fact the question is closed. If you have any problem with my code open a new question. – Vladimir Botka Aug 20 '22 at 08:48