Automate User Password Change using Ansible Playbook - ansible

I would like to change a user password if it exists, but I get this error
here my code
- name: Check for foo user
with_items: foo
changed_when: false
command: grep {{ item }} -q /etc/passwd
register: find_user
- name: Update foo user's Password
user:
name: foo
update_password: always
password: $6$rounds=656000$ZjMwlMPWqwGKF1nY$JbarjwHGtlr5PD3Yqfb5phz18gnHujSgmpD29DxsXQ7a7UdhuO
when: find_user is changed
TASK [Check for foo user] *****************************************************************************************************************************************************************************************
fatal: [192.168.56.124]: FAILED! => {"changed": false, "cmd": "grep -w 'foo' /etc/passwd", "delta": "0:00:00.003024", "end": "2019-07-01 12:59:45.966160", "msg": "non-zero return code", "rc": 1, "start": "2019-07-01 12:59:45.963136", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

Use getent module to test the existence of the user.
- name: Read passwd
getent:
database: passwd
- name: Update foo users password
user:
name: foo
update_password: always
password: ...
when: "'foo' in getent_passwd"

That's because the command task you have is having an exit code = 1 when the username does not exist in the /etc/passwd file:
[http_offline#greenhat-29 tests]$ grep foo -q /etc/passwd
[http_offline#greenhat-29 tests]$ echo $?
1
[http_offline#greenhat-29 tests]$ grep root -q /etc/passwd
[http_offline#greenhat-29 tests]$ echo $?
0
[http_offline#greenhat-29 tests]$
What you can do, is instruct this task to NOT fail when exit code from the grep command is not 0 or 1. To do that you need to add this clause in the command task:
failed_when: find_user.rc !=0 and find_user.rc !=1
The whole task would look like:
- name: Check for foo user
with_items: foo
changed_when: false
command: grep {{ item }} -q /etc/passwd
register: find_user
failed_when: find_user.rc !=0 and find_user.rc !=1

Related

Why does Ansible think this shell command has a non-zero return code?

I have this recipe:
- name: Kill usr/bin/perl -w /usr/share/debconf/frontend
shell: "{{ item }}"
with_items:
- 'pkill -9 -f debconf/frontend || echo'
changed_when: false # Don't report changed state
When I run this on the command line, it returns a 0 exit code thanks to || echo:
~$ pkill -9 -f debconf/frontend || echo
~$ $?
0
However running in Ansible it shows this:
failed: [testhost1] (item=pkill -9 -f debconf/frontend || echo) => {"ansible_loop_var": "item", "changed": false, "cmd": "pkill -9 -f debconf/frontend || echo", "delta": "0:00:00.132296", "end": "2023-01-13 10:34:11.098765", "item": "sudo pkill -9 -f debconf/frontend || echo", "msg": "non-zero return code", "rc": -9, "start": "2023-01-13 10:34:10.966469", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
Any ideas what I'm doing wrong?
Starting a test process via
perl -MPOSIX -e '$0="test"; pause' &
a minimal example playbook
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Shell task
shell:
cmd: "{{ item }}"
with_items:
- 'pkill -9 -f test || echo'
register: result
- name: Show result
debug:
msg: "{{ result }}"
reproduce the issue. Using instead
with_items:
- 'pkill -9 -f test'
or
with_items:
- 'kill -9 $(pgrep test) || echo'
will execute without an error.
Links
How can I start a process with any name which does nothing?
How to kill a running process using Ansible?
Similar Q&A
with the same error message
Ansible: How force kill process ...?
Further Reading
Since it is recommended to use Ansible modules instead of shell commands if possible
pids module – Retrieves process IDs list if the process is running otherwise return empty list
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Get Process ID (PID)
pids:
name: test
register: PID
- name: Show PID
debug:
msg: "{{ PID.pids | first }}"
- name: Shell task
shell:
cmd: "kill -9 {{ PID.pids | first }}"
register: result
- name: Show result
debug:
msg: "{{ result }}"
Ah, this is because running pkill from inside of Ansible causes it to kill itself (bug in pkill?)
In any case, a workaround is to do this:
with_items:
- 'if pgrep -f "debconf/frontend" | grep -v $$; then sudo pkill -9 -f "debconf/frontend"; fi'

End play if database does not exits

I have created the following playbook, to check if a database exists:
- name: Check database exits
shell: |
mysql -hmysqlhost -uroot -ppassword -e "show databases" | egrep db"
register: mysql_exist
- name: Show database
debug:
msg: "{{ mysql_exist.stdout }}"
My idea is to finish the playbook if the database does not exist and show a message, I tried this but it does not work, otherwise I should continue to the next task.
- name: Check database exits
shell: |
mysql -hmysqlhost -uroot -ppassword -e "show databases" | egrep db"
register: mysql_exist
- name: End Playbook If database not exits.
meta: end_play
when: mysql_exist == 0
- name: Show database
debug:
msg: "{{ mysql_exist.stdout }}"
## other tasks
How can I create a playbook to check if a database exists and if it does not exist, it must display the message The database does not exist and finish the playbook without running other tasks?
if you want to show a message if playbook has to finish, use a block:
(you dont show the output of your register when a db doesnt exist so, i suppose your test in when condition is ok!!)
- block:
- name: "end play "
debug:
msg: "db doesnt exist"
- meta: end_play
when: mysql_exist == 0
so the playbook is finished after the message displaying
Do you need to show the message? Stopping the playbook already happens automatically if egrep does not find anything, because it exits with a non-0 code.
Playbook:
---
- hosts: srv1
become: True
tasks:
- name: x
shell: "echo nope | egrep dbname"
- name: good
shell: "echo very much"
Output (notice how "good" is not executed):
PLAY [srv1] *******************************************************************************************************************************
TASK [x] **********************************************************************************************************************************
fatal: [srv1]: FAILED! => {"changed": true, "cmd": "echo nope | egrep dbname", "delta": "0:00:00.005942", "end": "2022-02-09 15:56:56.726828", "msg": "non-zero return code", "rc": 1, "start": "2022-02-09 15:56:56.720886", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
PLAY RECAP ********************************************************************************************************************************
srv1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
It could be approximated with something like this:
- name: x
shell: "echo nope | egrep dbname || { echo Database not found && false; }"
Which gives:
TASK [x] ***********************************************************************************************************************************
fatal: [srv1]: FAILED! => {"changed": true, "cmd": "echo nope | egrep dbname || { echo Database not found && false; }", "delta": "0:00:00.006159", "end": "2022-02-09 15:59:26.176704", "msg": "non-zero return code", "rc": 1, "start": "2022-02-09 15:59:26.170545", "stderr": "", "stderr_lines": [], "stdout": "Database not found", "stdout_lines": ["Database not found"]}

Getting Ansible runtime error dict object' has no attribute 'stdout_lines' despite variable not null

Below is my playbook which has a variable running_processes which contains a list of pids(one or more)
Next, I read the user ids for each of the pids. All good so far.
I then try to print the list of user ids in curr_user_ids variable using -debug module is when i get the error: 'dict object' has no attribute 'stdout_lines'
I was expecting the curr_user_ids to contain one or more entries as evident from the output shared below.
- name: Get running processes list from remote host
shell: "ps -few | grep java | grep -v grep | awk '{print $2}'"
changed_when: false
register: running_processes
- name: Gather USER IDs from processes id before killing.
shell: "id -nu `cat /proc/{{ running_processes.stdout }}/loginuid`"
register: curr_user_ids
with_items: "{{ running_processes.stdout_lines }}"
- debug: msg="USER ID LIST HERE:{{ curr_user_ids.stdout }}"
with_items: "{{ curr_user_ids.stdout_lines }}"
TASK [Get running processes list from remote host] **********************************************************************************************************
task path: /app/wls/startstop.yml:22
ok: [10.9.9.111] => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "cmd": "ps -few | grep java | grep -v grep | awk '{print $2}'", "delta": "0:00:00.166049", "end": "2019-11-06 11:49:42.298603", "rc": 0, "start": "2019-11-06 11:49:42.132554", "stderr": "", "stderr_lines": [], "stdout": "24032", "stdout_lines": ["24032"]}
TASK [Gather USER IDS of processes id before killing.] ******************************************************************************************************
task path: /app/wls/startstop.yml:59
changed: [10.9.9.111] => (item=24032) => {"ansible_loop_var": "item", "changed": true, "cmd": "id -nu `cat /proc/24032/loginuid`", "delta": "0:00:00.116639", "end": "2019-11-06 11:46:41.205843", "item": "24032", "rc": 0, "start": "2019-11-06 11:46:41.089204", "stderr": "", "stderr_lines": [], "stdout": "user1", "stdout_lines": ["user1"]}
TASK [debug] ************************************************************************************************************************************************
task path: /app/wls/startstop.yml:68
fatal: [10.9.9.111]: FAILED! => {"msg": "'dict object' has no attribute 'stdout_lines'"}
Can you please suggest why am I getting the error and how can I resolve it ?
Few points to note why your solution didn't work.
The task Get running processes list from remote host returns a newline splitted \n string. So you will need to process this and turn the output into a propper list object first.
The task Gather USER IDs from processes id before killing. is returning a dictionary containing the key results where the value is of type list, so you will need iterate over it and fetch for each element the stdout value.
This is how I solved it.
---
- hosts: "localhost"
gather_facts: true
become: true
tasks:
- name: Set default values
set_fact:
process_ids: []
user_names: []
- name: Get running processes list from remote host
shell: "ps -few | grep java | grep -v grep | awk '{print $2}'"
changed_when: false
register: running_processes
- name: Register a list of Process ids (Split newline from output before)
set_fact:
process_ids: "{{ running_processes.stdout.split('\n') }}"
- name: Gather USER IDs from processes id before killing.
shell: "id -nu `cat /proc/{{ item }}/loginuid`"
register: curr_user_ids
with_items: "{{ process_ids }}"
- name: Register a list of User names (Out of result from before)
set_fact:
user_names: "{{ user_names + [item.stdout] | unique }}"
when: item.rc == 0
with_items:
- "{{ curr_user_ids.results }}"
- name: Set unique entries in User names list
set_fact:
user_names: "{{ user_names | unique }}"
- name: DEBUG
debug:
msg: "{{ user_names }}"
The variable curr_user_ids registers results of each iteration
register: curr_user_ids
with_items: "{{ running_processes.stdout_lines }}"
The list of the results is stored in
curr_user_ids.results
Take a look at the variable
- debug:
var: curr_user_ids
and loop the stdout_lines
- debug:
var: item.stdout_lines
loop: "{{ curr_user_ids.results }}"

Ansible mount module to just check state and not report status

Team,
I am writing a validation task that is supposed to just check if a mount exists or not and report its state from output. so my task is below but it fails and am not sure how to handle it. any hint what adjustments do i need to make?
- name: "Verify LVP Mounts on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
#failed_when: lvp_mount.rc != 0
#ignore_errors: yes
# - debug:
# var: lvp_mount
- name: "Report status of mounts"
fail:
msg: |
Mounts sdd not found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }}
{{ lvp_mount.stderr }}
when: lvp_mount | failed
changed: [localhost -> ] => (item=hostA)
[WARNING]: Consider using the mount module rather than running 'mount'. If you
need to use command because mount is insufficient you can add 'warn: false' to
this command task or set 'command_warnings=False' in ansible.cfg to get rid of
this message.
failed: [localhost -> hostA.test.net] (item=hostA) => {"ansible_loop_var": "item", "changed": true, "cmd": "mount | grep sdd", "delta": "0:00:00.009284", "end": "2019-11-06 18:22:56.138007", "failed_when_result": true, "item": "hostA", "msg": "non-zero return code", "rc": 1, "start": "2019-11-06 18:22:56.128723", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring
TASK [services-pre-install-checks : Report status of mounts] ************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'\n\nThe error appears to be in '/home/run_ansible_playbook/k8s/baremetal/roles/services-pre-install-checks/tasks/main.yml': line 265, column 9, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: \"Report status of mounts\"\n ^ here\n"}
Your task "Verify LVP Mounts on CPU Nodes for mount_device" is a loop so the register behavior is modified as specified in the documentation.
You can access the various outputs with lvp_mount.results.X.stdout where X is the index.
There is a cleaner way to write your script however. More specifically using:
delegate_to: "{{ item }}"
with_items: "{{ groups['kube-cpu-node'] }}"
is bad practice. You can accomplish your desired outcome at the play level.
For example:
- hosts: kube-cpu-node # allows you to iterate over all hosts in kube-cpu-node group
tasks:
- name: "Verify LVP Mounts on CPU Nodes for mount_device"
shell: "mount | grep sdd"
register: lvp_mount
ignore_errors: yes
# notice there is no loop here
- name: "Report status of mounts"
fail:
msg: |
Mounts sdd not found
Output of `mount | grep sdd`:
{{ lvp_mount.stdout }} # no loop so you can use lvp_mount.stdout
{{ lvp_mount.stderr }} # no loop so you can use lvp_mount.stderr
when: lvp_mount | failed

how to extract string from ansible regsiter variable in ansible

I have written the following ansible playbook to find the disk failure on the raid
- name: checking raid status
shell: "cat /proc/mdstat | grep nvme"
register: "array_check"
- debug:
msg: "{{ array_check.stdout_lines }}"
Following is the output I got
"msg": [
"md0 : active raid1 nvme0n1p1[0] nvme1n1p1[1]",
"md2 : active raid1 nvme1n1p3[1](F) nvme0n1p3[0]",
"md1 : active raid1 nvme1n1p2[1] nvme0n1p2[0]"
]
I want to extract the disk name which is failed from the register variable array_check.
How do I do this in the ansible? Can I use set_fact module in ansible? Can I use grep, awk, sed command on the register variable array_check
This is the playbook I am using to check the health status of a drive using smartctl
- name: checking the smartctl logs
shell: "smartctl -H /dev/{{ item }}"
with_items:
- nvme0
- nvme1
And I am facing the following error
(item=nvme0) => {"changed": true, "cmd": "smartctl -H /dev/nvme0", "delta": "0:00:00.090760", "end": "2019-09-05 11:21:17.035173", "failed": true, "item": "nvme0", "rc": 127, "start": "2019-09-05 11:21:16.944413", "stderr": "/bin/sh: 1: smartctl: not found", "stdout": "", "stdout_lines": [], "warnings": []}
(item=nvme1) => {"changed": true, "cmd": "smartctl -H /dev/nvme1", "delta": "0:00:00.086596", "end": "2019-09-05 11:21:17.654036", "failed": true, "item": "nvme1", "rc": 127, "start": "2019-09-05 11:21:17.567440", "stderr": "/bin/sh: 1: smartctl: not found", "stdout": "", "stdout_lines": [], "warnings": []}
The desired output should be something like this,
=== START OF SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
Below is the complete playbook including the logic to execute multiple commands in a single task using with_items,
---
- hosts: raid_host
remote_user: ansible
become: yes
become_method: sudo
tasks:
- name: checking raid status
shell: "cat /proc/mdstat | grep 'F' | cut -d' ' -f6 | cut -d'[' -f1"
register: "array_check"
- debug:
msg: "{{ array_check.stdout_lines }}"
- name: checking the samrtctl logs for the drive
shell: "/usr/sbin/smartctl -H /dev/{{ item }} | tail -2|awk -F' ' '{print $6}'"
with_items:
- "nvme0"
- "nvme1"
register: "smartctl_status"

Resources