Running the following 2 bash commands in Ansible [duplicate] - linux

This question already has answers here:
Difference between sh and Bash
(11 answers)
shell module: Bash <(process substitution) with ansible
(3 answers)
Closed 6 months ago.
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": []
}

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) }}"

Related

How to pass data from text file to ansible playbook?

I want to have text file which contains name and password
name: "Peter", "Joe", "Mark"
password: "smith", "biden", "garyy"
And I have playbook like this
---
- hosts: myhosts
become: yes
remote_user: root1
become_user: root
vars_files:
- vars.yml
vars:
ansible_ssh_private_key_file: "{{key}}"
tasks:
- name: Create users
user: name="{{item.name}}" shell=/bin/bash home="/srv/{{item.name}}" groups=root generate_ssh_key=yes ssh_key_bits=2048
loop: "{{ lookup('file', 'userspasswd.txt', wantList=True)| list }}"
- name: Set password to users
shell: echo "{{item.name}}:{{item.password}}" | sudo chpasswd
no_log: True
loop: "{{ lookup('file', 'userspasswd.txt', wantList=True)| list }}"
I am getting error like this
fatal: [xxx.xxx.xxx.xxx]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'name'\n\nThe error appears to be in '/home/root1/Documents/ansiblekernel/main.yml': line 12, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Create users\n ^ here\n"}
Is there any correct way of doing this? Cause I am new to this?
Given the file
shell> cat userspasswd.txt
name: "Peter", "Joe", "Mark"
password: "smith", "biden", "garyy"
Neither wantList=True nor the filter list will help you to parse the file because it's not a valid YAML. If you can't change the structure of the file you'll have to parse it on your own.
Declare the variables
userspasswd_lines: "{{ lookup('file', 'userspasswd.txt').splitlines() }}"
userspasswd_values: "{{ userspasswd_lines|
map('split', ':')|
map('last')|
map('regex_replace', '\"', '')|
map('split', ',')|
map('map', 'trim')|
list }}"
userspasswd_dict: "{{ dict(userspasswd_values.0|
zip(userspasswd_values.1)) }}"
give
userspasswd_lines:
- 'name: "Peter", "Joe", "Mark"'
- 'password: "smith", "biden", "garyy"'
userspasswd_values:
- - Peter
- Joe
- Mark
- - smith
- biden
- garyy
userspasswd_dict:
Joe: biden
Mark: garyy
Peter: smith
Iterate the dictionary. Test it
- name: Create users
debug:
msg: |
name: {{ item }}
shell: /bin/bash
home: /srv/{{ item }}
groups: root
generate_ssh_key: yes
ssh_key_bits: 2048
loop: "{{ userspasswd_dict.keys()|list }}"
- name: Set password to users
debug:
msg: 'echo "{{ item.key }}:{{ item.value}}" | sudo chpasswd'
loop: "{{ userspasswd_dict|dict2items }}"
gives
TASK [Create users] **************************************************************************
ok: [test_11] => (item=Peter) =>
msg: |-
name: Peter
shell: /bin/bash
home: /srv/Peter
groups: root
generate_ssh_key: yes
ssh_key_bits: 2048
ok: [test_11] => (item=Joe) =>
msg: |-
name: Joe
shell: /bin/bash
home: /srv/Joe
groups: root
generate_ssh_key: yes
ssh_key_bits: 2048
ok: [test_11] => (item=Mark) =>
msg: |-
name: Mark
shell: /bin/bash
home: /srv/Mark
groups: root
generate_ssh_key: yes
ssh_key_bits: 2048
TASK [Set password to users] *****************************************************************
ok: [test_11] => (item={'key': 'Peter', 'value': 'smith'}) =>
msg: echo "Peter:smith" | sudo chpasswd
ok: [test_11] => (item={'key': 'Joe', 'value': 'biden'}) =>
msg: echo "Joe:biden" | sudo chpasswd
ok: [test_11] => (item={'key': 'Mark', 'value': 'garyy'}) =>
msg: echo "Mark:garyy" | sudo chpasswd
Example of a complete playbook for testing
- hosts: myhosts
vars:
userspasswd_lines: "{{ lookup('file', 'userspasswd.txt').splitlines() }}"
userspasswd_values: "{{ userspasswd_lines|
map('split', ':')|
map('last')|
map('regex_replace', '\"', '')|
map('split', ',')|
map('map', 'trim')|
list }}"
userspasswd_dict: "{{ dict(userspasswd_values.0|
zip(userspasswd_values.1)) }}"
tasks:
- block:
- debug:
var: userspasswd_lines
- debug:
var: userspasswd_values
- debug:
var: userspasswd_dict
run_once: true
- name: Create users
debug:
msg: |
name: {{ item }}
shell: /bin/bash
home: /srv/{{ item }}
groups: root
generate_ssh_key: yes
ssh_key_bits: 2048
loop: "{{ userspasswd_dict.keys()|list }}"
- name: Set password to users
debug:
msg: 'echo "{{ item.key }}:{{ item.value}}" | sudo chpasswd'
loop: "{{ userspasswd_dict|dict2items }}"- hosts: myhosts
vars:
userspasswd_lines: "{{ lookup('file', 'userspasswd.txt').splitlines() }}"
userspasswd_values: "{{ userspasswd_lines|
map('split', ':')|
map('last')|
map('regex_replace', '\"', '')|
map('split', ',')|
map('map', 'trim')|
list }}"
userspasswd_dict: "{{ dict(userspasswd_values.0|
zip(userspasswd_values.1)) }}"
tasks:
- block:
- debug:
var: userspasswd_lines
- debug:
var: userspasswd_values
- debug:
var: userspasswd_dict
run_once: true
- name: Create users
debug:
msg: |
name: {{ item }}
shell: /bin/bash
home: /srv/{{ item }}
groups: root
generate_ssh_key: yes
ssh_key_bits: 2048
loop: "{{ userspasswd_dict.keys()|list }}"
- name: Set password to users
debug:
msg: 'echo "{{ item.key }}:{{ item.value}}" | sudo chpasswd'
loop: "{{ userspasswd_dict|dict2items }}"

Insert lines in a file from an other file lines in Ansible

I would copy lines from a file /tmp/test1 to a file /tmp/test2
the /tmp/test1 contains:
argument1
argument2
#test1
#test2
#test3
the /tmp/test2 contains:
argument1.1
argument2192
#example
#test2
#example1
So my main goal is to insert every line that doesn't exist in /tmp/test2 from file /tmp/test1
and that the line added must be added at the end of the last line which is containing the same begin of line: ^[[:alpha:]] and ^#, so /tmp/test2 should look like this:
argument1.1
argument2192
argument1
argument2
#example
#test2
#example1
#test1
#test3
I created this playbook but it doesn't do what i am looking for:
- name: check test1 content
command: cat /tmp/test1
register: tmp_content
- name: insert line
lineinfile:
path: /tmp/test2
line: '{{item}}'
insertafter: "^#*"
loop: "{{tmp_content.stdout_lines}}"
1) "Insert every line that doesn't exist in /tmp/test2 from file /tmp/test1"
2) "The line added must be added at the end of the last line which is containing the same beginning."
A: The task below does the job. If the first character is # the line is inserted at the end of the file. Otherwise, the line is inserted before the first line starting with #. The parameters insertafter and insertbefore may not be used together. The negative options omit make the parameters insertafter and insertbefore mutually exclusive
- name: insert line
lineinfile:
path: /tmp/test2
line: "{{ item }}"
insertafter: "{{ (item.0 == '#')|ternary('EOF', omit) }}"
insertbefore: "{{ (item.0 != '#')|ternary('^#.*$', omit) }}"
firstmatch: true
loop: "{{ tmp_content.stdout_lines }}"
Notes
Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
tasks:
- name: check test1 content
command: cat /tmp/test1
register: tmp_content
changed_when: false
- name: insert line
lineinfile:
path: /tmp/test2
line: "{{ item }}"
insertafter: "{{ (item.0 == '#')|ternary('EOF', omit) }}"
insertbefore: "{{ (item.0 != '#')|ternary('^#.*$', omit)}}"
firstmatch: true
loop: "{{ tmp_content.stdout_lines }}"
The playbook is idempotent. See the output of the diff_mode below
shell> ansible-playbook pb.yml --diff
...
TASK [insert line] *************************************************
--- before: /tmp/test2 (content)
+++ after: /tmp/test2 (content)
## -1,5 +1,6 ##
argument1.1
argument2192
+argument1
#example
#test2
#example1
changed: [localhost] => (item=argument1)
--- before: /tmp/test2 (content)
+++ after: /tmp/test2 (content)
## -1,6 +1,7 ##
argument1.1
argument2192
argument1
+argument2
#example
#test2
#example1
changed: [localhost] => (item=argument2)
--- before: /tmp/test2 (content)
+++ after: /tmp/test2 (content)
## -5,3 +5,4 ##
#example
#test2
#example1
+#test1
changed: [localhost] => (item=#test1)
ok: [localhost] => (item=#test2)
--- before: /tmp/test2 (content)
+++ after: /tmp/test2 (content)
## -6,3 +6,4 ##
#test2
#example1
#test1
+#test3
changed: [localhost] => (item=#test3)
Brute force option
Read the files
- command: cat /tmp/test1
register: test1
- command: cat /tmp/test2
register: test2
Declare the variables
l1_alpha: "{{ test1.stdout_lines|select('match', '^[^#].*$') }}"
l1_glyph: "{{ test1.stdout_lines|select('match', '^#.*$') }}"
l2_alpha: "{{ test2.stdout_lines|select('match', '^[^#].*$') }}"
l2_glyph: "{{ test2.stdout_lines|select('match', '^#.*$') }}"
l1_alpha_diff: "{{ l1_alpha|difference(l2_alpha) }}"
l1_glyph_diff: "{{ l1_glyph|difference(l2_glyph) }}"
result: "{{ l2_alpha + l1_alpha_diff + l2_glyph + l1_glyph_diff }}"
This gives the expected result
- debug:
msg: |
{% for line in result %}
{{ line }}
{% endfor %}
msg: |-
argument1.1
argument2192
argument1
argument2
#example
#test2
#example1
#test1
#test3
Write it to a file
- copy:
dest: /tmp/test2
content: |
{% for line in result %}
{{ line }}
{% endfor %}
gives
shell> cat /tmp/test2
argument1.1
argument2192
argument1
argument2
#example
#test2
#example1
#test1
#test3
Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
vars:
l1_alpha: "{{ test1.stdout_lines|select('match', '^[^#].*$') }}"
l1_glyph: "{{ test1.stdout_lines|select('match', '^#.*$') }}"
l2_alpha: "{{ test2.stdout_lines|select('match', '^[^#].*$') }}"
l2_glyph: "{{ test2.stdout_lines|select('match', '^#.*$') }}"
l1_alpha_diff: "{{ l1_alpha|difference(l2_alpha) }}"
l1_glyph_diff: "{{ l1_glyph|difference(l2_glyph) }}"
result: "{{ l2_alpha + l1_alpha_diff + l2_glyph + l1_glyph_diff }}"
tasks:
- command: cat /tmp/test1
register: test1
changed_when: false
- command: cat /tmp/test2
register: test2
changed_when: false
- copy:
dest: /tmp/test2
content: |
{% for line in result %}
{{ line }}
{% endfor %}
The playbook is idempotent.

how to traverse through each line of a text file in ansible

I have to traverse through package list file which contains list of packages with their architecture. How can I feed those input to my playbook file? I found a way to get the package names alone but architecture version is not coming. This is my package_list file
nginx | x86_64
telnet| x86_64
openssh | i386
This is my playbook
- name: get contents of package.txt
command: cat "/root/packages.txt"
register: _packages
- name: get contents of architecture from packages.txt
command: cat "/root/packages.txt" | awk '{print $3}'
register: _arch
- name: Filter
theforeman.foreman.content_view_filter:
username: "admin"
password: "mypass"
server_url: "myhost"
name: "myfilter"
organization: "COT"
content_view: "M_view"
filter_type: "rpm"
architecture: "{{ _arch }}"
package_name: "{{ item }}"
inclusion: True
loop: "{{ _packages.stdout_lines }}"
loop: "{{ _arch.stdout_lines }}"
Any help would be appreciated
The required output is package name and architecture should be read from packages.txt file through ansible-playbook
try this playbook:
- name: Reproduce issue
hosts: localhost
gather_facts: no
tasks:
- name: get contents of package.txt
command: cat "/root/packages.txt"
register: _packages
- debug:
msg: "package: {{ line.0 }}, arch: {{ line.1 }}"
loop: "{{ _packages.stdout_lines }}"
vars:
line: "{{ item.split('|')|list }}"
result:
ok: [localhost] => (item=nginx | x86_64) => {
"msg": "package: nginx , arch: x86_64 "
}
ok: [localhost] => (item=telnet| x86_64) => {
"msg": "package: telnet, arch: x86_64 "
}
ok: [localhost] => (item=openssh | i386) => {
"msg": "package: openssh , arch: i386 "
}
for your case:
- name: Filter
theforeman.foreman.content_view_filter:
:
:
architecture: "{{ line.1 }}"
package_name: "{{ line.0 }}"
inclusion: True
loop: "{{ _packages.stdout_lines }}"
vars:
line: "{{ item.split('|')|list }}"
following the version of ansible you could write too line: "{{ item | split('|') | list }}"
You need to split up the line into the necessary values by filtering.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Gahter package list
shell:
cmd: cat package.txt
register: _packages
- name: Show packages
debug:
msg: "Name: {{ item.split('|')[0] }}, Arch: {{ item.split('|')[1] }}"
loop: "{{ _packages.stdout_lines }}"
Further Documentation
Playbook filters - Manipulating strings
Jinja Template Designer - Filters
Further Q&A
Split string into list in Jinja?

Ansible: A registered variable is undefined when even after debug shows it's contents

Ansuble Register Variables
I have task list where I register output from a shell task. The shell command lists a directory and then pipes the output to grep. The task works and I get the output I wanted. Eariler in the playbook SVN source files are checked outed and transferred to {{ DestRemoteDir }} directory. The code in question builds a list from the output of the command. I take those lists to set various other facts later in the playbook. [ Mapping a list of Debian packages in a specific order of 2nd list with Ansible ] (I know of ansible's find module, but I found "ls -1" far easier to use.)
Playbook (tasks/main.yml)
## use List -1 to find the file names for the deb files.| grep
## It stays, The tasks work as expected.
- name: Find the needed deb files
shell: "ls -1 {{ DestRemoteDir }} | grep .*.deb" # Local dir
register: Deb_List
ignore_errors: yes
delegate_to: 127.0.0.1 #localhosts
- name: Find the needed IXAD list file
shell: "ls -1 {{ DestRemoteDir }} | grep IA-XD" # Local dir
register: IXAD_List_Source
ignore_errors: yes
delegate_to: 127.0.0.1 #localhosts
- name: Print the Deblist for IX-AD
debug:
msg:
- "Deb file list: {{ Deb_List.stdout_lines }}"
- "IXAD file {{ IXAD_List_Source.stdout_lines }}"
- name: Print if undefined Deb_list
debug:
msg: "Deb_List is not real"
when: Deb_list is undefined
- name: Print if undefined Deb_list.stdout_lines
debug:
msg: "Deb_List.stdout_lines is not real"
when: Deb_list.stdout_lines is undefined
Output
changed: [AnsibleTest2 -> 127.0.0.1] => {
"changed": true,
"cmd": "ls -1 /home/ansible/IA-XD | grep .*.deb",
***
"invocation": {
"module_args": {
***
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "iaxd_1.2.7.6-15_all.deb\niaxdautocfg_1.0.0.0_all.deb\nlibjpegdeb7u1_amd64.deb\nopenjdk-6-jre_610-1~deb7u1_amd64.deb\nopenjdk-6-jre-headless_610-1~deb7u1_amd64.deb\nopenjdk-610-1~deb7u1_all.deb",
"stdout_lines": [
"iaxd_1.2.7.6-15_all.deb",
"iaxdautocfg_1.0.0.0_all.deb",
"libjpeg7u1_amd64.deb",
"openjdk-6-jre_610-1~deb7u1_amd64.deb",
"openjdk-6-jre-headless_610-1~deb7u1_amd64.deb",
"openjdk-6-jre-lib_610-1~deb7u1_all.deb"
]
}
changed: [AnsibleTest2 -> 127.0.0.1] => {
"changed": true,
"cmd": "ls -1 /home/ansible/IA-XD | grep IA-XD",
"invocation": {
"module_args": {
"_raw_params": "ls -1 /home/ansible/IA-XD | grep IA-XD",
***
}
},
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "IA-XD_List",
"stdout_lines": [
"IA-XD_List"
]
}
Debug
ok: [AnsibleTest2] => {
"msg": [
"Deb file list: [u'iaxd_1.2.7.6-15_all.deb',u'iaxdautocfg_1.0.0.0_all.deb',u'libjpegdeb7u1_amd64.deb',u'openjdk-6-jre_610-1~deb7u1_amd64.deb',u'openjdk-6-jre-headless_610-1~deb7u1_amd64.deb',u'openjdk-610-1~deb7u1_all.deb']",
"IXAD file [u'IA-XD_List']"
]
}
Above both "stdout_lines": [ "IA-XD_List" ] and "stdout_lines": [ "iaxd_1.2.7.6-15_all.deb",...] are ready.
So from the debug task I see that the variables are there and defined (Or so I thought). But when I test to see if there if the shell command failed.
Error Message
The status clearly shows that Deb_List is undefined. why?
I just debug thad value of that variable.
TASK [server_iaxd_install : Print if undefined Deb_list] *********************************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:64
Tuesday 25 February 2020 11:50:12 +0100 (0:00:00.222) 0:00:07.890 ******
ok: [AnsibleTest2] => {
"msg": "Deb_List is not real"
}
Read vars_file '/home/ansible/.ssh/SudoPassKey'
Try to test the key data I want "Deb_list.stdout_lines", Ansible errors as the variable is not there.
TASK [server_iaxd_install : Print if undefined Deb_list.stdout_lines] ********************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:69
Tuesday 25 February 2020 11:50:12 +0100 (0:00:00.197) 0:00:08.087 ******
fatal: [AnsibleTest2]: FAILED! => {
"msg": "The conditional check 'Deb_list.stdout_lines is undefined' failed. The error was: error while evaluating conditional (Deb_list.stdout_lines is undefined): 'Deb_list' is undefined\n\nThe error appears to have been in '/home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml': line 69, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Print if undefined Deb_list.stdout_lines\n ^ here\n"
}
Either this is a "forest for the trees" (I can't see the obvious) error or an annoying quirk of Ansible that I need to kluge around.
Yes, it was a "forest for the trees" (I can't see the obvious) error.
After looking for the error, I change the code.
- name: Print if undefined Deb_List
debug:
msg: "Deb_List is not real"
when: Deb_List is undefined
- name: Print if undefined Deb_List.stdout_lines
debug:
msg: "Deb_List.stdout_lines is not real"
when: Deb_List.stdout_lines is undefined
And now the output is far better:
TASK [server_iaxd_install : Print if undefined Deb_List] *********************************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:77
Tuesday 25 February 2020 16:00:34 +0100 (0:00:00.242) 0:00:08.013 ******
skipping: [AnsibleTest2] => {}
Read vars_file '/home/ansible/.ssh/SudoPassKey'
TASK [server_iaxd_install : Print if undefined Deb_List.stdout_lines] ********************************************************
task path: /home/ansible/ansible_server_working/roles/server_iaxd_install/tasks/main.yml:82
Tuesday 25 February 2020 16:00:34 +0100 (0:00:00.065) 0:00:08.078 ******
skipping: [AnsibleTest2] => {}

Using register with a loop in Ansible

i want to code a playbook which IF a user exists changes the pw of it.
The playbook should be able to take n User's and change the pw of those Users.
At the moment im having the issue that the when is empty due to the loop, i tried using with_items: {{ user_exists.results }} but this is somehow not working.
(http://docs.ansible.com/ansible/playbooks_loops.html#using-register-with-a-loop)
Am i doing something wrong ?
Br,
Numblesix
---
-
become: true
become_method: sudo
hosts: xetest
name: "Updates the password of given User if exists"
tasks:
-
ignore_errors: true
name: "Check if User exists"
register: user_exists
shell: "grep -q {{ item.key }} /etc/passwd &>/dev/null"
with_dict: "{{ users }}"
-
debug:
var: user_exists
-
debug:
msg: "User name is {{ item.key }} and hash is {{ item.value.passwd}} and return code is: "
with_dict: "{{ users }}"
-
debug:
var: user_exists
with_items: "{{user_exists.results }}"
-
name: "updating password for given User"
user: "name={{ item.key }} update_password=always password={{ item.value.passwd}} createhome=no"
when: user_exists.rc == 0
with_dict: "{{ users }}"
with_items: "{{ user_exists.results }}"
vars:
users:
foo:
passwd: $6$random_salt$12A.ar9eNDsgmds3leKoCDZPmq7OHLvhBtQg/Q3K2G/3yeEa/r8Ou4DxJpN6vzccewugvZt7IkfCbHFF2i.QU.
RESULTS IN ERROR!
duplicate loop in task: items
WITHOUT with_items: "{{ user_exists.results }}" im getting this error
"failed": true, "msg": "The conditional check 'user_exists.rc == 0' failed.
The error was: error while evaluating conditional (user_exists.rc == 0):
'dict object' has no attribute 'rc'
For my testing, I'm using ansible 2.1.4.0.
When running the script, you can see in the debug for user_exists.results that it contains the input value passed in along with the return code:
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "grep -q foo /etc/passwd",
"delta": "0:00:00.009034",
"end": "2017-05-02 17:42:57.835871",
"failed": true,
"invocation": {
"module_args": {
"_raw_params": "grep -q foo /etc/passwd",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"item": {
"key": "foo",
"value": {
"passwd": "foobar"
}
},
"rc": 1,
"start": "2017-05-02 17:42:57.826837",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings": []
},
So instead doing two loops (which would have been done with with_nested and two lists), you can do everything with a single loop:
- name: "updating password for given User"
debug:
msg: "name={{ item.item.key }} update_password=always password={{ item.item.value.passwd}} createhome=no"
when: item.rc == 0
with_items: "{{ user_exists.results }}"
Note: In my testing shell: "grep -q {{ item.key }} /etc/passwd &>/dev/null" was always returning a 0 return code. I had to remove the "&>/dev/null" part to get the proper return code.

Resources