Ansible

In this section of the lab you will configure all the Ansible components so that the CI/CD pipeline will automatically configure OSPF interfaces on the two Cisco Nexus 9000v virtual switches. Ansible will act as the configuration management tool for the CI/CD pipeline.

group_vars

Let's start by creating a new folder called group_vars within the cicd folder. As you might know, the group_vars folder has a special meaning in Ansible. This folder contains variables, such as usernames and passwords, that apply to a group of devices. In this new group_vars folder, create a new file called nxos.yaml and populate it with the following entries. Make sure to include the three dashes, ---, at the top of the file.

---
ansible_user: cisco

ansible_password: cisco

ansible_network_os: nxos

These entries specify the username, password and type of network operating system that Ansible will use to establish SSH connections to the two Nexus 9000v virtual switches running in Cisco CML.

host_vars

Next, create a new folder called host_vars also within the cicd folder. The host_vars folder has a special role with Ansible as well. It contains specific individual device variables that can be referenced when creating Ansible playbooks. In this new host_vars folder, create two new files called 10.10.20.177.yml and 10.10.20.178.yml. Each of these files will contain OSPF configuration variables pertaining to each individual virtual switch.

Populate the 10.10.20.177.yml file with the following entries:

---
ospf_process_id: 1
router_id: 192.168.0.1

configure_ospf:
    - nxos_ospf_interface: loopback0
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 192.168.0.1/32
    - nxos_ospf_interface: vlan101
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.101.2/24
    - nxos_ospf_interface: vlan102
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.102.2/24
    - nxos_ospf_interface: vlan103
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.103.2/24
    - nxos_ospf_interface: vlan104
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.104.2/24
    - nxos_ospf_interface: vlan105
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.105.2/24

As you can see, the first Nexus 9000v virtual switch is configured with an OSPF process ID of 1, a router ID matching the IPv4 address of interface Loopback0, 192.168.0.1, and six interfaces (Loopback0 and VLAN interfaces from 101 to 105) configured to be part of the OSPF advertisements sent through the network.

The second YAML file, 10.10.20.178.yml will contain OSPF configuration information for the second Nexus 9000v virtual switch and should be populated with the following information:

---
ospf_process_id: 1
router_id: 192.168.0.2

configure_ospf:
    - nxos_ospf_interface: loopback0
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 192.168.0.2/32
    - nxos_ospf_interface: vlan101
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.101.3/24
    - nxos_ospf_interface: vlan102
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.102.3/24
    - nxos_ospf_interface: vlan103
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.103.3/24
    - nxos_ospf_interface: vlan104
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.104.3/24
    - nxos_ospf_interface: vlan105
      nxos_ospf_number: 1
      nxos_ospf_area: 0.0.0.0
      nxos_ip: 172.16.105.3/24

Similar to the first virtual switch, the second Nexus 9000v is also configured with an OSPF process ID of 1, a router ID matching the IPv4 address of its Loopback0 interface and six interfaces (Loopback0 and VLAN interfaces from 101 to 105) that will be as part of the OSPF network.

The folder structure of the cicd folder should look like below thus far:

hosts

Next, in the cicd folder create a new file called hosts. This file contains the IPv4 addresses of the two Nexus switches and creates a grouping of these two devices called nxos

[nxos]
10.10.20.177
10.10.20.178

You will reference this grouping in the next step when you create the Ansible playbook that configures the two virtual switches for OSPF.

configure-ospf.yml

Under the cicd folder create a new folder called actions. In this newly created folder, create a new folder called configure-ospf and within this folder create a new file called configure-ospf.yml. Creating this folder structure gives you the option to easily extend the functionality of the pipeline by simply creating additional folders such as configure-bgp, configure-eigrp, etc. within the actions folder.

Populate the configure-ospf.yml file with the following YAML text:

---

- name: Playbook to unconfigure interfaces and remove OSPF
  hosts: nxos
  gather_facts: false
  vars:
    ansible_connection: network_cli
  tasks:
  - name: Remove OSPF route from interface
    loop: "{{ configure_ospf }}"
    cisco.nxos.nxos_interface_ospf:
      interface: "{{ item.nxos_ospf_interface }}"
      ospf: "{{ item.nxos_ospf_number }}"
      area: "{{ item.nxos_ospf_area }}"
      state: absent

- name: Playbook to Configure interfaces for OSPF
  hosts: nxos
  gather_facts: false
  vars:
    ansible_connection: network_cli
  tasks:
  - name: CONFIGURE OSPF PROCESS ID AND AREA AND ROUTER ID
    cisco.nxos.nxos_config:
      lines:
        - 'router-id {{ router_id }}'
      parents: 'router ospf {{ ospf_process_id }}'
      before: 'no router ospf {{ ospf_process_id }}'


  - name: Create interface
    loop: "{{ configure_ospf }}"
    cisco.nxos.nxos_interfaces:
      config:
      - name: "{{ item.nxos_ospf_interface }}"
        description: "{{ item.nxos_ospf_interface }} Configured by Ansible"
        enabled: true
      state: merged

  - name: Set interface IPv4 address
    loop: "{{ configure_ospf }}"
    cisco.nxos.nxos_l3_interface:
      name: "{{ item.nxos_ospf_interface }}"
      ipv4: "{{ item.nxos_ip }}"
      state: present

  - name: Add OSPF configuration to the interface
    loop: "{{ configure_ospf }}"
    cisco.nxos.nxos_interface_ospf:
      interface: "{{ item.nxos_ospf_interface }}"
      ospf: "{{ item.nxos_ospf_number }}"
      area: "{{ item.nxos_ospf_area }}"
      state: present

This Ansible playbook uses the cisco.nxos collection to first remove the OSPF configuration from the interfaces and then re-apply the OSPF configuration based on the host_vars YAML files.

First thing to notice is the hosts key in the playbook. The hosts that this playbook will run against are contained in the nxos group that was defined in the hosts file. This means that this playbook will run on the hosts with IPv4 addresses of 10.10.20.177 and 10.10.20.178. The credentials to connect to these devices will be retrieved by Ansible from the group_vars nxos.yaml file. And the configuration that will be applied to these devices will be retrieved from the YAML files in the host_vars folders.

As interfaces on these two virtual switches get configured for OSPF and also removed from the OSPF configuration is important to notice that the playbook starts by removing the OSPF configuration from all interfaces first. Why is this the case? If you were to only add interfaces to the OSPF configuration then you could skip this first step of the playbook but since in real life you both add and remove OSPF interface configurations, this is the only way that addresses OSPF configuration removal.

You can also see extensive usage of variables as defined in the 10.10.20.177.yml and 10.10.20.178.yml files in this playbook. The loop keyword is basically a for loop that iterates over all interfaces, one interface at a time. Variables are included in the Ansible playbook between curly braces, {{variable}}. For example, configure_ospf variable in the playbook, references the configure_ospf section defined in the YAML files created under the host_vars folder. As Ansible iterates over each interface with the loop command, the item keyword is needed to reference and access the value of the variables defined in the host_vars YAML files.

After all the changes and new files and folders created so far, it is time to upload this new data centrally into the GitLab cicd repo. As mentioned before, the cicd folder on the CentOS virtual machine you are connected to is a copy of the cicd repo that is hosted by GitLab on the same virtual machine. You can verify the status of this repo in GitLab by connecting to http://10.10.20.50 using the username developer and the password C1sco12345. Once logged in, select the developer ansible\cicd project and the following information should be displayed:

As you can see, the Ansible folders, files and playbook that you created are not yet uploaded to GitLab. Back in Visual Studio Code, issue the git status command in the terminal window. You should see a status similar to the following one:

[developer@gitlab cicd]$ git status
# On branch main
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       actions/
#       group_vars/
#       host_vars/
#       hosts
nothing added to commit but untracked files present (use "git add" to track)

You can see that git has detected that there are untracked files present but they have not been added to commit. In order to add all these files and folders to commit, issue the git add . command in the terminal window in the cicd folder. Issue a new git status command right after git add . and you should see the following output:

[developer@gitlab cicd]$ git add .
[developer@gitlab cicd]$ git status
# On branch main
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   actions/configure-ospf/configure-ospf.yml
#       new file:   group_vars/nxos.yaml
#       new file:   host_vars/10.10.20.177.yml
#       new file:   host_vars/10.10.20.178.yml
#       new file:   hosts
#

All the new files and folders are now in staging and are ready to be commited for tracking. Issue the git commit -m "added Ansible configuration files and folders" command in the terminal to track changes on these files.

[developer@gitlab cicd]$ git commit -m "added Ansible configuration files and folders"
[main ba5d416] added Ansible configuration files and folders
 5 files changed, 120 insertions(+)
 create mode 100644 actions/configure-ospf/configure-ospf.yml
 create mode 100644 group_vars/nxos.yaml
 create mode 100644 host_vars/10.10.20.177.yml
 create mode 100644 host_vars/10.10.20.178.yml
 create mode 100644 hosts

All the files are now commited for tracking and ready to be uploaded centrally to the GitLab server. Issue the git push command next, to upload the new files to GitLab. Provide the developer username and C1sco12345 password to authenticate to GitLab and upload the files.

[developer@gitlab cicd]$ git push
Counting objects: 12, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (11/11), 1.44 KiB | 0 bytes/s, done.
Total 11 (delta 1), reused 0 (delta 0)
To http://10.10.20.50/developer/cicd.git
   b2d6102..dae6ece  main -> main

Refresh the web browser connection to http://10.10.20.50/developer/cicd and you should see the new Ansible folders and files have been successfully uploaded to GitLab.

Next, let's have a look at Cisco pyATS.