Using when conditional to match string in output register (Ansible) - ansible

Im unable to search my output variable for a specified string that im using for a when statement. The code below is supposed to check for the string "distribute-list" in the output variable but when run the playbook it gives the error.
fatal: [192.168.3.252]: FAILED! => {"failed": true, "msg": "The conditional check 'output | search(\"distribute-list\")' failed. The error was: Unexpected templating type error occurred on ({% if output | search(\"distribute-list\") %} True {% else %} False {% endif %}): expected string or buffer\n\nThe error appears to have been in '/home/khibiny/test4.yml': line 26, 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 - debug:\n ^ here\n"}
Here is the code that is causing issue:
- ios_command:
commands: show run | sec ospf
provider: "{{cli}}"
register: output
- debug:
msg: "{{output.stdout_lines}}"
when: output | search("distribute-list")
Would appreciate some help. Thanks in advance.

search expects string as input, but output is a dict with different properties.
You should be good with
when: output.stdout | join('') | search('distribute-list')
you need intermediate join here, because for ios-family modules stdout is a list of strings, and stdout_lines is a list of lists (whereas for usual command module stdout is a string and stdout_lines is a list of strings).

Related

Ansible task - Evaluate when with or and

I have vars like this:
vars:
src_wls: "{{ source_database.src_wls_password }}"
src_pwd: "{{ source_database.src_password }}"
tgt_secondary_servers: "{{ inventory_hostname }}"
I want it to run this part if the env is 003 or 004 and the secondary server is like *app02*
I've tried a few iterations, but can't get it to work. Thanks for looking.
- name: Performing managed server
shell: "cd {{ dest }}; {{ dest }}/script_app.sh {{ src_pwd }} {{ src_wls }}"
when:
- target_clone == '003' or target_clone == '004'
- tgt_secondary_servers | regex_search("*app02")
fatal: [lebapp02]: FAILED! => {"msg": "The conditional check 'tgt_secondary_servers | regex_search("*app02")' failed. The error was: nothing to repeat\n\nThe error appears to be in 'main.yml': line 27, 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: Performing managed server)\n ^ here\n"}
expecting it to run on 003 or 004 if server is like *app02
As a start, 2 enhancements that are not the source of your error:
your first condition can be simplified for performance, readability and scalability by checking for the presence of a value in a list with the in test rather than making all tests one after the other.
you're not using default values in case your vars are undefined which can lead to more errors when running (i.e. variable xxxx is undefined)
Your real problem is the second condition which:
is applying a filter returning a string rather than making a boolean test (e.g. is <some_test>, == 'some_value', ...)
receives as a parameter something that is not a regex (or at least not the one you seem to be looking for)
Since you're just looking for a substring, the most straightforward way is to use search.
Here is a fixed version:
when:
- target_clone | d('') in ['003', '004']
- tgt_secondary_servers | d('') is search('app02')
References:
ansible tests
ansible filters

How to use a combination of variable and a string in ansible when condition?

I want to search for a combination of a string and a file in a particular command output and if both exists then skip the task
Here my data_dir variable value is /data/dbdata/test
- name: Extracting existing selinux context
shell: "semanage fcontext -l -C|grep -i {{data_dir|dirname}}"
register: selin_context
- name: Setting Selinux context for data and log dir
command: "semanage fcontext -a -t {{item.name}} {{item.dirpath|dirname}}(/.*)?"
with_items:
- { name: 'postgresql_db' , dirpath: "{{data_dir}}" }
when: "'postgresql_db' and {{data_dir}} not in selin_context.stdout'
If i try above then getting below error
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: 'postgresql_db' and
{{data_dir}} not in selin_context.stdout
fatal: [pgdbsql-02]: FAILED! => {
"msg": "The conditional check ''postgresql_db' and {{data_dir|dirname}} not in selin_context.stdout' failed. The error was: template error while templating string: unexpected '/'. String: {% if 'postgresql_db' and /data/dbdata not in selin_context.stdout %} True {% else %} False {% endif %}\n\nThe error appears to be in '/home/ec2-user/ansible/pgdb/roles/pgdb/tasks/main.yml': line 56, 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: Setting Selinux context for data and log dir\n ^ here\n"
Please guide me how to handle this?

I have used register variable to store output values of task so i'm using same value in when condition from ansible role

---
- name: Check the apps list in ArgoCD server with related to cluster:"{{clustername.stdout}}"
shell: |
argocd app list | grep {{clusterip.stdout}} | grep {{proj_name}} | awk '{print $1}'
register: applist
- debug:
var: applist.stdout_lines
- name: Create xedge apps to production ns
shell: |
argocd app create {{item}}-{{app_extention}} --project {{proj_name}} --repo {{gitops_url}} --revision HEAD --values {{values_file}}.yaml --path {{item}} --dest-namespace production --label app={{item}} --dest-server {{clusterip.stdout}}
with_items:
- "{{production_apps}}"
#skip apps creation if apps are already existed
when : "item-app_extention not in applist.stdout_lines"
''
error:
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'item-app_extention not in applist.stdout_lines' failed. The error was: Unexpected templating type error occurred on ({% if item-app_extention not in applist.stdout_lines %} True {% else %} False {% endif %}): unsupported operand type(s) for -: 'AnsibleUnsafeText' and 'AnsibleUnicode'\n\nThe error appears to be in '/etc/ansible/roles/xedge/tasks/argocd_apps.yml': line 8, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n var: applist.stdout_lines\n- name: Create xedge apps to production ns\n ^ here\n"}
''
You're trying to perform substration on string values, here:
with_items:
- "{{production_apps}}"
#skip apps creation if apps are already existed
when : "item-app_extention not in applist.stdout_lines"
An unquoted variable name is a variable reference. You're try to subtract app_extention from item. I think you mean something like:
when: "item ~ '-' ~ app_extention not in applist.stdout_lines
Where ~ is the string concatenation operator.
Or with less confusing quoting, using the > folding block operator so we're not nesting quotes:
when: >
item ~ '-' ~ app_extention not in applist.stdout_lines
Or using string formatting rather than concatenation:
when: >
'%s-%s' % (item, app_extention) not in applist.stdout_lines

Ansible compare stdout with a variable

I have a questions since I am giving crazy. I want to compare stdout result to one variable storaged in my vars file.
For instance, instead of using the variable but the string ( The IP 22.22.2.2), it works:
Nets.yml
- List_nets_find:
- host 22.22.2.2
Playbook:
---
- name: Black List
hosts: routers
gather_facts: false
vars_files:
- vars/Nets.yml
tasks:
- name: Check the object-group
ios_command:
commands:
- command: "show object-group BLOCK-LIST"
register: output
tags:
- see
- debug:
msg: included
when: output.stdout is search('22.22.2.2')
tags:
- see
Result:
TASK [debug] **************************************************************************************************************************************************************************************
skipping: [Router1]
ok: [Router3] => {
"msg": "included"
}
ok: [Router2] => {
"msg": "included"
}
But instead of using the string, I use the Variable, it does not work.
- name: Black List
hosts: routers
gather_facts: false
vars_files:
- vars/Nets.yml
tasks:
- name: Check the object-group
ios_command:
commands:
- command: "show object-group BLOCK-LIST"
register: output
tags:
- see
- debug:
msg: included
when: output.stdout is search('{{List_net_find}}')
tags:
- see
This is the error:
fatal: [Router1]: FAILED! => {"msg": "The conditional check 'output.stdout is search('{{List_net_find}}')' failed. The error was: error while evaluating conditional (output.stdout is search('{{List_net_find}}')): 'List_net_find' is undefined\n\nThe error appears to be in '/home/ansible/Ios_ACL_LAB/object-group.yml': line 23, column 10, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n - see\n - debug:\n ^ here\n"}
fatal: [Router3]: FAILED! => {"msg": "The conditional check 'output.stdout is search('{{List_net_find}}')' failed. The error was: error while evaluating conditional (output.stdout is search('{{List_net_find}}')): 'List_net_find' is undefined\n\nThe error appears to be in '/home/ansible/Ios_ACL_LAB/object-group.yml': line 23, column 10, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n - see\n - debug:\n ^ here\n"}
fatal: [Router2]: FAILED! => {"msg": "The conditional check 'output.stdout is search('{{List_net_find}}')' failed. The error was: error while evaluating conditional (output.stdout is search('{{List_net_find}}')): 'List_net_find' is undefined\n\nThe error appears to be in '/home/ansible/Ios_ACL_LAB/object-group.yml': line 23, column 10, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n - see\n - debug:\n ^ here\n"}
Any suggestion? or other way to do it?
Thanks so much!
Your vars/Nets.yml does not declare a variable named List_nets_find, it declares an anonymous list whose first element is a dict whose only key is named List_nets_find
If you want a variable named that, then change - List_nets_find: to be List_nets_find:
Separately, the next question you are going to ask is "why does my search not match anything" and that's because List_nets_find is a list of str, so you will want to change that test to be output.stdout is search(List_nets_find | map("regex_escape") | join("|")), using the regex_escape filter to turn those strings into something that can be safely fed into a search alternation

Ansible Print IOS output on string match

I'm trying to use Ansible to hit a bunch (100+) Cisco Catalyst switches and check if they have a certain line card installed. Via SSH, this can be done with the "sh mod" command. I want to parse the output of that command in a playbook and then show the output of the command if a certain string matches. Right now with the playbook below I get the following error:
fatal: [redacted-hostname]: FAILED! => {"failed": true, "msg": "The
conditional check 'showmod | search(\"4548\")' failed. The error was:
Unexpected templating type error occurred on ({% if showmod |
search(\"4548\") %} True {% else %} False {% endif %}): expected
string or buffer\n\nThe error appears to have been in
'/etc/ansible/playbooks/linecard-4548.yaml': line 22, 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 - debug:
\"msg='4548 Card Found'\"\n ^ here\n"}
Current playbook code:
---
- hosts: redacted-hostname
gather_facts: yes
connection: local
tasks:
- name: SYS | Define provider
set_fact:
provider:
host: "{{ inventory_hostname }}"
username: redacted-user
password: redacted-password
- name: IOS | Get Module List
ios_command:
provider: "{{ provider }}"
commands:
- sh mod | inc 4548
register: showmod
- debug: "msg='4548 Card Found'"
when: showmod.stdout | search("/4548/")
I've tried the when in the debug with and without the .stdout to no avail. I've done some research and the error I'm getting usually occurs when, in my case, showmod is undefined but it definitely is. If I replace the debug with the following snippet, the playbook runs fine but of course it'll print the output for every switch which isn't what I want.
- name: IOS | Show Output
debug:
var: showmod
Any suggestions?
ios_command returns stdout as list and stdout_lines as list of lists (whereas command module return stdout as string and stdout_lines as list).
So in your case, you may want to try:
- debug: "msg='4548 Card Found'"
when: showmod.stdout | join(" ") | search("/4548/")

Resources