Ansible's Meraki Modules - Developing Playbooks

Introduction

Part 1 of this series gives a peek into the internal architecture of the Meraki modules in Ansible. Descriptions of the internals are interesting but they don’t explain how to write playbooks to configure Meraki environments.

For this example, we will create a combined network, add a switch, and configure a switch port on the switch.

All Meraki modules, except for the meraki_organization and meraki_config_template modules, are expected to be idempotent. In other words, if you run the same task twice, the end state should be identical on both executions and Meraki’s changed return parameter should show True for the first execution and False for the second. Note, the modules don’t currently return data when it’s not changed. This will be fixed in a future release.

Ansible Header

Meraki uses an HTTP based API for querying and configuring their infrastructure. Like any Ansible playbook, a header is needed.

- name: Test Meraki playbook
  connection: local
  hosts: localhost

All connections must be local since it’s the local system which executes the HTTP requests to the API. As of now, I haven’t written an Ansible connection plugin which would eliminate the need to specify local for all playbook connections. That may come in Ansible 2.9 or later so it’s on the roadmap but not an urgent need.

Tasks

Each Ansible task needs to reference an API key via the auth_key parameter. This must be specified for each task. If you don’t have an API key, login to the Meraki Dashboard, go to your organization preferences, and generate a key at the bottom. Meraki only allows for 2 API keys to exist at once. Common to most Ansible modules, the state parameter must say the type of action to be performed. Per Ansible standards, you can choose absent (delete), present (create or modify), or query.

Meraki has all objects assigned to a single organization. Both organizations, and networks, can be provided to an Ansible task via the *_name or *_id parameter. For example, an organization name is passed via org_name and a network ID is net_id.

Many modules will require a name parameter. In the case of meraki_network, this is the name of the network to be created. This example will assume the name is HQNetwork.

Each module has its own parameters it needs to execute properly. meraki_network must know its network type via the type parameter. Note, Ansible 2.6 and 2.7 take the parameter value of combined for a combined network. Ansible 2.8 will hopefully allow for more flexible combined networks. When the updated type parameter code is merged into a release, I will update this post. Meraki networks also have an optional timezone field.

This example will store the returned information about the newly created network in the hq_switch_network variable.

- name: Create combined network
  meraki_network:
		auth_key: abc123badc0ff33
		state: present
	  org_name: AcmeCorpOrg
	  name: HQNetwork
	  type: combined
	  timezone: Americas/Chicago
  register: hq_switch_network

Executing this task will create a network and return the following data.

...insert response data here...

Claiming a device into the network is going to follow a similar parameter structure. We will start with the following parameters:

- name: Add switch to network
  meraki_device:
    auth_key: abc123badc0ff33
    org_name: AcmeCorpOrg
    net_name: HQNetwork
    state: present

The only required parameter to claim a device into a network is the serial tag. name appears again, but within the meraki_device module, it sets the hostname for the device. However, there are other, optional parameters which can be passed. For example, if this switch needed a tag to identify it as a device within PCI scope, the tags parameter would be used. Finally, address assigns the device to a physical mailing address within the Meraki Dashboard.

- name: Add switch to network
  meraki_device:
    auth_key: abc123badc0ff33
    org_name: AcmeCorpOrg
    net_name: HQNetwork
    state: present
    serial: abc-123-def-456
    name: HQAccessSwitch01
    address: 123 Main St., Chicago, IL
    tags: pci
  register: add_switch

Tasks using the meraki_switchport module use the serial number of the device. meraki_switchport is interesting it doesn’t require the organization or network as a parameter since a serial number can only be tied to one network. This playbook will set ports 1-10 as access ports with a VLAN of 100. A voice VLAN of 200 must be configured on each of these ports. Each port has an optional description of “Employee Switchport”, configured via the name parameter.

- name: Add switch to network
  meraki_device:
    auth_key: abc123badc0ff33
		state: present
		serial: abc-123-def-456
		number: {item}
		name: Employee Switchport
		type: access
		vlan: 100
		voice_vlan: 200
	register: port_config
	loop: range(1,10)

Because the task needs to run on multiple ports, Ansible’s loop function is used on the last line. An explanation of the loop function is outside the scope of this post.

Meraki’s API doesn’t allow for multiple tasks to execute in a single call. This means the task needs to fully run for each port. In my experience, each API request takes approximately 1 second for a full request and response. Transparent to the playbook author, each module may make multiple calls. Assuming each task execution takes 2 seconds, Ansible will run for 20 seconds configuring the switch ports. This is idle time for the playbook author but is still a significant amount of time. Future enhancements to Meraki’s API combined with optimizations to Ansible’s Meraki modules will improve performance.

Conclusion

A common statement amongst network administrators is “I don’t want to be a developer”. Ansible playbooks use plenty of programming logic, especially when integrating Jinja 2 functions. But a lot of data in an Ansible-Meraki task should be understandable to someone comfortable with networks or the Meraki Dashboard. Furthermore, Ansible hides much of the complexity of Python (ex. dictionaries, HTTP packages) which would be mandatory knowledge if an administrator were to write their own automation tool. Ansible’s Meraki modules are meant to be a simple, but flexible, tool in a network administrator’s tool chest for automating their environment.