Deploy Static Ports in ACI using Ansible
Use Ansible to automate repetitive tasks
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.
I also created 4 EPGS/BD and two VRFs.
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.