Deploy Static Ports in ACI using Ansible

Use Ansible to automate repetitive tasks

Alt text

General

Sometimes you want to deploy the same Static Port to multiple EPGs. For example when you have a Fabric Interconnector connected through a VPC Static port to your EPGs then every static port is basically a vlan tag for the trunk port.

This task can be automated with Ansible. We will configure a Syntax that collects data of your EPGs and compares this data to CSV files and deploys the VPC policy to the EPGs.


I created a VPC policy that is connected to eth1/1 of Leaf1 and Leaf2.

Alt text

I also created 4 EPGS/BD and two VRFs.

Alt text

Config

I start with the two csv files I use. The first is for he Endpoint Groups that should get the policies and the second is the vpc policy itself.

epg.csv

name,vlan,vrf
Oracle,110,T
Heroku,120,T
Oracle,130,P
Heroku,140,P

vpcpolicy.csv

pod,leaves,iface
1,101-102,server_int1_1_VPC

The main.yml includes the login variables and imports the epg.csv file. Then it will start add_vpc.yml and pass the content of epg.csv as loop line by line. I use the Cisco.ACI module for Ansible. In ACI REST API I explained how to install the module.

main.yml

---
- name: Create-tenant
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    ansible_python_interpreter: /usr/bin/python3
    aci_host: 192.168.15.81
    aci_username: admin
    aci_password: cisco123

  tasks:
    - name: Include epg
      community.general.read_csv:
        path: epg.csv
      register: epgfile

    - ansible.builtin.include_tasks: add_vpc.yml
      loop: "{{ epgfile.list }}"
      loop_control:
        loop_var: epg

The add_vpc.yml will use the ACI REST API to get all Static Ports of an EPG and save it in query_result.

It then starts a subtask to write the Static Ports in an array called userdata.

Then it imports the vpcpolicy.csv file and creates a vpc ONLY when the EPG does not already have the VPC configured. I do this by comparing the userdata array with the imported vpcpolicy list.

add_vpc.yml

---
- ansible.builtin.set_fact:
    userdata: []

- name: Track vpcpolicy in EPG
  cisco.aci.aci_rest:
    host: "{{ aci_host }}"
    username: "{{ aci_username }}"
    password: "{{ aci_password }}"
    validate_certs: false
    method: get
    path: api/node/mo/uni/tn-TNT1/ap-{{ epg.vrf }}_AP/epg-{{ epg.name }}_{{ epg.vrf }}_EPG.json?query-target=subtree&target-subtree-class=fvRsPathAtt
  register: query_result

- ansible.builtin.include_tasks: add_vpc_subtask.yml
  with_sequence: "0-2"
  when: "{{query_result['imdata'][item|int]['fvRsPathAtt']['attributes']['dn'] is defined}}"

- name: Include vpc policy
  community.general.read_csv:
    path: vpcpolicy.csv
  register: vpcfile

- name: Create static binding with encap ID
  cisco.aci.aci_static_binding_to_epg:
    host: "{{ aci_host }}"
    username: "{{ aci_username }}"
    password: "{{ aci_password }}"
    validate_certs: false
    tenant: TNT1
    ap: "{{ epg.vrf }}_AP"
    epg: "{{ epg.name }}_{{ epg.vrf }}_EPG"
    encap_id: "{{ epg.vlan }}"
    deploy_immediacy: lazy
    interface_mode: trunk
    interface_type: vpc
    interface: "{{ vpc.iface }}"
    pod_id: "{{ vpc.pod }}"
    leafs: "{{ vpc.leaves }}"
    state: present #absent
  ignore_errors: true
  loop: "{{ vpcfile.list }}"
  loop_control:
    loop_var: vpc
  when:
    - userdata | intersect(vpc.iface)|length == 0 #intersect shows only matches

The add_vpc_subtask.yml writes the VPCs of an EPG in an array.

I had to use regexp to optimize the output of userdata by cutting away the last two characters regex_replace(']]$', '')].

add_vpc_subtask.yml

---
- ansible.builtin.set_fact:
    tmpvar: "{{ query_result['imdata'][item | int]['fvRsPathAtt']['attributes']['dn'].split('pathep-[')[1] }}"

- name: Create and Add items to dictionary #https://www.middlewareinventory.com/blog/ansible-dict/
  ansible.builtin.set_fact:
    userdata: "{{ userdata + [tmpvar | regex_replace(']]$', '')] }}"

Every file is in the same directory. When we issue the command ansible-playbook main.yml now the VPC will be successfully deployed on every EPG static port. I like to use the verbose mode of the command ansible-playbook main.yml -vvv to get the full json output of every task.


Thanks for reading my article. If you have any questions or recommendations you can message me via arvednetblog@gmail.com.