Unable to search output of Cisco show command using Ansible - ansible

Running Ansible 2.7.4
I have the following code:
- hosts: switches
tasks:
- name: show run on remote devices
ios_command:
commands: show run
register: output
- name: Display The Results
debug:
msg: "Enable Secret Found"
when: ('secret' in output.stdout)
I want to read in the output of a show run command on a Cisco switch and then search that output for specific phrases in the output.
If a match is found I want a message to be displayed to the screen, however no match is ever found.
PLAY [switches] *****************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************************
ok: [10.10.2.68]
TASK [show run on remote devices] ***********************************************************************************************************************************************************************************************************
ok: [10.10.2.68]
TASK [Display The Results] ******************************************************************************************************************************************************************************************************************
skipping: [10.10.2.68]
PLAY RECAP **********************************************************************************************************************************************************************************************************************************
10.10.2.68 : ok=2 changed=0 unreachable=0 failed=0
I have also tried altering the when statement to
when: output.stdout.find('enable') != -1
but this gives me the following error:
fatal: [10.10.2.68]: FAILED! => {"msg": "The conditional check 'output.stdout.find('enable') != -1' failed. The error was: error while evaluating conditional (output.stdout.find('enable') != -1): 'list object' has no attribute 'find'\n\nThe error appears to have been in '/etc/ansible/playbooks/showrun2.yml': line 8, 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: Display The Results\n ^ here\n"}
Any idea what I'm doing wrong?

'list object' has no attribute 'find'
I'm not sure how much clearer you would expect the error message to be, but in that circumstance output.stdout is a list, not a str
So you'll want
"enable" in (output.stdout | join("\n"))
or the strictly pythonic way
"enable" in "\n".join(output.stdout)

Related

How to access a variable between different play/hosts in the same playbook?

I am a newcomer to Ansible. We have ansible 2.9.7 in our environment.
I need help in accessing a variable between different hosts/play on the playbook. In below code, group of servers is passed here dynamically and creating tempfile directory for each hosts on the Ansible server.
In the second play, i am unable to access the tempfile directory name (stagingdir) for the hosts, probably i am not using the correct approach using hostvars.
Can you please help & guide me to access the stagingdir value of hosts in the first play from the second play below ?
- hosts: "{{host}}"
gather_facts: false
tasks:
- name: Create local staging dir
local_action:
module: tempfile
state: directory
register: stagingdir
- name: print stdout in same play
debug: msg="Value of the variable is {{ hostvars[inventory_hostname].stagingdir.path }}"
- hosts: localhost
gather_facts: false
tasks:
- name: print stdout in next play
debug: msg="Value of the variable is {{ hostvars[ "{{host}}" ].stagingdir.path }}"
This is the result I get:
# ansible-playbook test.yml -e "host=testhost"
PLAY [testhost] *************************************************
TASK [Create local staging dir] *************************************************
changed: [testhost -> localhost]
TASK [print stdout in same play] ************************************************
ok: [testhost] => {
"msg": "Value of the variable is /tmp/ansible.IsLik6"
}
PLAY [localhost] ****************************************************************
TASK [print stdout in next play] ************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['{{host}}']\" is undefined\n\nThe error appears to be in '/home/ooauto/ansible/test.yml': line 17, 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: print stdout in next play\n ^ here\n"}
PLAY RECAP **********************************************************************
testhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

How to print only the stderr_lines when shell command execution fails in ansible playbook task

In my ansible playbook I have a task that executes a shell command. One of the parameters of that command is password. When the shell command fails, ansible prints the whole json object that includes the command having password. If I use no_log: True then I get censored output and not able to get stderr_lines. Is there a way to customize the output when shell command execution fails?
You can take advantage of ansible blocks and their error handling feature.
Here is an example playbook
---
- name: Block demo for shell
hosts: localhost
gather_facts: false
tasks:
- block:
- name: my command
shell: my_command is bad
register: cmdresult
no_log: true
rescue:
- name: show error
debug:
msg: "{{ cmdresult.stderr }}"
- name: fail the playbook
fail:
msg: Error on command. See debug of stderr above
which gives the following result:
PLAY [Block demo for shell] *********************************************************************************************************************************************************************************************************************************************
TASK [my command] *******************************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result", "changed": true}
TASK [show error] *******************************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "/bin/sh: 1: my_command: not found"
}
TASK [fail the playbook] ************************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Error on command. See debug of stderr above"}
PLAY RECAP **************************************************************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=1 ignored=0
You can utilize something like this :
- name: Running it
hosts: localhost
tasks:
- name: failing the task
shell: sh a.sh > output.txt
ignore_errors: true
register: abc
- name: now failing
command: rm output.txt
when: abc|succeeded
stdout will be written to a file. If it's a failure you can check the file and debug it, if it's a success then file will be deleted.

Conditionally import a playbook based on vars_prompt in Ansible

I am using the following ansible script to import a playbook based on the user input,
---
- hosts: localhost
vars_prompt:
- name: "cleanup"
prompt: "Do you want to run cleanup? Enter [yes/no]"
private: no
- name: run the cleanup yaml file
import_playbook: cleanup.yml
when: cleanup == "yes"
Execution log:
bash-$ ansible-playbook -i hosts cleanup.yml
Do you want to run cleanup? Enter [yes/no]: no
PLAY [localhost] *********************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************
ok: [127.0.0.1]
PLAY [master] ********************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************
fatal: [192.168.56.128]: FAILED! => {"msg": "The conditional check 'cleanup == \"yes\"' failed. The error was: error while evaluating conditional (cleanup == \"yes\"): 'cleanup' is undefined"}
to retry, use: --limit #/home/admin/playbook/cleanup.retry
PLAY RECAP ***************************************************************************************************************************
127.0.0.1 : ok=1 changed=0 unreachable=0 failed=0
192.168.56.128 : ok=0 changed=0 unreachable=0 failed=1
It throws error in the imported playbook not in the mail playbook.
Please help me to import a playbook based on user input.
vars_prompt variables are only defined in the play in which they were called. In order to use them in other plays, a workaround is to use set_fact to bind the variable to a host, then use hostvars to access that value from the second play.
For instance:
---
- hosts: localhost
vars_prompt:
- name: "cleanup"
prompt: "Do you want to run cleanup? Enter [yes/no]"
private: no
tasks:
- set_fact:
cleanup: "{{cleanup}}"
- debug:
msg: 'cleanup is available in the play using: {{cleanup}}'
- debug:
msg: 'cleanup is also available globally using: {{hostvars["localhost"]["cleanup"]}}'
- name: run the cleanup yaml file
import_playbook: cleanup.yml
when: hostvars["localhost"]["cleanup"] == True

How to run an ansible playbook only if a group exists?

I wonder if anyone found a solution that would avoid displaying any warnings if an inventory group is undefined or empty.
I just want to make a section of the playbook run if a group exists and is not empty, skipping without warnings if not.
Please read https://github.com/ansible/ansible/issues/35255#issuecomment-388455001 and test alternatives because I spend a good amount of time trying to find a workaround for this issue.
So far I was not able to find any way to avoid the warnings when group is not defined.
I'm slightly unsure if I'm answering the right question, but here goes. I'm interpreting "if a group exists and is not empty" to mean "the currently executing host belongs to a certain group".
If you meant to ask something like "can I find out from the current host if any other hosts belong to a group that the current host does not belong to," or "can I run a playbook without errors when the hosts defined for some groups are unreachable," then I'm afraid this doesn't answer your question :)
But running a task based on whether or not the current host belongs to a group can be done with one of Ansible's default vars, groups group_names.
The following playbook contains two tasks, one to run a debug task when the current host belongs to the group existent, and one to run a debug task when the current host belongs to the group nonexistent. As the output shows, the first task runs and the second does not.
hosts.yml
[existent]
localhost ansible_connection=local
playbook.yml
- hosts: all
gather_facts: true
tasks:
- name: This command will run.
debug:
msg: "The group `existent_1` exists!"
when:
- "'existent_1' in groups"
- name: This command will not run.
debug:
msg: "The group `existent_1` exists and this host is in it!"
when:
- "'existent_1' in groups"
- "'existent_1' in group_names"
- name: This command will run.
debug:
msg: "The group `existent_2` exists and this host is in it!"
when:
- "'existent_2' in groups"
- "'existent_2' in group_names"
- name: This command will not run.
debug:
msg: "The group `nonexistent` exists!"
when:
- "'nonexistent' in groups"
- "'nonexistent' in group_names"
Output
➜ ansible-playbook -i hosts.yml playbook.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [This command will run.] **************************************************
ok: [localhost] =>
msg: The group `existent_1` exists!
TASK [This command will not run.] **********************************************
skipping: [localhost]
TASK [This command will run.] **************************************************
ok: [localhost] =>
msg: The group `existent_2` exists and this host is in it!
TASK [This command will not run.] **********************************************
skipping: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
Not sure if this will suppress the warnings or not, but it should accomplish the first part ("make a section of the playbook run if a group exists and is not empty"):
- hosts: all
gather_facts: true
tasks:
- name: "This command will only run if {{ group_to_test }} is a non-empty group that exists"
debug:
msg: The group 'existent' exists and contains hosts!
when: group_to_test in groups and groups[group_to_test]
Give 'er a test and let me know if she works to suppress the warnings!
Obviously group_to_test must be replaced with a constant string or set as a variable/fact/default.

How should an include playbook be different from a standalone one?

I have two playbooks which are launched against a remote host (10.233.84.58). When launched standalone (ansible-playbook -i inventory.txt playbook.yml) they work fine.
The first playbook includes the second one, which is identical, except obviously for the include:
---
- hosts: all
tasks:
- debug: msg="hello form playbook1"
# up to now the content is identical between playbook1.yaml and playbook2.yaml
# without the next line the playbook runs fine
- include: playbook2.yml
When I run playbook1.yml:
# ansible-playbook -i inventory.txt playbook1.yml (master✱)
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [10.233.84.58]
TASK [debug] *******************************************************************
ok: [10.233.84.58] => {
"msg": "hello form playbook1"
}
TASK [include] *****************************************************************
fatal: [10.233.84.58]: FAILED! => {"failed": true, "reason": "no action detected in task. This often indicates a misspelled module name, or incorrect module path.\n\nThe error appears to have been in '/root/tests/playbook2.yml': line 2, 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- hosts: all\n ^ here\n\n\nThe error appears to have been in '/root/tests/playbook2.yml': line 2, 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- hosts: all\n ^ here\n"}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit #playbook1.retry
PLAY RECAP *********************************************************************
10.233.84.58 : ok=2 changed=0 unreachable=0 failed=1
I extracted the "reason" from the error message above and made it more readable:
no action detected in task. This often indicates a misspelled module name, or incorrect module path.
The error appears to have been in '/root/tests/playbook2.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
---
- hosts: all
^ here
How should an include playbook be different from a standalone one?
There are two types of include. You can include playbook or list of tasks.
---
- hosts: all
tasks:
- include: list_of_tasks.yml
- include: complete_playbook.yml
In your example you try to include playbook2.yml as a list of tasks.
Move include on the same indent as - hosts and you'll be good.

Resources