While it is possible to write a playbook in one file as we've done throughout this workshop, eventually you’ll want to reuse files and start to organize things.
Ansible Roles is the way we do this. When you create a role, you deconstruct your playbook into parts and those parts sit in a directory structure.
For this exercise, you are going to take the playbook you just wrote and refactor it into a role. In addition, you'll learn to use Ansible Galaxy.
Ansible Galaxy is a free site for finding, downloading, and sharing roles. It's also pretty handy for creating them which is what we are about to do here.
Navigate to the roles
directory in the project.
Note: In a previous exercise, we specified in
ansible.cfg
that roles should be at the level of the main project instead of at the level of the playbook, which is the default.
cd roles
Use the ansible-galaxy
command to initialize a new role called ios-ntp
.
ansible-galaxy init ios-ntp
Take a look around the structure you just created. Here are a few commonly used directories:
- The Role entry point is
roles/ios-ntp/tasks/main.yml
- Default variables to your role in
roles/ios-ntp/defaults/main.yml
- Role-specific variables to your role in
roles/ios-ntp/vars/main.yml
- Role handlers in
roles/ios-ntp/handlers/main.yml
In this section, we will separate out the major parts of your playbook including vars:
, tasks:
, template:
, and handlers:
.
cd ..
cp ntp-restconf2.yml roles/ios-ntp/tasks/main.yml
Now edit roles/ios-ntp/tasks/main.yml
to remove the play definition and reduce the indentation:
- name: GET THE NTP LIST SERVERS
uri:
url: "https://{{ hostvars[inventory_hostname].ansible_host }}:443/restconf/data/Cisco-IOS-XE-native:native/Cisco-IOS-XE-native:ntp/Cisco-IOS-XE-ntp:server"
user: admin
password: admin
method: GET
return_content: yes
headers:
Accept: 'application/yang-data+json'
validate_certs: no
register: results
- set_fact:
actual_ntp_servers: "{{ results.json['Cisco-IOS-XE-ntp:server']['server-list'] | map(attribute='ip-address') | list }}"
desired_ntp_servers: "{{ ntp_server_list | map(attribute='ip-address') | list }}"
- debug:
msg: "{{ actual_ntp_servers | difference(desired_ntp_servers) }}"
- name: SET THE NTP SERVERS
uri:
url: "https://{{ hostvars[inventory_hostname].ansible_host }}:443/restconf/data/Cisco-IOS-XE-native:native/Cisco-IOS-XE-native:ntp/Cisco-IOS-XE-ntp:server"
user: admin
password: admin
method: PUT
return_content: yes
headers:
Content-Type: 'application/yang-data+json'
Accept: 'application/yang-data+json, application/yang-data.errors+json'
body_format: json
body:
server:
server-list: "{{ ntp_server_list }}"
validate_certs: no
status_code: [200, 204]
register: results
changed_when: yes
when: actual_ntp_servers != desired_ntp_servers
We are going to put the default variables into roles/ios-ntp/defaults/main.yml
so they can be overridden by either passing
in vars with the role or with host_vars/group_vars:
# defaults file for ios-ntp
ntp_server_list:
- { ip-address: 192.5.41.40 }
- { ip-address: 192.5.41.41 }
Note: The following variable precedence:
- vars directory
- defaults directory
- group_vars directory
- In the playbook under the
vars:
section- In any file which can be specified on the command line using the
--extra_vars
option- On a boat, in a moat, with a goat (disclaimer: this is a complete lie)
Refer to variable precedence to understand both where to define variables and which locations take precedence. In this exercise, we are using role defaults to define a couple of variables and these are the most malleable.
Now let's change the original playbook to call the role:
- name: CONFIGURE ROUTERS
hosts: routers
connection: local
gather_facts: no
tasks:
- include_role:
name: ios-ntp
Note: We are using
include_role
to call the role instead of the more traditional practice of calling roles in theroles:
section of the play. It is the opinion of the author that this function-like approach makes it easier to intersperse roles with other logic, making it more conducive to the more complex task of network automation.
Run the playbook.
ansible-playbook ntp-role.yml
If successful, your standard output should look similar to the previous, but with tasks prepended with the role name:
$ ansible-playbook ntp-role.yml
PLAY [CONFIGURE ROUTERS] ***********************************************************************************************************************
TASK [include_role : ios-ntp] ******************************************************************************************************************
TASK [ios-ntp : GET THE NTP LIST SERVERS] ******************************************************************************************************
ok: [sp1]
ok: [core]
ok: [hq]
ok: [internet]
TASK [ios-ntp : set_fact] **********************************************************************************************************************
ok: [core]
ok: [sp1]
ok: [hq]
ok: [internet]
TASK [ios-ntp : debug] *************************************************************************************************************************
ok: [core] => {
"msg": []
}
ok: [sp1] => {
"msg": []
}
ok: [hq] => {
"msg": []
}
ok: [internet] => {
"msg": []
}
TASK [ios-ntp : SET THE NTP SERVERS] ***********************************************************************************************************
skipping: [core]
skipping: [sp1]
skipping: [hq]
skipping: [internet]
PLAY RECAP *************************************************************************************************************************************
core : ok=3 changed=0 unreachable=0 failed=0
hq : ok=3 changed=0 unreachable=0 failed=0
internet : ok=3 changed=0 unreachable=0 failed=0
sp1 : ok=3 changed=0 unreachable=0 failed=0
Now, let try to pass in variables to override the default:
- name: CONFIGURE ROUTERS
hosts: routers
connection: local
gather_facts: no
tasks:
- include_role:
name: ios-ntp
vars:
ntp_server_list:
- { ip-address: 192.5.41.40 }
- { ip-address: 192.5.41.43 }
Since we changed the NTP servers from the default, we should see a change from the idempotency we added earlier:
$ ansible-playbook ntp-role.yml
PLAY [CONFIGURE ROUTERS] ***********************************************************************************************************************
TASK [include_role : ios-ntp] ******************************************************************************************************************
TASK [ios-ntp : GET THE NTP LIST SERVERS] ******************************************************************************************************
ok: [hq]
ok: [core]
ok: [internet]
ok: [sp1]
TASK [ios-ntp : set_fact] **********************************************************************************************************************
ok: [core]
ok: [sp1]
ok: [hq]
ok: [internet]
TASK [ios-ntp : debug] *************************************************************************************************************************
ok: [core] => {
"msg": [
"192.5.41.41"
]
}
ok: [sp1] => {
"msg": [
"192.5.41.41"
]
}
ok: [hq] => {
"msg": [
"192.5.41.41"
]
}
ok: [internet] => {
"msg": [
"192.5.41.41"
]
}
TASK [ios-ntp : SET THE NTP SERVERS] ***********************************************************************************************************
changed: [core]
changed: [sp1]
changed: [hq]
changed: [internet]
PLAY RECAP *************************************************************************************************************************************
core : ok=4 changed=1 unreachable=0 failed=0
hq : ok=4 changed=1 unreachable=0 failed=0
internet : ok=4 changed=1 unreachable=0 failed=0
sp1 : ok=4 changed=1 unreachable=0 failed=0
You have completed lab exercise 6.5
Click Here to return to the Viptela Networking Automation Workshop