F5 and Cisco ACI Essentials: Automate automate automate !!!

This article will focus on automation support by BIG-IP and Cisco ACI and how automation tools specifically Ansible can be used to automate different use cases. Before getting into the weeds let's discuss and understand BIG-IP's and Cisco ACI's automation strategies.

BIG-IP automation strategy

BIG-IP automation strategy is simple-abstract as much complexity as possible from the user, give an easy button to the user to deploy their BIG-IP configuration. This could honestly mean different methods to different people, some prefer sending a single API call to perform one action( A one-to-one mapping between your API<->Configuration).

Others prefer a more declarative approach where one API call performs multiple actions, basically a one-to -many mapping between your API(1)<->Configuration(N). A great link to refresh and learn about the different options: https://www.f5.com/products/automation-and-orchestration

Cisco ACI automation strategy

Cisco Application Policy Infrastructure Controller (APIC) is the network controller for the ACI fabric. APIC is the unified point of automation and management for the Cisco ACI fabric, policy enforcement, and health monitoring. The Cisco ACI programmability model provides complete programmatic access using APIC. Click here to learn more https://developer.cisco.com/site/aci/

Automation tools

There are a lot of automation tools that are being talked for network automation BUT the one that comes up in every customer conversation is Ansible. Its simplicity, maturity and community adoption has made it very popular. In this article we are going to focus on using Ansible to automate a service discovery use case.

Use Case: Dynamic EP attach/detach

Let’s take an example of a simple http web service being made highly available and secure using the BIG-IP Virtual IP address. This web service has a bunch of backend web servers hosting the application, the IP of this web servers is configured on the BIG-IP as pool members. These same web server IP’s are learned as endpoints in the ACI fabric and are part of an End Point Group (EPG) on the APIC. Hence there is a logical mapping between a EPG on APIC and a pool on the BIG-IP.

Now if the application is adding or deleting web servers that is hosting the application maybe to save cost or maybe to deal with increase/decrease of traffic, what happens is that the web server IP will be automatically learned/unlearned on APIC. BUT an admin will still have to add/remove that web server IP from the pool on BIG-IP. This can be a burden on the network admin specially if this happens very often. Here is where automation can help and let’s look at how in the next section

More details on the use case can be found at https://devcentral.f5.com/s/articles/F5-Cisco-ACI-Essentials-Dynamic-pool-sizing-using-the-F5-ACI-ServiceCenter

Automation of Use Case: Dynamic EP attach/detach

Automation can be achieved by using Ansible and Ansible tower where API calls are made directly to the BIG-IP. Another option it to use the F5 ACI ServiceCenter (a native F5 ACI integration) to automate this particular use case.

Ansible and Ansible tower

To learn more about Ansible and Ansible tower: https://www.ansible.com/products/tower

Using this method of automation separate API calls are made directly to the ACI and the BIG-IP.

Sample playbook to perform the addition and deletion of pool members to a BIG-IP pool based on members in a particular EPG. The mapping of pool to EPG is provided as input to the playbook.

- name: Dynamic end point attach/dettach 
  hosts: aci
  connection: local
  gather_facts: false

  vars:
    epg_members: []
    pool_members: []
    pool_members_ip: []
    bigip_ip: 10.192.73.xx
    bigip_password: admin
    bigip_username: admin
    # Here we are mapping pool 'dynamic_pool' to EPG 'internalEPG' which belongs to APIC tenant 'TenantDemo'
    app_profile_name: AppProfile
    epg_name: internalEPG
    partition: Common
    pool_name: dynamic_pool
    pool_port: 80
    tenant_name: TenantDemo

  tasks:
  - name: Setup provider
    set_fact:
     provider:
      server: "{{bigip_ip}}"
      user: "{{bigip_username}}"
      password: "{{bigip_password}}"
      server_port: "443"
      validate_certs: "false"

  - name: Get end points learned from End Point group
    aci_rest:
      action: "get"
      uri: "/api/node/mo/uni/tn-{{tenant_name}}/ap-{{app_profile_name}}/epg-{{epg_name}}.json?query-target=subtree&target-subtree-class=fvIp"
      host: "{{inventory_hostname}}"
      username: "{{ lookup('env', 'ANSIBLE_NET_USERNAME') }}"
      password: "{{ lookup('env', 'ANSIBLE_NET_PASSWORD') }}"
      validate_certs: "false"
    register: eps
  
  - name: Get the IP's of the servers part of the EPG
    set_fact: 
     epg_members="{{epg_members + [item]}}"
    loop: "{{eps | json_query(query_string)}}"
    vars:
     query_string: "imdata[*].fvIp.attributes.addr"
    no_log: True

  - name: Get only the IPv4 IP's
    set_fact:
     epg_members="{{epg_members | ipv4}}"
     
  - name: Adding Pool members to the BIG-IP
    bigip_pool_member:
      provider: "{{provider}}"
      state: "present"
      name: "{{item}}"
      host: "{{item}}"
      port: "{{pool_port}}"
      pool: "{{pool_name}}"
      partition: "{{partition}}"
    loop: "{{epg_members}}"

  - name: Query BIG-IP facts
    bigip_device_facts:
      provider: "{{provider}}"
      gather_subset:
       - ltm-pools
    register: bigip_facts

  - name: "Show members belonging to pool {{pool_name}}"
    set_fact:
     pool_members="{{pool_members + [item]}}"
    loop: "{{bigip_facts.ltm_pools | json_query(query_string)}}"
    vars:
     query_string: "[?name=='{{pool_name}}'].members[*].name[]"

  - set_fact:
     pool_members_ip: "{{pool_members_ip + [item.split(':')[0]]}}"
    loop: "{{pool_members}}"

  - debug: "msg={{pool_members_ip}}"

  #If there are any membeers on the BIG-IP that are not present in the EPG,then delete them
  - name: Find the members to be deleted if any 
    set_fact:
     members_to_be_deleted: "{{ pool_members_ip | difference(epg_members) }}"

  - debug: "msg={{members_to_be_deleted}}"

  - name: Delete Pool members from the BIG-IP
    bigip_pool_member:
      provider: "{{provider}}"
      state: "absent"
      name: "{{item}}"
      port: "{{pool_port}}"
      pool: "{{pool_name}}"
      preserve_node: yes
      partition: "{{partition}}"
    loop: "{{members_to_be_deleted}}"

Ansible tower's scheduling feature can be used to schedule this playbook to be run every minute, every hour or once per day based on how often an application is expected to change and how important is it for the configuration on both the Cisco ACI and the BIG-IP to be in sync.

F5 ACI ServiceCenter

To learn more about the integration : https://www.f5.com/cisco

The F5 ACI ServiceCenter is installed on the APIC controller. Here automation can be used to create the initial EPG to Pool mapping. Once the mapping is created the F5 ACI ServiceCenter handles the dynamic sizing of pools based on events generated by APIC. Events are generated when a server is learned/unlearned on an EPG which is what the F5 ACI ServiceCenter listens to and accordingly adds or removes pool members from the BIG-IP.

Sample playbook to deploy the mapping configuration on the BIG-IP through the F5 ACI ServiceCenter

---
- name: Deploy EPG to Pool mapping
  hosts: localhost
  gather_facts: false
  connection: local

  vars:
   apic_ip: "10.192.73.xx"
   big_ip: "10.192.73.xx"
   partition: "Dynamic"

  tasks:

  - name: Login to APIC
    uri:
       url: https://{{apic_ip}}/api/aaaLogin.json
       method: POST
       validate_certs: no
       body_format: json
       body:
        aaaUser:
         attributes:
          name: "admin"
          pwd: "******"
       headers:
         content_type: "application/json"
       return_content: yes
    register: cookie

  - debug: msg="{{cookie['cookies']['APIC-cookie']}}"

  - set_fact:
     token: "{{cookie['cookies']['APIC-cookie']}}"

  - name: Login to BIG-IP
    uri:
      url: https://{{apic_ip}}/appcenter/F5Networks/F5ACIServiceCenter/loginbigip.json
      method: POST
      validate_certs: no
      body:
       url: "{{big_ip}}"
       user: "admin"
       password: "admin"
      body_format: json
      headers:
       DevCookie: "{{token}}"

  #The body of this request defines the mapping of Pool to EPG
  #Here we are mapping pool 'web_pool' to EPG 'internalEPG' which belongs to APIC tenant 'TenantDemo'
  - name: Deploy AS3 dynamic EP mapping
    uri:
       url: https://{{apic_ip}}/appcenter/F5Networks/F5ACIServiceCenter/updateas3data.json
       method: POST
       validate_certs: no
       body:
        url: "{{big_ip}}"
        partition: "{{partition}}"
        application: "DemoApp1"
        json:
         class: Application
         template: http
         serviceMain:
           class: Service_HTTP
           virtualAddresses:
           - 10.168.56.100
           pool: web_pool
         web_pool:
           class: Pool
           monitors:
           - http
           members:
           - servicePort: 80
             serverAddresses: []
           - addressDiscovery: event
             servicePort: 80
         constants:
           class: Constants
           serviceCenterEPG:
             web_pool:
               tenant: TenantDemo
               application: AppProfile
               epg: internalEPG
       body_format: json
       status_code:
       - 202
       - 200
       headers:
        DevCookie: "{{token}}"
       return_content: yes
    register: complete_info

  - name: Get task ID of above request
    set_fact:
     task_id: "{{ complete_info.json.message.taskId}}"
    when: complete_info.json.code == 202

  - name: Get deployment status
    uri:
      url: https://{{apic_ip}}/appcenter/F5Networks/F5ACIServiceCenter/getasynctaskresponse.json
      method: POST
      validate_certs: no
      body:
       taskId: "{{task_id}}"
      body_format: json
      headers:
       DevCookie: "{{token}}"
      return_content: yes
    register: result
    until: result.json.message.message != "in progress"
    retries: 5
    delay: 2
    when: task_id is defined

  - name: Display final result
    debug:
     var: result

After deploying this configuration, adding/deleting pool members and making sure the configuration is in sync is the responsibility of the F5 ACI ServiceCenter.

Takeaways

Both methods are highly effective and usable. The choice of which one to use comes down to the operational model in your environment. Some pros and cons to help made the decision on which platform to use for automation.

Ansible Tower

Pros

  • No dependency on any other tools
  • Fits in better with bigger company automation strategy to use Ansible for ALL network automation

Cons

  • Have to manage playbook execution and scheduling using Ansible Tower
  • If more logic is needed besides what’s described above playbooks will have to be written and maintained
  • Execution of playbook is based on scheduling and is not event driven

F5 ACI ServiceCenter

Pros

  • Only pool-epg mapping has to be deployed using automation, rest all is handled by the application
  • User interface to view pool member to EPG mapping once deployed and view discrepancies if any
  • Limited automation knowledge is needed, heavy lifting is being done by the application
  • Dynamically adding/deleting pool members is event driven, as members are learned/unlearned by the F5 ACI ServiceCenter an action is taken

Cons

  • Another tool is required
  • Customization of pool to EPG mapping is not present. Only one-to-one EPG to pool mapping is present.

References



Published Nov 20, 2020
Version 1.0
No CommentsBe the first to comment