finding and setting new var from ansible_net_config - ansible

I'm trying to come up with a way to find a piece of text in a very long string. I'm using the ios_facts module to grab a Cisco config. I'm looking for the text below and want to set it as a new var. The 'ip nbar protocol-pack' portion will never change but the value after that will vary from node to node.
{{ ansible_net_config }} =
o ip source-route\n!\n!\nip nbar protocol-pack bootflash:pp-adv-isr4000-169.1-34-47.0.0.pack \n!\n!\n!\n!\nip nb
the value of ansible_net_config is much longer. I trimmed it down for sanity sake.
This is what I want the var set to:
ip nbar protocol-pack bootflash:pp-adv-isr4000-169.1-34-47.0.0.pack
Here is the code I'm working with. I don't know if I should keep trying regex_search or try json_query or something I'm not yet aware of.
---
- name: Cisco NBAR Test
connection: ansible.netcommon.network_cli
hosts: all
tasks:
- name: collect facts
cisco.ios.ios_facts:
gather_subset:
- config
- name: set vars
set_fact: config={{ ansible_net_config | regex_search('ip nbar protocol-pack') }}
#set_fact: config={{ ansible_net_config | community.general.json_query('*') }}
- name: show output
debug:
var: config
Any idea on how to do this?
Thanks,

I'd write the regexp like this:
set_fact: config="{{ ansible_net_config | regex_search('.*ip nbar protocol-pack.*') | trim }}"
- name: test
hosts: localhost
tasks:
- name: set vars
set_fact: config="o ip source-route\n!\n!\nip nbar protocol-pack bootflash:pp-adv-isr4000-169.1-34-47.0.0.pack \n!\n!\n!\n!\nip nb"
- name: regex vars
set_fact: result="{{ config | regex_search('.*ip nbar protocol-pack.*') | trim }}"
- name: show
debug:
var: result
result:
TASK [show] ***********************************************************************************************************************************************************************
ok: [localhost] => {
"result": "ip nbar protocol-pack bootflash:pp-adv-isr4000-169.1-34-47.0.0.pack"
}

Related

Ansible: 'regex_replace' removing every character starting with "#"

I have following registered variable with stdout and I want to remove every character starting with "#".
ok: [localhost] => {
"msg": [
"wazuh#4.3.10-4311"
]
}
Example: wazuh#4.3.10-4311 should become wazuh.
remove every character after "#"
---
- hosts: localhost
gather_facts: false
vars:
my_string: wazuh#4.3.10-4311
tasks:
- debug:
msg: "{{ my_string | regex_replace('#.*', '') }}"
Provides:
wazuh
One could also look at the use case as just interested in the left part of the #
delimitered string.
---
- hosts: localhost
gather_facts: false
vars:
my_string: wazuh#4.3.10-4311
tasks:
# For Ansible v2.9 and later
- name: Use of Python string method
debug:
msg: "{{ my_string.split('#') | first }}"
So not removing the part behind but only deliver the part before.
# For Ansible v2.10 and later
- name: Show left part with filter
debug:
msg: "{{ my_string | split('#') | first }}"
Also this solution it's working:
regex_replace('#.*$','')

Ansible to print the variable value having another variable inside it

In a.yml file, I have stored data like below
---
Server:
"Node1" : ["Node1", "Owner1", "ID1"]
"Node2" : ["Node2", "Owner2", "ID2"]
Now, in xyz.yml playbook, I tried to debug a variable as below and I am passing the Node_Name in commandline (ansible-playbook xyz.yml -e "Node_Name=Node1")
---
- name: "Print Variable value"
hosts: all
gather_facts: no
vars:
Node_Name: Node
ID_Name: "{{ Server.{{ Node_Name }}[2] }}"
tasks:
- name: "Print the id"
debug:
msg:
- "The id is {{ ID_Name }}"
But this is failing with error - Template error while templating string :expected name or number
Can someone please help to fix this and let me know how can I get the ID printed as output. Here expected output is ID1
You never nest {{...}} markers.
Recall that to access a nested variable. the syntax Server.Node1 is exactly equivalent to Server["Node1"]. The second syntax allows us to make use of variables (and string interpolation) on the key, so we can write:
Server[Node_Name]
In other words:
- name: "Print Variable value"
hosts: all
gather_facts: no
vars:
Node_Name: Node
ID_Name: "{{ Server[Node_Name][2] }}"
tasks:
- name: "Print the id"
debug:
msg:
- "The id is {{ ID_Name }}"

Ansible how to set_fact with condition or var base on condition

I have 3 types of servers: dev, qa and prod. I need to send files to server specific home directories, i.e:
Dev Home Directory: /dev/home
QA Home Directory:/qa/home
PROD Home Directory: /prod/home
I have var set as boolean to determine the server type and think of using set_fact with condition to assign home directories for the servers. My playbook looks like this:
---
- hosts: localhost
var:
dev: "{{ True if <hostname matches dev> | else False }}"
qa: "{{ True if <hostname matches qa> | else False }}"
prod: "{{ True if <hostname matches prod> | else False }}"
tasks:
- set_facts:
home_dir: "{{'/dev/home/' if dev | '/qa/home' if qa | default('prod')}}"
However, then I ran the playbook, I was getting error about 'template expected token 'name', got string> Anyone know what I did wrong? Thanks!
Use match test. For example, the playbook
shell> cat pb.yml
- hosts: localhost
vars:
dev_pattern: '^dev_.+$'
qa_pattern: '^qa_.+$'
prod_pattern: '^prod_.+$'
dev: "{{ hostname is match(dev_pattern) }}"
qa: "{{ hostname is match(qa_pattern) }}"
prod: "{{ hostname is match(prod_pattern) }}"
tasks:
- set_fact:
home_dir: /prod/home
- set_fact:
home_dir: /dev/home
when: dev|bool
- set_fact:
home_dir: /qa/home
when: qa|bool
- debug:
var: home_dir
gives (abridged)
shell> ansible-playbook pb.yml -e hostname=dev_007
home_dir: /dev/home
Notes:
The variable prod is not used because /prod/home is default.
prod/home is assigned to home_dir first because it's the default. Next tasks can conditionally overwrite home_dirs.
Without the variable hostname defined the playbook will crash.
A simpler solution that gives the same result is creating a dictionary of 'pattern: home_dir'. For example
- hosts: localhost
vars:
home_dirs:
dev_: /dev/home
qa_: /qa/home
prod_: /prod/home
tasks:
- set_fact:
home_dir: "{{ home_dirs|
dict2items|
selectattr('key', 'in' , hostname)|
map(attribute='value')|
list|
first|default('/prod/home') }}"
- debug:
var: home_dir
Adding an alternative method to achieve this. This kind of extends the group_vars suggestion given by #mdaniel in his comment.
Ansible has a ready-made mechanism to build the variables based on the inventory hosts and groups. If you organize your inventory, you can avoid a lot of complication in trying to match host patterns.
Below is a simplified example, please go through the link above for more options.
Consider an inventory file /home/user/ansible/hosts:
[dev]
srv01.dev.example
srv02.dev.example
[qa]
srv01.qa.example
srv02.qa.example
[prod]
srv01.prod.example
srv02.prod.example
Using group_vars:
Then you can have below group_var files in /home/user/ansible/group_vars/ (matching inventory group names):
dev.yml
qa.yml
prod.yml
In dev.yml:
home_dir: "/dev/home"
In qa.yml:
home_dir: "/qa/home"
In prod.yml:
home_dir: "/prod/home"
Using host_vars:
Or you can have variables specific to hosts in host_vars directory /home/user/ansible/host_vars/:
srv01.dev.example.yml
srv01.prod.example.yml
# and so on
In srv01.dev.example.yml:
home_dir: "/dev/home"
In srv01.prod.example.yml:
home_dir: "/prod/home"
These variables will be picked based on which hosts you run the playbook, for example the below playbook:
---
- hosts: dev
tasks:
- debug:
var: home_dir
# will be "/dev/home"
- hosts: prod
tasks:
- debug:
var: home_dir
# will be "/prod/home"
- hosts: srv01.dev.example
tasks:
- debug:
var: home_dir
# will be "/dev/home"
- hosts: srv01.prod.example
tasks:
- debug:
var: home_dir
# will be "/prod/home"

Return Variable from Included Ansible Playbook

I have seen how to register variables within tasks in an ansible playbook and then use those variables elsewhere in the same playbook, but can you register a variable in an included playbook and then access those variables back in the original playbook?
Here is what I am trying to accomplish:
This is my main playbook:
- include: sub-playbook.yml job_url="http://some-jenkins-job"
- hosts: localhost
roles:
- some_role
sub-playbook.yml:
---
- hosts: localhost
tasks:
- name: Collect info from Jenkins Job
script: whatever.py --url "{{ job_url }}"
register: jenkins_artifacts
I'd like to be able to access the jenkins_artifacts results back in main_playbook if possible. I know you can access it from other hosts in the same playbook like this: "{{ hostvars['localhost']['jenkins_artifacts'].stdout_lines }}"
Is it the same idea for sharing across playbooks?
I'm confused what this question is about. Just use the variable name jenkins_artifacts:
- include: sub-playbook.yml job_url="http://some-jenkins-job"
- hosts: localhost
debug:
var: jenkins_artifacts
This might seem complicated but I love doing this in my Playbooks:
rc defines the name of the variable which contains the return value
ar gives the arguments to the include tasks
master.yml:
- name: verify_os
include_tasks: "verify_os/main.yml"
vars:
verify_os:
rc: "isos_present"
ar:
image: "{{ os.ar.to_os }}"
verify_os/main.yml:
---
- name: check image on device
ios_command:
commands:
- "sh bootflash: | inc {{ verify_os.ar.image }}"
register: image_check
- name: check if available
shell: "printf '{{ image_check.stdout_lines[0][0] }}\n' | grep {{ verify_os.ar.image }} | wc -l"
register: image_available
delegate_to: localhost
- set_fact: { "{{ verify_os.rc }}": "{{ true if image_available.stdout == '1' else false }}" }
...
I can now use the isos_present variable anywhere in the master.yml to access the returned value.

Ansible parses strings as lists if the format is compatible, how to escape?

Using ansible, I need to put a list of hosts in line in a file like so:
["127.0.0.1", "127.0.0.2", "127.0.0.3"]
But whenever I achieve this format, ansible interprets it as a list and the content of the file is this pythonic version:
['127.0.0.1', '127.0.0.2', '127.0.0.3']
Here's my attempts to get it out thus far:
---
- hosts: all
gather_facts: False
tasks:
- set_fact:
myhosts:
- 127.0.0.1
- 127.0.0.2
- 127.0.0.3
# This comes out as a list, I need a string
- set_fact:
var: "[ \"{{ myhosts | join('\", \"')}}\" ]"
- debug: var=var
# This comes out as a string, but I need no underscore on it
- set_fact:
var: "_[ \"{{ myhosts | join('\", \"')}}\" ]"
- debug: var=var
# This also comes out as a list
- set_fact:
var: >
[ "{{ myhosts | join('", "')}}" ]
- debug: var=var
# Also parsed as a list
- set_fact:
var: "{{ myhosts | to_json }}"
- debug: var=var
# ansible-playbook -i "localhost," this_file.yml
There are some filters that prevent Ansible template engine from doing string evaluation.
This list of filters is stored in STRING_TYPE_FILTERS setting.
In Ansible 2.1 it contains: string, to_json, to_nice_json, to_yaml, ppretty, json.
So, you can do this:
- lineinfile: line="{{ myhosts | to_json }}" dest=output.txt
This will add ["127.0.0.1", "127.0.0.2", "127.0.0.3"] line to the file.
And don't believe debug's output when dealing with exact string formatting.
Always use copy: content="{{ string_output_to_test | string }}" dest=test.txt and check file contents to be sure.
debug: var=myvar will always template with evaluation, so your string will always be printed as a list.
debug: msg="{{ myvar | string }}" will print myvar as JSON encoded string.

Resources