Ansible
Config

YAML

Under the majority of the role directories you'll notice a ".yml" file. Playbooks are written in a very simple markup language called YAML, which stands for Yet Another Markup Language. YAML is used as it's even easier to read than data structure formats such as XML or JSON.

YAML files optionally begin with --- at the top of the file to signify the start of the file. Following the file start, comes the Ansible modules written in YAML syntax. YAML syntax for Ansible modules are expressed as a list of key/value pairs. Below you can see an example of YAML syntax that contains a list of dictionaries and where the dictionaries contain lists:


- name: CREATE ACI TENANT
  cisco.aci.aci_tenant:
    tenant: "My_Tenant"
    descr: "This Tenant is for testing only"
    host: "x.x.x.x"
    username: "admin"
    password: "superpass"
    validate_certs: false

As you can see the first thing, we are doing is to introduce you is to an specific ansible module. In this case the aci_tenant is an ansible module. There are many ansible modules available and more added with each release. Keep the reference to the ACI documentation for Ansible saved. Also the link for modules is available. Just click on the link and then click on content button.

Ansible Variables

An important key to any programing language are variables and Ansible is no different. If you would have had to create 100 tenants in an ACI fabric, you dont want to have to create 100 different YAML files with the configuration that we showed above. That makes no sense.

Ansible allows the placement of variables in the YAML file via what we know as templates. This template system is called Jinja Templates and is used in many aspects of Python, the core base of Ansible. This is how the syntax would be like for the example above:



- name: CREATE ACI TENANT
  cisco.aci.aci_tenant:
    tenant: "{{ tenant_name }}"
    descr: "{{ descr }}"
    host: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    validate_certs: false


Variables can be defined in various locations and Ansible has a precedence system for understanding what and when a variable would be overridden if used in more than one location. The precedence for a variable can be seen below. As an example, a variable in the role defaults directory would be overridden by a variable in the playbook global_vars/all directory and file. Further, both of these are overridden by the local vars directory within the specific role, role vars.

Note

We will be showing you a capability called module_defaults that will allow us to configure the authentication and connection elements needed for each module in a central location to simplify the structure of the tasks.

Step 1 - Create group_vars Variable File

You are now going to create a new file in the group_vars directory under the playbook/aci directory. You will be doing this in the Visual Studio Code (VSC) editor. Right click on the editor left pane where the group_vars directory is and then click on New File to create the all.yml file in group_vars and populate the contents of the file for the ansible_connection, username, password, and protocol to be used in the ACI tasks. group_vars/all is where you place universal variables that apply for all devices.

This new file will be called all.yml

The ansible_connection variable is used to define the connection type to the device. For this lab, you will be using the local connection type, which means that Ansible will be executing the tasks locally on the device where Ansible is installed.


---
ansible_connection: local
username: aciproglab04
password: cisco.123

Step 2 - Create host_vars Variable File

The device specific variables can be defined under the host_vars directory for each device.

Note

For this lab you are going to be leveraging a specific user that has write permissions for a specific tenant. For this reason we have created the Tenant for you. The ACI Tenant provides a user space domain for creating network elements and is controlled via RBAC.

You are now going to create a new file in the host_vars directory under the playbook/aci directory. Like before, you will do this in the Visual Studio Code (VSC) editor. Right click on the editor left pane where the host_vars directory is and then click on New File to create the apic.yml file in host_vars and populate the contents of the file with the data that will be used in your Ansible tasks that will be defined next. host_vars/apic.yml is where you place variables that apply to your intended configuration state. If you had variable data that is the for your tasks no matter what, then you could define that directly in your roles/vars/main.yml.

Again, this new file will be called apic.yml

Inset the variables for your tenant, VRFs, and application profile after the # vars file for apic comment:


---
tenant: aciproglab04
vrf1: POD04_vrf_1
vrf2: POD04_vrf_2 
app_profile_name: POD04_APP

Ansible Tasks

The Ansible documentation for each network module provides a synopsis of what function the module performs and a table of parameters or keys. The tabulated parameters inform the user which parameters are required for the module to function as a task, which parameters are optional, and what the defaults are for parameters. There are many network modules that exist to configure Tenants, VRFs, BDs, APs, EPGs, Contracts, etc. Some of the modules that are available and the ones you will use today are the following:

  • aci_vrf
  • aci_bd
  • aci_ap
  • aci_epg

Cisco is commited to Ansible and continues to expand the library with new modules in the pursuit of having 100% correlation between the module and ACI capabilities. In a place where an Ansible module is not available, Cisco has developed a specific module that allows you to send specific ACI configuration objects into the fabric via the REST interface called aci_rest.

Step 3 - Create VRF and Bridge Domains tasks

In the editor find the file main.yml under the roles/apic/tasks directory and open it by double-clicking on it. You will be adding the following Ansible tasks using the beforementioned modules in YAML format after the # tasks file for apic comment. Pay attention to the line numbers as they should match with your editor.


- name: CREATE ACI TENANT VRF1
  cisco.aci.aci_vrf: 
    vrf: "{{ vrf1 }}"
    state: present
    tenant: "{{ tenant }}" 

- name: CREATE ACI TENANT VRF2
  cisco.aci.aci_vrf:
    vrf: "{{ vrf2 }}"
    state: present
    tenant: "{{ tenant }}" 

- name: CREATE BRIDGE DOMAIN FOR WEB
  cisco.aci.aci_bd:
    bd: "web"
    description: 'POD04 Web front end Bridge Domain'
    state: present
    vrf: "{{ vrf1 }}"
    tenant: "{{ tenant }}" 

- name: CREATE SUBNET FOR DB WEB
  cisco.aci.aci_bd_subnet:
    bd: "web"
    subnet_name: "POD04_web_subnet"
    description: 'POD04 Subnet for Web front end'
    gateway: "10.100.4.1"
    mask: 24
    scope: private
    state: present
    tenant: "{{ tenant }}" 

- name: CREATE BRIDGE DOMAIN FOR DB
  cisco.aci.aci_bd:
    bd: "database"
    description: 'POD04 Database Bridge Domain'
    state: present
    vrf: "{{ vrf1 }}"
    tenant: "{{ tenant }}" 

- name: CREATE SUBNET FOR DB BRIDGE DOMAIN
  cisco.aci.aci_bd_subnet:
    bd: "database"
    subnet_name: "POD04_db_subnet"
    description: 'POD04 Subnet for Database Bridge Domain'
    gateway: "10.100.104.1"
    mask: 24
    scope: private
    state: present
    tenant: "{{ tenant }}" 

Step 4 - Create application profile and EPG taks

In the editor, under the same file you will be adding the following modules.


- name: CREATE ACI TENANT APPLICATION PROFILE
  cisco.aci.aci_ap:
    ap: "POD04_APP"
    description: 'POD04 Application Profile'
    state: present
    tenant: "{{ tenant }}" 

- name: CREATE DATABASE EPG
  cisco.aci.aci_epg:
    ap: "POD04_APP"
    bd: "web"
    epg: "web"
    description: 'POD04 WEB EPG'
    state: present
    tenant: "{{ tenant }}" 

- name: CREATE DATABASE EPG
  cisco.aci.aci_epg:
    ap: "POD04_APP"
    bd: "database"
    epg: "database"
    description: 'POD04 Database EPG'
    state: present
    tenant: "{{ tenant }}" 

Ansible Host Files

Ansible refers to its host file as an inventory file. The inventory file has a default location in /etc/ansible/hosts, but can also be specified directly within a playbook locally and used with the -i hosts.yml option, where hosts happens to be in the inventory file name. Within the inventory file, you can simply list all the devices/hosts or make use of group names using brackets which classifies devices you are controlling at what times and for what purpose.

Step 5 - Create Ansible Host File

The host file will be created in the location ~/ltrdcn-3225/ansible/playbooks/aci. Please goto this location and create the file hosts.yml.


# hosts file for Ansible playbook
---
all:
  children:
    aci:
      hosts:
        apic:
          ansible_host: 10.0.226.41

Main Playbook

As previously mentioned, Ansible calls its configuration and orchestration framework "playbooks" and is a collections of "play(s)" or tasks for configuration management and deployment to a device or multiple devices. While playbooks can be represented as a single file, Ansible best practices recommend a particular directory structure for playbooks that you built using roles for better organization and reuse. You built all of this over the last three sections. You now need to build the main playbook file, which would look like the below:

The below playbook file you will use for this lab designates the following behaviors, for each role ‘x’:

  • If roles/x/tasks/main.yml exists, tasks listed therein will be added to the play
  • If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play
  • If roles/x/vars/main.yml exists, variables listed therein will be added to the play
  • If roles/x/defaults/main.yml exists, variables listed therein will be added to the play
  • If roles/x/meta/main.yml exists, any role dependencies listed therein will be added to the list of roles (1.3 and later)
  • Any copy, script, template or include tasks (in the role) can reference files in roles/x/{files,templates,tasks}/ (dir depends on task) without having to path them relatively or absolutely

Ansible module_defaults

Ansible allows you to define default values for modules in the playbooks. This is done by defining a module_defaults section in the playbook. The module_defaults section is a dictionary that contains key/value pairs for the default values of the modules. Cisco has introduced in latest versions of Ansible the capability to define the default values for the ACI modules.

This capability simplifies the playbook structure and makes it more readable since it avoids the repetition in the definition of the variables for each module. Here we will define the default values needed to authenticate to the APIC, for which Ansible will pass these defaults to each task that under the roles.

Step 6 - Create main playbook

The host file will be created in the location ~/ltrdcn-3225/ansible/playbooks/aci. Please goto this location and create the file site.yml and add the following content.


---
# main playbook
- name: APIC Tenant Configuration playbook
  hosts: apic
  gather_facts: false
  module_defaults:
    group/cisco.aci.all:
      hostname: "{{ansible_host}}"
      username: "{{ username }}"
      password: "{{ password }}"
      validate_certs: false
      use_ssl: true
  roles:
    - role: apic

Now we can proceed to execute the ansible playbooks.