Need assistance how to filter output and run additional tasks based on the previous task in ansible.
I am writing a task which check metrics configuration is enabled/disabled. If disabled need to run enable task.
- name: Verify insights configuration
shell: dsetool -h `hostname` -a username -b {{ password }} insights_config --
show_config
register: insight_output
- name: Print status
debug:
msg: "{{ insight_output.stdout }}"
- name: Filter Mode
shell: dsetool -h `hostname` -a username -b {{ password }} insights_config --
show_config | python -m json.tool | jq '.mode' | tr -d '"'
register: mode_status
Output of print status will be like below
msg:
config_refresh_interval_in_seconds: 30
data_dir_max_size_in_mb: 1024
metric_sampling_interval_in_seconds: 30
mode: ENABLED_WITH_LOCAL_STORAGE
node_system_info_report_period: PT1H
TASK [cassandra : Print mode]
msg: ENABLED_WITH_LOCAL_STORAGE
How can I accomplish running additional tasks if output shows DISABLED.
How can I accomplish running additional tasks if output shows DISABLED.
You may have a look into the following minimal example playbook with Conditionals.
---
- hosts: localhost
become: false
gather_facts: false
vars:
mode_status:
mode: ENABLED_WITH_LOCAL_STORAGE
tasks:
- name: Show status
debug:
msg: "DISABLED"
when: "'DISABLED' in mode_status.mode"
Further Q&A
... which might be interesting for future use
Ansible: Test what a variable begins with
Ansible Conditionals - Wildcard match string
How do you search for substring?
Related
I have the following Ansible Playbook code:
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
when: ansible_distribution in ['Debian', 'Ubuntu']
- name: Users | Generate password for user (Fedora)
shell: makepasswd -m 20 -M 20
register: make_password
when: ansible_distribution in ['Fedora', 'Amazon']
- name: Users | Generate password for user (CentOS)
shell: mkpasswd -l 20
register: make_password
when: ansible_distribution in ['CentOS']
- name: debug
debug: var=make_password
Which outputs:
TASK: [users | debug]
ok: [127.0.0.1] => {
"var": {
"make_password": {
"changed": false,
"skipped": true
}
}
}
... Because every register block gets executed regardless of the when condition.
How would I fix this so make_password doesn't get overwritten when the when condition isn't met?
Or if this is the wrong approach for what you can see that I'm trying to accomplish, let me know of a better one.
Unfortunately, this is the expected behavior. From Ansible Variables
Note
If a task fails or is skipped, the variable still is registered
with a failure or skipped status, the only way to avoid registering a
variable is using tags.
I do not know how to use tags to solve your issue.
EDIT: I found a way albeit a crude solution. Store the results so that it is not overwritten
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
So your code will look like:
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
when: ansible_distribution in ['Debian', 'Ubuntu']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: Users | Generate password for user (Fedora)
shell: makepasswd -m 20 -M 20
register: make_password
when: ansible_distribution in ['Fedora', 'Amazon']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: Users | Generate password for user (CentOS)
shell: mkpasswd -l 20
register: make_password
when: ansible_distribution in ['CentOS']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: debug
debug: var=mypwd
Typically for tasks that run differently on different distros I tend to include a distro specific playbook that is then conditionally included into main.yml.
So an example might look something like this:
main.yml:
- include: tasks/Debian.yml
when: ansible_distribution in ['Debian', 'Ubuntu']
- include: tasks/Fedora.yml
when: ansible_distribution in ['Fedora', 'Amazon']
- include: tasks/Centos.yml
when: ansible_distribution in ['CentOS']
- name: debug
debug: var=make_password
Debian.yml
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
And obviously repeat for the other 2 distros.
This way you keep main.yml to be only running all the generic tasks for the role that can be run on any distro but then anything that needs to be different can be in a distro specific playbook. Because the include is conditional it won't even load the task if the condition isn't met so the variable should not be registered.
how about define a dict in var file?
cat vars.yml
make_password: {
'Debian':'makepasswd --chars=20',
'Ubuntu':'makepasswd --chars=20',
'Fedora':'makepasswd -m 20 -M 20',
'Amazon':'makepasswd -m 20 -M 20',
'CentOS':'mkpasswd -l 20'
}
cat test.yml
---
- hosts: "{{ host }}"
remote_user: root
vars_files:
- vars.yml
tasks:
- name: get mkpasswd
debug: var="{{ make_password[ansible_distribution] }}"
run result:
TASK: [get mkpasswd]
ok: [10.10.10.1] => {
"mkpasswd -l 20": "mkpasswd -l 20"
}
Maybe it makes sense to put all the variants into a shell script and then just run that script instead of multiple Ansible tasks.
The script can detect the OS or simply react on a passed parameter.
#!/bin/bash
case "$1" in
"Debian" | "Ubuntu")
makepasswd --chars=20
;;
"Fedora" | "Amazon")
makepasswd -m 20 -M 20
;;
"CentOS")
mkpasswd -l 20
;;
*)
echo "Unexpected distribution" 1>&2
exit 1
;;
esac
Throw this in the scripts folder of your role as make_password.sh and then call it as:
- name: Users | Generate password for user
script: make_password.sh {{ ansible_distribution }}
register: make_password
Another idea: You seem to actually generate a password remotely, register the output and then use it later in other tasks. If you can guarantee the Ansible master host always is of the same type and not every team member uses a different distribution you could simply run the task locally.
Let's say you use Ubuntu:
- name: Users | Generate password for user
shell: makepasswd --chars=20
delegate_to: localhost
register: make_password
The tasks is executed locally on the host you ran Ansible via delegate_to.
I am trying to run a playbook with these tasks on a few thousand servers
- name: Check root login config
shell: "egrep -i '^PermitRootLogin' /etc/ssh/sshd_config|awk '{print $2}'"
register: config_value
async : 3
become: yes
poll: 1
- name: "config value"
debug: msg="{{ inventory_hostname }} - {{ config_value.stdout }}"
They have slightly varied configs but this should work on most of them. While running it ,ansible gets stuck somewhere in the middle on some hosts where my user doesn't have passwordless sudo or sudo privileges.
I want to skip those servers where this doesn't work.Is there a way to do that ?
ansible-playbook -i hosts playbook.yml --ask-become-pass
I tried giving a wrong password too ,but it still hangs.
Ansible continues with the rest of the hosts if one task fails on one or more hosts. You could use that behaviour by provoking it before the actual tasks. Don't set become in the playbook, do this instead:
- name: Ping or fail host
become: true
ping:
- name: Check root login config
become: true
shell: "egrep -i '^PermitRootLogin' /etc/ssh/sshd_config|awk '{print $2}'"
register: config_value
async : 3
become: yes
poll: 1
- name: "config value"
debug: msg="{{ inventory_hostname }} - {{ config_value.stdout }}"
We use an Ansible playbook for running a few commands like version_get, device_status on the target machine. Intentionally we have restricted reboot option from being executed. But occasionally, we would like to automatically answer the yes prompt by setting some variables in the --extra-vars option.
A simple representation of our playbook minimized to run on localhost.
---
- hosts: localhost
gather_facts: no
tasks:
- name: Confirm Execution
pause:
prompt: "You are about to execute a '{{cmd}}' command on the device. Enter 'yes' to proceed"
register: pause_result
run_once: True
when: not (cmd|regex_search('(get|status)'))
- meta: end_play
when: pause_result.user_input|default('yes') != 'yes'
I know I can add reboot as part of the existing get|status list, but I don't want to do that, because I want the users exercise special precaution when running it. So with the current code as above, if I run reboot I'm left with a prompt like
$ ansible-playbook loc.yml -e 'cmd=reboot'
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] ***********************************************************************************************************************************************************
TASK [Confirm Execution] ***************************************************************************************************************************************************
[Confirm Execution]
You are about to execute a 'reboot' command on this device. Enter 'yes' to proceed:
I just know how to set a variable to automatically answer this prompt. Tried passing echo yes | to the playbook and seeing an error as
$ echo yes | ansible-playbook loc.yml -e 'cmd=reboot'
[WARNING]: Not waiting for response to prompt as stdin is not interactive
I also tried to pass the --extra-vars as below but none of them seemed to work
-e 'cmd=reboot {"pause_result": "yes"}'
-e 'cmd=reboot pause_result=yes'
I would simply use an other var and condition the prompt to this one. Some lines of code being more expressive than a long speech:
The playbook
---
- hosts: localhost
gather_facts: no
tasks:
- name: Confirm Execution
pause:
prompt: "You are about to execute a '{{cmd}}' command on the device. Enter 'yes' to proceed"
register: pause_result
run_once: True
when:
- not (cmd | regex_search('(get|status)'))
- not (skip_confirm | default(false) | bool)
- meta: end_play
when: pause_result.user_input | default('yes') != 'yes'
- name: dummy task to see if end of play was effective
debug:
msg: "In real world, I would play {{ cmd }}"
Example calls:
$ ansible-playbook test.yml -e cmd=reboot
$ ansible-playbook test.yml -e cmd=reboot -e skip_confirm=true
If you do not want to introduce a new var, you can use the existing one but that will still require a modification of your current playbook.
The when clause of your prompt should become:
when:
- not (cmd | regex_search('(get|status)'))
- pause_result is not defined
And the call:
$ ansible-playbook test.yml -e cmd=reboot -e "pause_result={user_input: yes}"
I am using ansible 2.4 in centos, trying to run the below script in remote servers and getting the output. Here the problem is yum info output is showing with json format also. But i need to display only the output. How to remove the json format.
---
- hosts: GeneralServer
tasks:
- name: Checking the service status
shell: systemctl status {{ item }}
with_items:
- httpd
- crond
- postfix
- sshd
register: service
- debug: var=service
- name: Checking the package info
shell : yum info {{ item }}
with_items:
- httpd
- postfix
register: info
- debug: var=info
- name: Executing the mysql running scripts in mysql
shell: mysql -u username --password mysql -Ns -e 'show databases;'
register: databases
- debug: var=databases
Also i am new in callback Module. Please help me to resolve this issue.
Is it possibile to display only stdout_lines values only.
You can try to play with different callback plugins to alter your output, e.g.:
$ ANSIBLE_STDOUT_CALLBACK=oneline ansible-playbook myplaybook.yml
$ ANSIBLE_STDOUT_CALLBACK=minimal ansible-playbook myplaybook.yml
But generally you would not avoid JSON, as it's how Ansible interprets data.
To reduce amount of info, you can use different technics. For example json_query filter.
Something like this:
- debug:
msg: "{{ info.results | json_query('[].stdout_lines[]') }}"
I have the following Ansible Playbook code:
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
when: ansible_distribution in ['Debian', 'Ubuntu']
- name: Users | Generate password for user (Fedora)
shell: makepasswd -m 20 -M 20
register: make_password
when: ansible_distribution in ['Fedora', 'Amazon']
- name: Users | Generate password for user (CentOS)
shell: mkpasswd -l 20
register: make_password
when: ansible_distribution in ['CentOS']
- name: debug
debug: var=make_password
Which outputs:
TASK: [users | debug]
ok: [127.0.0.1] => {
"var": {
"make_password": {
"changed": false,
"skipped": true
}
}
}
... Because every register block gets executed regardless of the when condition.
How would I fix this so make_password doesn't get overwritten when the when condition isn't met?
Or if this is the wrong approach for what you can see that I'm trying to accomplish, let me know of a better one.
Unfortunately, this is the expected behavior. From Ansible Variables
Note
If a task fails or is skipped, the variable still is registered
with a failure or skipped status, the only way to avoid registering a
variable is using tags.
I do not know how to use tags to solve your issue.
EDIT: I found a way albeit a crude solution. Store the results so that it is not overwritten
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
So your code will look like:
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
when: ansible_distribution in ['Debian', 'Ubuntu']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: Users | Generate password for user (Fedora)
shell: makepasswd -m 20 -M 20
register: make_password
when: ansible_distribution in ['Fedora', 'Amazon']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: Users | Generate password for user (CentOS)
shell: mkpasswd -l 20
register: make_password
when: ansible_distribution in ['CentOS']
- set_fact: mypwd="{{make_password}}"
when: make_password.changed
- name: debug
debug: var=mypwd
Typically for tasks that run differently on different distros I tend to include a distro specific playbook that is then conditionally included into main.yml.
So an example might look something like this:
main.yml:
- include: tasks/Debian.yml
when: ansible_distribution in ['Debian', 'Ubuntu']
- include: tasks/Fedora.yml
when: ansible_distribution in ['Fedora', 'Amazon']
- include: tasks/Centos.yml
when: ansible_distribution in ['CentOS']
- name: debug
debug: var=make_password
Debian.yml
- name: Users | Generate password for user (Debian/Ubuntu)
shell: makepasswd --chars=20
register: make_password
And obviously repeat for the other 2 distros.
This way you keep main.yml to be only running all the generic tasks for the role that can be run on any distro but then anything that needs to be different can be in a distro specific playbook. Because the include is conditional it won't even load the task if the condition isn't met so the variable should not be registered.
how about define a dict in var file?
cat vars.yml
make_password: {
'Debian':'makepasswd --chars=20',
'Ubuntu':'makepasswd --chars=20',
'Fedora':'makepasswd -m 20 -M 20',
'Amazon':'makepasswd -m 20 -M 20',
'CentOS':'mkpasswd -l 20'
}
cat test.yml
---
- hosts: "{{ host }}"
remote_user: root
vars_files:
- vars.yml
tasks:
- name: get mkpasswd
debug: var="{{ make_password[ansible_distribution] }}"
run result:
TASK: [get mkpasswd]
ok: [10.10.10.1] => {
"mkpasswd -l 20": "mkpasswd -l 20"
}
Maybe it makes sense to put all the variants into a shell script and then just run that script instead of multiple Ansible tasks.
The script can detect the OS or simply react on a passed parameter.
#!/bin/bash
case "$1" in
"Debian" | "Ubuntu")
makepasswd --chars=20
;;
"Fedora" | "Amazon")
makepasswd -m 20 -M 20
;;
"CentOS")
mkpasswd -l 20
;;
*)
echo "Unexpected distribution" 1>&2
exit 1
;;
esac
Throw this in the scripts folder of your role as make_password.sh and then call it as:
- name: Users | Generate password for user
script: make_password.sh {{ ansible_distribution }}
register: make_password
Another idea: You seem to actually generate a password remotely, register the output and then use it later in other tasks. If you can guarantee the Ansible master host always is of the same type and not every team member uses a different distribution you could simply run the task locally.
Let's say you use Ubuntu:
- name: Users | Generate password for user
shell: makepasswd --chars=20
delegate_to: localhost
register: make_password
The tasks is executed locally on the host you ran Ansible via delegate_to.