ansible assert check two strings (or condition) in output - ansible

How to put or condition for the link "'Nexus 56' in version_output['stdout'][0]['chassis_id']" ? I want to check if 'chassis_id' contains 'Nexus 56' or 'Nexus 60'
- assert:
that:
- "'Nexus 56' in version_output['stdout'][0]['chassis_id']"
- "'n6000' in version_output['stdout'][0]['isan_file_name']"
fail_msg: "This is not a N5600/N6000 chassis."
success_msg: "This is a N5600/N6000 chassis."

fixed using following:
("'Nexus 56' in version_output['stdout'][0]['chassis_id']") or ("'Nexus 60' in version_output['stdout'][0]['chassis_id']")

Related

json_query filter with bug?

I have a situation.
When I try to use json_query filter in ansible-playbook return this error:
{"msg": "Error in jmespath.search in json_query filter plugin:\ninvalid literal for int() with base 10: '-'"}
I solve this with replace ('-','_') filter.
Have I other way to solve this?
complete code here:
---
# tasks file for mpls-lsp
- name: Colete informações do protocolo osfp
junipernetworks.junos.junos_rpc:
rpc: get-ospf-neighbor-information
output: json
register:
_data
- name: Aplica as configurações padrão em RT-BRAS.*
ansible.builtin.debug:
var: item
loop: "{{ _data2 | json_query('ospf_neighbor_information[0].ospf_neighbor[*].neighbor_address[0].data') }}"
vars:
_data2: "{{ _data.output | replace ('-','_') }}"
when: "'device_roles_bras' in {{ group_names }}"
TL;DR
"ospf-neighbor-information"[0]."ospf-neighbor"[*]."neighbor-address"[0].data
Full Story
I solve this with replace ('-','_') filter.
This is actually quite dangerous as this replaces dashes for underscores absolutely everywhere in the input, identifiers and values. But if we now look at your resulting jmespath expression
json_query('ospf_neighbor_information[0].ospf_neighbor[*].neighbor_address[0].data')
we can infer that all your identifiers where previously using - as a separator
In the above expression, you are using unquoted identifiers. If you look at jmespath specification for identifiers, you will see that unquoted ones cannot contain dashes.
identifier = unquoted-string / quoted-string
unquoted-string = (%x41-5A / %x61-7A / %x5F) *( ; A-Za-z_
%x30-39 / ; 0-9
%x41-5A / ; A-Z
%x5F / ; _
%x61-7A) ; a-z
quoted-string = quote 1*(unescaped-char / escaped-char) quote
unescaped-char = %x20-21 / %x23-5B / %x5D-10FFFF
escape = %x5C ; Back slash: \
quote = %x22 ; Double quote: '"'
escaped-char = escape (
%x22 / ; " quotation mark U+0022
%x5C / ; \ reverse solidus U+005C
%x2F / ; / solidus U+002F
%x62 / ; b backspace U+0008
%x66 / ; f form feed U+000C
%x6E / ; n line feed U+000A
%x72 / ; r carriage return U+000D
%x74 / ; t tab U+0009
%x75 4HEXDIG ) ; uXXXX U+XXXX
So if your identifiers contain dashes, you must quote them (and note that quoting identifiers is made with double-quotes)
You can transform your json_query task as below to make it work on your original data (you might have to adapt as I didn't have your original structure and had to guess a bit...)
- name: Aplica as configurações padrão em RT-BRAS.*
ansible.builtin.debug:
var: item
loop: "{{ _data.output | json_query(query) }}"
vars:
query: >-
"ospf-neighbor-information"[0]."ospf-neighbor"[*]."neighbor-address"[0].data
when: "'device_roles_bras' in {{ group_names }}"

lineinfile/regexp/line: why line at the end of file?

I don't understand how lineinfile works, I use:
- name: "configure"
lineinfile:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^\/\/ "\${distro_id}:\${distro_codename}-updates";'
line: ' "${distro_id}:${distro_codename}-updates";'
state: present
And I expect that line in file will be uncommented:
// "${distro_id}:${distro_codename}-updates";
instead of this, this line stay as it is, but at the end of file,
I see:
"${distro_id}:${distro_codename}-updates";
so "match" happens, but why there is new line at the end of file instead of replace?
Your regexp does not escape all of the special symbols and therefore there is no match which causes the addition of the new line instead of the replacement. Curly braces should be escaped, according to Python's re module documentation.
This task works as expected on my Ubuntu 18.04 server.
- name: "configure"
lineinfile:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^//\s+"\$\{distro_id\}:\$\{distro_codename\}-updates";'
line: ' "${distro_id}:${distro_codename}-updates";'
state: present
Diff
-// "${distro_id}:${distro_codename}-updates";
+ "${distro_id}:${distro_codename}-updates";
There must be other problem. The code works as expexted
shell> diff 50unattended-upgrades 50unattended-upgrades.orig
1c1
< "${distro_id}:${distro_codename}-updates";
---
> // "${distro_id}:${distro_codename}-updates";

How can I convert a decimal string to an hexadecimal string?

I have a playbook that queries a server for it's SystemID which can be converted to a model number using a vendor-provided table that maps the id to a model. The server returns a decimal value but the table uses the hexadecimal equivalent.
What I want to do is to convert the decimal string to an hexadecimal string that can be matched with an entry in the vendor-provided table.
Example:
Server returns: SystemID = 1792
Matching entry in vendor table: 0x0700
I've searched in the Ansible documentation and Web searched for either a native Ansible command or jinja2 expression to do the conversion.
I've only found the int(value, base=x) jinja2 function that does the opposite of what I am trying to do.
The native python hex() command can do it. But I'd like to avoid that if possible.
Here is the playbook task that parses the servers stdout to get systemid value:
set_fact:
server_model: "{{ ( server_model_results.stdout_lines | select('match','SystemID' ) | list| first ).split('=')[1] | regex_replace('^\ |\ /$', '' ) }}"
Environment:
Ansible 2.9.7
Python 3.8.0
macOS 10.15.4
You can use a python format with the % operator inside a jinja2 template string:
$ ansible localhost -m debug -a msg="{{ '%#x' % 1792 }}"
localhost | SUCCESS => {
"msg": "0x700"
}
You will probably still have to deal with the leading 0 that is present in your file (i.e. 0x0700).
If all your values are padded to 4 hexa digits in your file (i.e. after the 0x prefix) a quick and dirty solution could be:
$ ansible localhost -m debug -a msg="0x{{ '%04x' % 1792 }}"
localhost | SUCCESS => {
"msg": "0x0700"
}
If not, you will have to implement some kind of dynamic 0 padding to the next odd number of chars yourself.
You might want to switch the 'x' type specifier to 'X' (see doc link above) if hexa digits above nine are uppercase in your vendor table
$ ansible localhost -m debug -a msg="0x{{ '%04x' % 2569 }}"
localhost | SUCCESS => {
"msg": "0x0a09"
}
$ ansible localhost -m debug -a msg="0x{{ '%04X' % 2569 }}"
localhost | SUCCESS => {
"msg": "0x0A09"
}

Test a substring with special character in a list

I have a list with some application landscape names and I have to look for an specific application with special characters in Jinja2
landscape_list: ["cmdb:app1 landscape", "cmdb:app2 (ex app3) landscape",
"cmdb:app4 landscape"]
app_to_look: "app2 (ex app3)"
I'm trying to use this code to test the list:
{{landscape_list | select('search',land_key) | list | count > 0}}
But I'm always getting 0 when I tried to test "app2 (ex app3)".
I think this problem is related with special characters like ().
Is it possible to look into a list for that specific application in jinja2?
Thanks
Q: "This problem is related to special characters like ()."
A: Yes. The parenthesis must be escaped in the regex. For example
- set_fact:
land_key: 'app2 \(ex app3\)'
- debug:
msg: "{{ landscape_list|select('search', land_key)|list }}"
- debug:
msg: "{{ landscape_list|select('search', land_key)|list|length }}"
- debug:
msg: One or more items match the searched pattern.
when: landscape_list|select('search', land_key)|list|length > 0
give
"msg": [
"cmdb:app2 (ex app3) landscape"
]
"msg": "1"
"msg": "One or more items match the searched pattern."
I end up using a similar method. Instead of using search, I used contains as a search method
{{completed_list | select('contains',solution_search) | list | count > 0}}
solution_search contains the full name of what I'm looking.
{%-set solution_search = env_key ~' '~env_server_key ~' TEST'-%}
Where env_key is the application name that can contain special characters and env_server_key is the application environment.

Ansible: How to loop a command and ignore the return code?

I'm trying to loop a command and wait for a certain phrase in stdout, but the task will prematurely fail because the command will return "1" if it can't connect. How can I make it ignore the return code?
- name: Wait for Fabric Creation to complete
action: shell /usr/local/jboss/jboss-fuse/bin/client container-list
register: result
until: result.stdout.find("success")
retries: 20
delay: 10
It's not really a problem with the command failing (although the task result will be based on the return code of the shell script - this can be altered with failed_when).
The real problem is in the following condition itself:
until: result.stdout.find("success")
find returns -1 value if no match is found, so a boolean check actually passes when there is no success string in the stdout. The condition in until is thus met on the first run.
You need to change the condition to:
- name: Wait for Fabric Creation to complete
action: shell /usr/local/jboss/jboss-fuse/bin/client container-list
register: result
until: result.stdout.find("success") != -1
retries: 20
delay: 10

Resources