Creating Ansible Role#

As we learned about the role directory structure, the next step is to create the structure of the role, populate it with the necessary data (such as variables and tasks), create a playbook to use the role, and ensure the role is portable and sharable without hardcoding your credentials.

Creating the Role Structure#

First, let’s create the role directory structure using the ansible-galaxy init command. This command sets up the necessary directories and files for a new role.

(.venv)   ansible-cbt-lab git:(main) ansible-galaxy init ospf_role
- Role ospf_role was created successfully

Populating the Role#

We will convert the following playbook into an Ansible role:

Original Playbook#

---
- name: "PLAYBOOK - OSPF CONFIGURATION"
  hosts: 172.16.10.14
  gather_facts: false

  tasks:
    - name: "TASK 1 - CONFIG OSPF"
      cisco.ios.ios_config:
        src: "ospf.j2"

    - name: "TASK 2 - SHOW OSPF CONFIG"
      cisco.ios.ios_command:
        commands:
          - show run | sec ospf
      register: ospf_config

    - name: "TASK 3 - PRINT OSPF CONFIG"
      ansible.builtin.debug:
        msg: "{{ ospf_config.stdout_lines }}"

Variables for 172.16.10.14#

ospf:
  process_id: 10
  router_id: 1.1.1.1
  networks:
    - network: 9.9.9.8
      mask: 0.0.0.3
    - network: 192.168.71.0
      mask: 0.0.0.255

Jinja2 Template ospf.j2#

router ospf {{ ospf.process_id }}
  router-id {{ ospf.router_id }}
  {% for network in ospf.networks %}
  network {{ network.network }} {{ network.mask }} area 0
  {% if ospf.router_id == '1.1.1.1' %}
  default-information originate
  {% endif %}
  {% endfor %}

Creating the Role#

With the role directory structure created, we will now populate it with the necessary tasks, templates, and variables.

Tasks#

Copy the tasks from your playbook to tasks/main.yml:

---
# tasks file for ospf_role

- name: "TASK 1 - {{ TASK_ONE_NAME }}"
  cisco.ios.ios_config:
    src: "{{ ospf_template }}"

- name: "TASK 2 - {{ TASK_TWO_NAME }}"
  cisco.ios.ios_command:
    commands:
      - show run | sec ospf
  register: ospf_config

- name: "TASK 3 - {{ TASK_THREE_NAME }}"
  ansible.builtin.debug:
    msg: "{{ ospf_config.stdout_lines }}"

Note the use of generic task names and the removal of redundant tasks keywords.

Templates#

Copy the Jinja2 ospf.j2 template to the role’s templates directory:

router ospf {{ ospf.process_id }}
  router-id {{ ospf.router_id }}
  {% for network in ospf.networks %}
  network {{ network.network }} {{ network.mask }} area 0
  {% if ospf.router_id == '1.1.1.1' %}
  default-information originate
  {% endif %}
  {% endfor %}

Variables#

Populate your variables into defaults/main.yml:

---
# defaults file for ospf_role
TASK_ONE_NAME: "OSPF CONFIGURATION"
TASK_TWO_NAME: "SHOW OSPF CONFIG"
TASK_THREE_NAME: "PRINT OSPF CONFIG"

ospf_template: "ospf.j2"

Creating the Playbook to Run the Role#

Now, create a playbook to utilize the role:

---
- name: "PLAYBOOK - OSPF CONFIGURATION"
  hosts: 172.16.10.14
  gather_facts: false

  roles:
    - ospf_role

Running the Playbook#

Execute the playbook to apply the OSPF configuration:

(.venv)   ansible-cbt-lab git:(main)  ansible-playbook ospf_role.yml

PLAY [PLAYBOOK - OSPF CONFIGURATION] ***************************************************

TASK [ospf_role : TASK 1 - OSPF CONFIGURATION] ****************************************************************************************
changed: [172.16.10.14]

TASK [ospf_role : TASK 2 - SHOW OSPF CONFIG] *******************************************
ok: [172.16.10.14]

TASK [ospf_role : TASK 3 - PRINT OSPF CONFIG] ******************************************
ok: [172.16.10.14] => {
    "msg": [
        [
            "router ospf 10",
            " router-id 1.1.1.1",
            " log-adjacency-changes",
            " network 9.9.9.8 0.0.0.3 area 0",
            " network 192.168.71.0 0.0.0.255 area 0",
            " default-information originate"
        ]
    ]
}

PLAY RECAP *****************************************************************************
172.16.10.14               : ok=3    changed=1    unreachable=0    failed=0    skipped=0

Conclusion#

By following these steps, you can create an Ansible role, making your automation tasks modular, reusable, and easily shareable. Remember to avoid hardcoding credentials to ensure the role’s portability and security.