Ansible (part 2): parametrization for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR
Anton Karneliuk
Hello my friend,
In this article I’ll finalize the review of the Ansible for automation network tasks, which I’ve started the last week in the previous article. The main focus is the per-node parametrization of the playbooks, so that you can really successfully use Ansible for massive roll outs in networks, built with Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR.
1 2 3 4 5
No part of this blogpost could be reproduced, stored in a
retrieval system, or transmitted in any form or by any
means, electronic, mechanical or photocopying, recording,
or otherwise, for commercial purposes without the
prior permission of the author.
Brief overview
The last week I was discussing Ansible in general and playbooks from my previous article with my colleague from customer’s service provider. He has made reasonable remark that my automation works but it’s necessary to change IPv4/IPv6 address at the interface afterwards. This fact eliminates the positive effect from the rollout.
I’ve bought wonderful book Ansible for DevOps and found a lot of interesting and useful information, which has helped me to add parametrization depending on particular node and turn usage of Ansible for network tasks from fancy toy to real helper in roll outs. So I want to share with you this information alongside with real playbooks that you can reuse.
What are we going to test?
We are continue deploying BGP/MPLS IP VPNs, so I’m going to solve the same task as in the first article about Ansible. My task is to create such Anisble’s playbook that will automatically create VPRN/VRF and all related parameters, just like it was previously. But newly configured interfaces must have different IPv4 and IPv6 addresses at different nodes. So main focus is to achieve such agility keeping playbook simple.
Topology
Physical topology is the same as it was in previous article:
Logical topology is also the same:
Management in our lab is also the same, as it was in the previous lab:
In the previous article we have created an inventory file that is used for gathering nodes, where playbooks or ad-hoc commands must be performed. The entries were IPv4 addresses. It’s possible, but in general not very convenient. In production environment you have an established DNS system, so you can just put in hosts names of your devise. I don’t have DNS server configured, so I’ll update system hosts file in order to map names to IP addresses.
The next step is to generate new SSH keys for these nodes, otherwise Ansible won’t able to connect to the devices. Just connect to them before playing playbooks:
[root@localhost ~]# ssh admin@SR1
RSA key fingerprint is 94:47:a9:b3:66:94:91:19:a6:12:a1:57:57:cd:fd:ef.
Are you sure you want to continue connecting (yes/no)? yes
It isn’t necessary, but it will make things more clear later.
BGP/MPLS IP VPN Service topology
At the picture above you see how the service that we are going to build looks like:
We follow the same guidelines for IP VPN service as in the previous lab. IP VPN supports both IPv4 and IPv6 address families; route-distinguisher is configured as IPv4_address_system_interface:100 and route-target is 65000:100. In each VRF/VPRN we have an interface with the same VLAN tag that is 444 and the same access-list that allows access only to certain subnet (IPv4: 192.168.0.0/24, IPv6: fc00::192:168:0:0/96) for attached nodes. But it must be possible to change all of these parameters (and some others) globally or per node easily without modifying playbook, so that by playing one book each node receives its specific values.
Short summary of Ansible’s variables
You remember that Ansible uses YAML as scripting language for its playbook. I’m pretty sure that each scripting language has possibility to define variables and to use them afterwards, and YAML isn’t something different. You may remember, we had the following code in the previous article:
There are dots in the beginning just to make structure visible. Omit them for the configuration.
Actually string “{{ inventory_hostname }}” is call of the variable, which has hostname of the node as it is in the inventory file. It’s a kind of built in variables, so we don’t define beforehand ourselves. But we’ve done it for one other variable, which is called “cli”:
You might find such string in the previous playbooks. It’s actually call of variable “cli”, which was defined in the part “vars” in the beginning.
Another good information, which is crucial for us, is that we can keep variables in separate external files that are written in the same YAML format. These files are just mentioned in the beginning of the playbook. What is even better, the name of the file can be also variable, what allows us to call necessary variables depending on the node, which playbook is applied to.
Ok, basic theory regarding variables in YAML/Ansible is known to you, let’s use for building awesome playbooks.
Creating per node and per service configuration files
First of all let’s create files, where will be collected per node parameters, which must be applied during playbook execution. For the sake of convenience, I put them into separate folder in the folder, where the playbook lays:
Later in the playbook I’ll be calling this parameters in the form “{{ node_var.rd_base }}” for example. It’s possible to remove that “node_var:” string and simply call “{{ rd_base }}”, but as I have a couple of external configuration files, it’s easier for me to understand reading the playbook, which file contains certain variable. Also you might spot that some parameters are different for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR, because in this certain case we need less parameters for Cisco IOS XR’s configuration.
The next folder that I want to create will contain connectivity information. As Nokia and Cisco has different credentials, I’m going to configure them:
[root@localhost nodes]# cd ..
[root@localhost ansible_test_scripts]# mkdir login
[root@localhost ansible_test_scripts]# cd login/
[root@localhost login]# touch cisco_credentials.yml
[root@localhost login]# touch nokia_credentials.yml
In these files I put information, what was previously contained in “vars” in the previous article:
It might be questionable, where to put VLAN_ID for the service: here or in per-node files. It’s absolutely up to you. From my experience, usually the VLAN id for customer or for service is the same across all routers in the network, just because it’s simple. On the other hand, PORT_IDs might be different depending on the router model. That’s why in my approach I put VLAN_ID in service template, whereas PORT_ID in the node template.
Modifying Ansible playbooks
Now it’s time to change Ansible playbooks for Nokia (Alcatel-Lucent) SR OS and Cisco IOS XR in the way they start to use variables instead of fixed values:
Remember, playbooks lay in the root folder comparing to creates sub folders
Spaces before words is absolutely important for YAML. Make sure they are consistent like in my example. Remove “.” In the beginning of each string and you copy-paste this config.
These playbooks do just the same, what they have done previously: they create IP VPN service across network devices either Nokia (Alcatel-Lucent) SR OS based or Cisco IOS XR based.
You may see that here we don’t have any single parameter that is defined in these playbooks. All parameters are called from external files, whereas these files are defined in the beginning of the playbook within “vars_files” part. Of particular interest is how we call per node files. You see that they are called as “nodes/{{ inventory_hostname }}.yml”. This works as follows:
playbook starts reading corresponding part of inventory file (hosts: nokia);
it assigns the first read value “SR1” to the variable “inventory_hostname”;
this effectively defines configuration file for node SR1: “nodes\SR1.yml”;
variables “node_var.*” are loaded from that file the playbook;
when the playbook is applied for the next node (i.e. SR2), its name is applied to “{{ inventory_hostname }}” and the process is done in the same way.
Let’s execute the playbook for Nokia (Alcatel-Lucent) SR OS routers and see what is going on:
It looks like everything is configured properly. Let’s briefly compare created configuration for VPRN part:
Ansible playbook
Ansible playbook
Nokia (Alcatel-Lucent) SR OS – SR1
Nokia (Alcatel-Lucent) SR OS – SR2
A:SR1# configure service vprn 100500
A:SR1>config>service>vprn# info
————————-
route-distinguisher 10.0.255.11:100
auto-bind-tunnel
resolution any
exit
vrf-target target:65000:100
interface “toCUST” create
address 192.168.1.1/24
ipv6
address fc00::192:168:1:1/112
exit
sap 1/1/2:444 create
ingress
filter ip 10
filter ipv6 10
exit
exit
exit
no shutdown
————————-
A:SR2# configure service vprn 100500
A:SR2>config>service>vprn# info
————————-
route-distinguisher 10.0.255.22:100
auto-bind-tunnel
resolution any
exit
vrf-target target:65000:100
interface “toCUST” create
address 192.168.2.1/24
ipv6
address fc00::192:168:2:1/112
exit
sap 1/1/2:444 create
ingress
filter ip 10
filter ipv6 10
exit
exit
exit
no shutdown
————————-
It’s very impressive, isn’t it? We have just launched playbook once, and each Nokia (Alcatel-Lucent) VSR router has got configuration modified with its specific parameters. Basically we need to prepare playbook, node-specific and service-specific templates and launch our script. Rollout is done further automatically. Let’s briefly check the content of routing tables at Nokia (Alcatel-Lucent) SR OS routers and make ping verification:
A:SR1# show router 100500 route-table
============================================================================
Route Table (Service: 100500)
============================================================================
Dest Prefix[Flags] Type Proto Age Pref
. Next Hop[Interface Name] Metric
—————————————————————————-
192.168.1.0/24 Local Local 01h22m58s 0
. toCUST 0
192.168.2.0/24 Remote BGP VPN 00h03m32s 170
. 10.0.255.22 (tunneled) 0
—————————————————————————-
No. of Routes: 2
============================================================================
!
!
A:SR1# ping router 100500 192.168.2.1
PING 192.168.2.1 56 data bytes
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=9.07ms.
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=3.75ms.
^C
ping aborted by user
—- 192.168.2.1 PING Statistics —-
2 packets transmitted, 2 packets received, 0.00% packet loss
round-trip min = 3.75ms, avg = 6.41ms, max = 9.07ms, stddev = 0.000ms
You don’t see any routes from Cisco IOS XR routers, because we haven’t executed that playbook and because I’m launching separately Nokia and Cisco routers due to limited resources at my laptop.
Let’s turn to Cisco IOS XR now. As playbook and all configuration templates are ready, I just have to execute it:
Our parametrization works quite well, so we make just the last check:
RP/0/0/CPU0:XR4#show route vrf ACME_100500 ipv6
B fc00::192:168:3:0/112
. [200/0] via ::ffff:10.0.255.33 (nexthop in vrf default), 00:02:52
C fc00::192:168:4:0/112 is directly connected,
. 00:03:01, GigabitEthernet0/0/0/0.444
L fc00::192:168:4:1/128 is directly connected,
. 00:03:01, GigabitEthernet0/0/0/0.444
!
!
RP/0/0/CPU0:XR4#ping vrf ACME_100500 fc00::192:168:3:1 source fc00::192:168:4:1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to fc00::192:168:3:1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/8/19 ms
Ok, for Cisco IOS XR our playbook works as well.
I’ve collected all my Anisble’s files from this lab in one tar archive so that it will be easier for you to test it and update for your needs. This archive contains also playbooks from the previous Ansible lab: ansible_nokia_cisco
Lessons learned
By the way, I haven’t tested in the details the initial configs in the previous lab and have missed one thing in Cisco IOS XR configuration. This thing is IPv6 addresses at loopback 0. They aren’t used anywhere in configuration, but they must be configured in order to bring ipv6/vpnv6 peering (though technically we use IPv4 address for BGP session and MPLS LSPs). This issue exists only in Cisco IOS XR, because in Cisco IOS / IOS XE there is no such problem. When I started to test pings between XR3 and XR4 I’ve found that I can perform then. After discovering that BGP is dead, I’ve configured IPv6 addresses at loopbacks 0 and everything started working.
Conclusion
Ansible is great thing to reduce the time for massive deployments. Personally I’ve started using it for reconfiguration of the devices for labs. With the parameterization its power only increases, as it comes from fancy-scripting-toys into something really useful for commercial operations. You can focus on learning new technologies or designing new solutions for your Nokia (Alcatel-Lucent) SR OS or Cisco IOS XR networks. Take care and good bye!