Gather a List of Configured IP Addresses - ansible

I want to pull out the lines of a Juniper config that assign an IPv6 address to an interface and save that output to a file.
The output I am after is generated with the command 'show configuration | display set| match "inet6 address" '
I'm building an Ansible playbook and have pinballed off of errors to end up with the below task. It is basically giving me the complete interface configs, and I just want to narrow it down to the lines that would fit the "match" line in the manual command. The commented out filters aren't working and I can't find documentation that explains filters in a way that I understand.
- name: "Get selected configuration hierarchies"
juniper_junos_config:
host: "{{ ansible_host }}"
retrieve: "committed"
config_mode : "private"
filter: "<configuration><interfaces/></configuration>"
#filter: "<configuration><interfaces/><family/><inet6/><address/></configuration>"
#filter: "inet6/address"
format: "set"
options:
inherit: "inherit"
dest: "{{ inventory_hostname }}-inet6-config"
register: response
- name: "Print result"
debug:
var: response
Output:
ok: [LAB-QFX5110-1] => {
"response": {
"changed": false,
"config": "\nset interfaces xe-0/0/0 apply-groups-except jumbo-frames\nset interfaces xe-0/0/0 description \"Test Laptop - DMZ;000\"\nset interfaces xe-0/0/0 gigether-options 802.3ad ae12\n<SNIP>\nset interfaces lo0 unit 10 family inet address 100.126.0.x/32\nset interfaces lo0 unit 10 family inet6 address ABCD:EF00:0000:01c4::1/128\n<SNIP>/n",
"config_lines": [
"",
"set interfaces xe-0/0/0 apply-groups-except jumbo-frames",
"set interfaces xe-0/0/0 description \"Test Laptop - DMZ;000\"",
"set interfaces xe-0/0/0 gigether-options 802.3ad ae12",
"<SNIP>",
"set interfaces lo0 unit 10 family inet address 100.126.0.x/32",
"set interfaces lo0 unit 10 family inet6 address ABCD:EF00:0000:01c4::1/128",
"<SNIP>",
],
"failed": false,
"msg": "Configuration has been: opened, retrieved, closed."
}
}
I just want the lines that read:
set interfaces unit X family inet6 address XXXX:YYYY:ZZZZ:1234::1/127
But I can't seem to plug in the correct filter.
I will also mention that if there is a better way to gather this, I am open to exploring it. It just seems like this is the task Ansible was created to perform.

here is how to do it. since your response dictionary contains the output split by lines, we will use the config_lines key, process line by line:
code:
---
- hosts: localhost
gather_facts: false
vars:
response:
changed: false
config: |2-
set interfaces xe-0/0/0 apply-groups-except jumbo-frames
set interfaces xe-0/0/0 description "Test Laptop - DMZ;000"
set interfaces xe-0/0/0 gigether-options 802.3ad ae12
<SNIP>
set interfaces lo0 unit 10 family inet address 100.126.0.x/32
set interfaces lo0 unit 10 family inet6 address ABCD:EF00:0000:01c4::1/128
<SNIP>/n
config_lines:
- ''
- set interfaces xe-0/0/0 apply-groups-except jumbo-frames
- set interfaces xe-0/0/0 description "Test Laptop - DMZ;000"
- set interfaces xe-0/0/0 gigether-options 802.3ad ae12
- "<SNIP>"
- set interfaces lo0 unit 10 family inet address 100.126.0.x/32
- set interfaces lo0 unit 10 family inet6 address ABCD:EF00:0000:01c4::1/128
- "<SNIP>"
failed: false
msg: 'Configuration has been: opened, retrieved, closed.'
tasks:
- name: find entries containing inet6 address, add to results
set_fact:
interfaces: "{{ interfaces | default([]) + [item] }}"
when: item is search('inet6 address')
with_items:
- "{{ response.config_lines }}"
- debug:
var: interfaces
- name: save results to file
template:
src: results.j2
dest: /tmp/results.out
you will need a jinja2 template for the last task to work (under same dir as your playbook), with contents:
results.j2:
# processing results:
{% for interface in interfaces -%}
{{ interface }}
{%- endfor %}
1st task parses each line and if the when condition is met, its adding the given line to a results , the interfaces list. 2nd task prints that variable. 3rd task saves the results to a file under /tmp/.
hope it helps

Related

Checking my vmnic on ESXi server using Ansible

I want to Checking my vmnic on ESXi server.
Let me show my Ansible-playbook yaml code, it's very simple.
---
- hosts: host
vars:
vcenter_server: "192.168.35.219"
vcenter_user: "root"
vcenter_pass: "P#ssw0rd"
esxi_hostname: "esxihost1"
gather_facts: true
- name: Gather info about vmnics of an ESXi Host
community.vmware.vmware_host_vmnic_info:
hostname: '{{ vcenter_server }}'
username: '{{ vcenter_user }}'
password: '{{ vcenter_pass }}'
esxi_hostname: '{{ esxi_hostname }}'
validate_certs: no
delegate_to: localhost
register: host_vmnics
- name: print esxi info
ansible.builtin.debug:
var: host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details
I want display vmnic status using Ansible playbook.
I created a playbook as below and ran it.
However, it contains a lot of unnecessary information.
TASK [Gather info about vmnics of an ESXi Host] ***********************************************************************************************************
ok: [192.168.35.219 -> localhost]
TASK [print esxi info] ************************************************************************************************************************************
ok: [192.168.35.219] => {
"host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details": [
{
"actual_duplex": "Full Duplex",
"actual_speed": 10000,
"adapter": "VMware Inc. vmxnet3 Virtual Ethernet Controller",
"configured_duplex": "Full Duplex",
"configured_speed": 10000,
"device": "vmnic0",
"driver": "nvmxnet3",
"lldp_info": "N/A",
"location": "0000:0b:00.0",
"mac": "00:0c:29:bc:67:65",
"status": "Connected"
}
]
}
I only want to see actual_duplex,actual_speed,device,status
like below
"host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details": [
{
"actual_duplex": "Full Duplex",
"actual_speed": 10000,
"device": "vmnic0",
"status": "Connected"
}
]
}
And, actual duplex: Full Duplex actual speed: 10000, device: vmnic0, status: Connected If each value is correct, "OK"
If not, I want to display it as "NOTOK".
Is it possible?
Regarding
it contains a lot of unnecessary information
you may have a look into the general documentation about Ansible Return Values
Ansible modules normally return a data structure that can be registered into a variable, or seen directly when output by the ansible program.
and because of
Each module can optionally document its own unique return values
into the specific documentation about vmware_host_vmnic_info module - Return Values.
dict with hostname as key and dict with vmnics information as value
In other words, the data structure hosts_vmnics_info returned just contain all this vmnic_details.
Regarding
I only want to see actual_duplex, actual_speed, device, status
you can access the key values by using in example something like
- name: Show
debug:
msg: "Device {{ host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details[0].device }} is in status {{ host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details[0].status }} at an actual speed of {{ host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details[0].actual_speed }} in mode {{
host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details[0].actual_duplex }}"
Further Documenation
Using Variables
Referencing list variables
Referencing key:value dictionary variables
Regarding
If the vmnic is not status: Connected, "NOT OK" is output. I want to do something similar a shell script if [[ "foo" == "$var" ]]; Then OK else Not OK fi
you could use an approach with the assert module like
- name: Check connection status
ansible.builtin.assert:
that:
- "host_vmnics.hosts_vmnics_info.esxihost1.vmnic_details[0].status == 'Connected'"
fail_msg: "NOT OK"
success_msg: "OK"

Adding a value to a template from a variable

I have a variable test
test:
- 10.0.0.1
- 10.0.0.2
- 10.0.0.3
- 10.0.0.4
And there is a config file where you need to insert one value from this variable. There should be 4 config files in the output, each file contains one line from this test variable. I figured out how to make 4 files be created with ip names from the list, but I can't understand how to make ip substituted into the template.
From template:
auto br_omgt
iface br_omgt inet static
bridge_ports bond0.2210
address {{ db }}
netmask 255.255.255.192
gateway 10.15.35.62
You have to use the module template.
Your file must be jinja2.
role/MY_Role/templates/my_file.txt.j2
my_file.txt.j2
auto br_omgt iface br_omgt inet static bridge_ports bond0.2210 address {{ db }} netmask 255.255.255.192 gateway 10.15.35.62
my_file.txt
auto br_omgt iface br_omgt inet static bridge_ports bond0.2210 address 10.0.0.1 netmask 255.255.255.192 gateway 10.15.35.62
Playbook :
vars:
db: 10.0.0.1
tasks:
- name: Use Template
template:
src: my_file.txt.j2
dest: home/My_User/my_file.txt
With a loop, you got 4 files. ( Extended )
vars:
db: 10.0.0.1
10.0.0.2
tasks:
- name: Use Template looped
template:
src: my_file.txt.j2
dest: home/My_User/my_file_{{index}}.txt
loop_control:
extended: yes
loop: "{{ db }}"

Ansible parse_cli build object from config lines in arbitrary order

I'm trying to parse a DHCP scope from a range of Cisco IOS routers using Ansible.
< TL;DR; > I'm currently using parse_cli with a regex including multiple named matches for the same thing in different positions (e.g. domain_name_1, domain_name_2) then combining them in the output object by assigning them as domain_name: "{{ item.domain_name_1 }}{{ item.domain_name_2 }}" - as only one of them at a time will be populated, the output object still contains the correct data. I'd like to find a way to do it which doesn't require ugly inflexible hacks like that. < /TL;DR; >
I like the parse_cli Jinja filter as it provides a nice object as the output containing only the info I need, but I can't work out a way to have it cope with an arbitrary order of commands in the config.
Three examples of the same config in different order are as follows. Order of config lines can vary depending on which firmware version the router is running, the order the commands were entered in, or the model of router. The commands themselves (in this case) will always be the same so I just need a way to pull out each line and parse it appropriately.
Cisco 867
ip dhcp pool Data
import all
network 192.168.1.0 255.255.255.0
update dns
default-router 192.168.1.1
dns-server 192.168.1.1 8.8.8.8
option 42 ip 192.168.1.1
domain-name test.local
lease 8
Cisco 881
ip dhcp pool Data
import all
network 192.168.1.0 255.255.255.0
option 42 ip 192.168.1.1
default-router 192.168.1.1
dns-server 192.168.1.1 8.8.8.8
domain-name test.local
lease 8
Cisco 1111
ip dhcp pool Data
import all
network 192.168.1.0 255.255.255.0
default-router 192.168.1.1
dns-server 192.168.1.1 8.8.8.8
domain-name test.local
option 42 ip 192.168.1.1
lease 8
In all of those cases or any other new order which appears in future, I want to create an object in ansible as a fact with format:
{
"network": "192.168.1.0",
"dns-servers": ["192.168.1.1", "8.8.8.8"],
"domain-name": "test.local",
"options": {
"42": {
"type": "ip",
"value": "192.168.1.1"
}
}
}
Currently I'm doing something like this:
tasks/main.yml
- name: Get Cisco IOS DHCP pools
ios_command:
commands:
- 'show running-config | s ip dhcp pool'
retries: 1
register: ciscoios_dhcp_pool_output
- name: Convert Cisco IOS DHCP pools to list
delegate_to: 127.0.0.1
set_fact:
info_dhcp_pools: "{{ ciscoios_dhcp_pool_output.stdout[0] | parse_cli('roles/get-router-dhcp-pools/parsers/ios-pools.yml') }}"
parsers/ios-pools.yml
---
vars:
dhcp_pool:
name: "{{ item.name }}"
network: "{{ item.network_ip }}"
subnet: "{{ item.network_subnet }}"
dns_servers: "{{ item.dns_servers_1 }}{{ item.dns_servers_2 }}"
domain_name: "{{ item.domain_name_0 }}{{ item.domain_name_1 }}{{ item.domain_name_2 }}{{ item.domain_name_3 }}"
options: "{{ item.options_1 }}{{ item.options_2 }}"
lease_days: "{{ item.lease_days }}"
lease_hours: "{{ item.lease_hours }}"
lease_minutes: "{{ item.lease_minutes }}"
keys:
dhcp_pools:
value: "{{ dhcp_pool }}"
items: "^ip dhcp pool (?P<name>[^\\n]+)\\s+(?:import (?P<import_all>all)\\s*)?(?:network (?P<network_ip>[\\d.]+) (?P<network_subnet>[\\d.]+)?\\s*)?(?:update dns\\s*)?(?:host (?P<host_ip>[\\d.]+) (?P<host_subnet>[\\d.]+)\\s*)?(?:domain-name (?P<domain_name_0>[\\w._-]+)\\s+)?(?:default-router (?P<default_router>[\\d.]+)\\s*)?(?:dns-server (?P<dns_servers_1>(?:[\\d.]+ ?)+ ?)+\\s*)?(?:domain-name (?P<domain_name_1>[\\w._-]+)\\s+)?(?P<options_1>(?:option [^\\n]+\\n*\\s*)*)?(?:domain-name (?P<domain_name_2>[\\w._-]+)\\s+)?(?P<options_2>(?:option [^\\n]+\\n*\\s*)*)?(?:dns-server (?P<dns_servers_2>(?:[\\d.]+ ?)+ ?)+\\s*)?(?:domain-name (?P<domain_name_3>[\\w._-]+)\\s*)?(lease (?P<lease_days>\\d+)(?: (?P<lease_hours>\\d+))?(?: (?P<lease_minutes>\\d+))?\\s*)?(?:update arp)?"
That however feels very messy, and requires updates every time I discover a new order that config lines can appear in. It feels like the sort of thing that there should be a better way to achieve but I'm not sure on what it is.

ipaddr or ipv4 filter in ansible changes non quad string to quad

I am writing ansible playbook to test if an ip address is a valid ipv4 address.
I wrote a playbook to check the ip address if it's a valid ip. But for testing when I provide ip address as 10.10.10 still it is matched as a valid ipv4 address.
- name: IP validation example
hosts: 127.0.0.1
gather_facts: False
vars:
single_ipv4: 10.10.10
tasks:
- name: check ip
set_fact:
single_ipv4_val: "{{ single_ipv4 | ipv4 }}"
Expected result: ok: [127.0.0.1] => {"ansible_facts":
{"single_ipv4_val": false}, "changed": false}
Actual Result: ok: [127.0.0.1] => {"ansible_facts":
{"single_ipv4_val": "10.10.10.0"}, "changed": false}
As best I can tell, you are running afoul of ipaddr's "helpfulness" because the thing you provided is almost an IP address, but ipaddr deals with more than just IP addresses, it sniffs out subnets and all kinds of things
So what you'll want is a more strict test, saying that the input must be an IP who's "address" subcomponent equals itself:
- debug:
msg: '{{ maybe_ip == (maybe_ip | ipv4("address")) }}'
vars:
maybe_ip: '10.10.10'
- debug:
msg: '{{ maybe_ip == (maybe_ip | ipv4("address")) }}'
vars:
maybe_ip: '10.10.10.1'

Looping over list data in Ansible playbooks

In my quest to automate some of our network environment I would like to know how you could loop over different items in nested lists. To make it more clear I will explain what I want to do using my existing inventory and playbook.
Inventory looks as followed, (Dummy Content)
parameters:
- mode: ""
speed: ""
duplex: ""
interfaces:
- Int_One
- Int_Two
So as you can see I have a list containing some network information (parameters) and another list containing two interfaces. The action that I want to accomplish in my playbook is to configure those two interfaces with the information found in the "parameters" list. In other words, loop over the "interfaces" using the information in the "parameters" list. But as of right now I can't get it to use the right data in the right time
Good to know is that I'm using a predefined "Cisco network module" in my playbook.
Playbook looks as followed,
- name: Deploy Network Interfaces
"Some network module":
mode: '{{ item.0.mode }}'
speed: '{{ item.0.speed }}'
duplex: '{{ item.0.duplex }}'
interface: '{{ item.1.interfaces }}'
state: present
delegate_to: localhost
loop:
- "{{ parameters }}"
- "{{ parameters|subelements('interfaces') }}"
As you can see the network module requires the "interface" to be provided. So again I want to iterate over the "interfaces" list and deploy them with the defined data in the "parameters" list.
Anyone that can tell me how to handle this issue?
Thanks in advance!
Your question is a little confusing. You have two variables; a list named parameters:
parameters:
- mode: ""
speed: ""
duplex: ""
And a list named interfaces:
interfaces:
- Int_One
- Int_Two
parameters has a single item, while interfaces has two. The fact that they have different numbers of items makes it hard to figure out how they are related. If each interface has unique parameters, you probably want something like this instead:
interfaces:
- name: Int_One
mode: ""
speed: ""
duplex: ""
- name: Int_Two
mode: ""
speed: ""
duplex: ""
In which case you would write your playbook like this:
- name: Deploy Network Interfaces
"Some network module":
mode: '{{ item.mode }}'
speed: '{{ item.speed }}'
duplex: '{{ item.duplex }}'
interface: '{{ item.name }}'
state: present
delegate_to: localhost
loop: "{{ interfaces }}"
On the other hand, if all interfaces will have the same parameters, then maybe you would structure your data like this:
parameters:
mode: ""
speed: ""
duplex: ""
interfaces:
- Int_One
- Int_Two
And write your playbook like this:
- name: Deploy Network Interfaces
"Some network module":
mode: '{{ parameters.mode }}'
speed: '{{ parameters.speed }}'
duplex: '{{ parameters.duplex }}'
interface: '{{ item.name }}'
state: present
delegate_to: localhost
loop: "{{ interfaces }}"
Given your example, a solution would be the following:
- hosts:
- localhost
gather_facts: False
vars:
parameters:
- mode: "auto"
speed: "1000"
duplex: "full"
interfaces:
- Int_One
- Int_Two
tasks:
- name: DBEUG
debug:
msg: >
mode: {{parameters.0.mode}},
speed: {{parameters.0.speed}},
duplex: {{parameters.0.duplex}},
interface: {{item}}
loop:
"{{interfaces}}"

Resources