Configure Arista EOS with Ansible¶
eos_config
is a core module managed by Ansible network team. As this module is part of the core, there is no need to install additional Ansible module with ansible-galaxy
As eos_*
modules are part of core engine, we can use ansible options to run tests and capture configuration changes when running playbooks:
--check
option: When ansible-playbook is executed with--check
it will not make any changes on remote systems. Modules will report what changes they would have made rather than making them.--diff
option: When this flag is supplied and the module supports this, Ansible will report back the changes made or, if used with –check, the changes that would have been made.
These options are generally called dry-run mode.
Apply lines of configurations to devices.¶
Example playbooks: ‘pb.config.lines.simple.yaml’
Basic lines of configuration¶
To push lines of configuraiton to device, a small playbook should be like this:
---
- name: Run commands on remote LAB devices
hosts: all
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: Configure device hostname from lines
eos_config:
provider: "{{arista_credentials}}"
lines:
- "hostname MyHostname"
- "ntp server 1.1.1.1"
In this playbook, we use an authentication provider for ARISTA products as described in the home page
When applying this playbook, output is like below:
using--diff
option display changes applied by tasks
$ ansible-playbook pb.config.lines.simple.yaml --diff
PLAY [Run commands on remote LAB devices] ********
TASK [include_vars] ********
ok: [ceos1]
ok: [ceos2]
TASK [Configure device hostname from lines] ********
--- system:/running-config
+++ session:/********_1551450161-session-config
@@ -2,7 +2,9 @@
!
transceiver qsfp default-mode 4x10G
!
-hostname CEOS2
+hostname MyHostname
+!
+ntp server 1.1.1.1
!
spanning-tree mode mstp
!
changed: [ceos2]
--- system:/running-config
+++ session:/********_1551450161-session-config
@@ -2,7 +2,7 @@
!
transceiver qsfp default-mode 4x10G
!
-hostname CEOS1
+hostname MyHostname
!
ntp server 1.1.1.1
!
changed: [ceos1]
PLAY RECAP ********
ceos1 : ok=2 changed=1 unreachable=0 failed=0
ceos2 : ok=2 changed=1 unreachable=0 failed=0
Dynamic lines of configuration¶
Even if it is not the easiest way to play with, you can include Jinja2 variables in your configuration lines. These Jinja2 variables shall be defined previously in your host_vars
and / or group_vars
---
- name: Run commands on remote LAB devices
hosts: all
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: Configure device hostname from lines
eos_config:
provider: "{{arista_credentials}}"
lines:
- "hostname {{inventory_hostname}}-ansible"
- "ntp server 1.1.1.1"
Below is output of a change when running this specific playbooK with --diff
TASK [Configure device hostname from lines] ********
--- system:/running-config
+++ session:/********_1551450491-session-config
@@ -2,7 +2,7 @@
!
transceiver qsfp default-mode 4x10G
!
-hostname MyHostname
+hostname ceos2-automation
!
ntp server 1.1.1.1
!
Lines of configuration within a block¶
Assuming we want to configure an interface, we have to first enter to this block and then push configuration like this:
Arista interace configuration:
!
interface Ethernet 1
description My Wonderful description
!
To achieve this configuration with ansible module, syntax should be like this:
---
- name: Run commands on remote LAB devices
hosts: all
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: Configure interface description
eos_config:
provider: "{{arista_credentials}}"
lines:
- description My Wonderful description
parents: interface Ethernet 1
replace: block
With a --diff
, we can that description is applied to interface Ethernet 1
[...]
changed: [ceos1]
--- system:/running-config
+++ session:/********_1551451836-session-config
@@ -13,6 +13,7 @@
!
interface Ethernet1
+ description My Wonderful description
!
interface Ethernet2
!
[...]
PLAY RECAP ***
ceos1 : ok=4 changed=1 unreachable=0 failed=0
ceos2 : ok=4 changed=1 unreachable=0 failed=0
And the result is quite simple:
ceos1-automation#show interfaces description
Interface Status Protocol Description
Et1 up up My Wonderful description
Et2 up up
Apply configuration file to device¶
When playing with jinja2 templates, it is easier to generate a file and then push it to devices instead of applying line by line.
eos_config
support a mechanism to push a config files from your server to remote devices. This file can be either a plain text file or a JINJA2 template. In case of a template, rendering will be done first by ansible and then result will be applied on devices.
Apply a config file¶
To apply a plain text config, following playbook should be used:
---
- name: Run commands on remote LAB devices
hosts: all
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: Configure interface description
eos_config:
provider: "{{arista_credentials}}"
src: inputs/generic-config.cfg
Config file can be a complete Arista configuration or just a snippet of the configuration you want to update.
In this example, inputs/generic-config.cfg
has following content:
interface Ethernet2
description Description from generic configuration block
!
And running playbook pb.config.file.yaml
with --diff
option shows all changes:
$ ansible-playbook pb.config.file.yaml --diff
PLAY [Run commands on remote LAB devices] ********
TASK [include_vars] ********
ok: [ceos1]
ok: [ceos2]
TASK [Configure interface description] ********
--- system:/running-config
+++ session:/********_1551711841-session-config
@@ -13,6 +13,7 @@
interface Ethernet1
!
interface Ethernet2
+ description Description from generic configuration block
!
no ip routing
!
changed: [ceos2]
--- system:/running-config
+++ session:/********_1551711841-session-config
@@ -13,6 +13,7 @@
interface Ethernet1
!
interface Ethernet2
+ description Description from generic configuration block
!
no ip routing
!
changed: [ceos1]
PLAY RECAP ********
ceos1 : ok=2 changed=1 unreachable=0 failed=0
ceos2 : ok=2 changed=1 unreachable=0 failed=0
Apply a template¶
eos_config
also supports a JINJA2 template as an input file. In this scenario, ansible will run template rendering locally and then will push result to devices. It means that your configuration will have some content specific per device and / or collected in a previous task.
This section will not describe JINJA2 syntax. A specific page is available with some hints about jinja2 syntax and YAML structures.
Following template creates a basic SNMP configuration with generic fields. Only thing is chassis-id
will be set with inventory_hostname
defined in our inventory.ini
file.
snmp-server chassis-id {{inventory_hostname}}
snmp-server contact demo@acme.com
snmp-server location "cEOS Virtual lab"
Playbook is very close to playbook in Apply a config file
---
- name: Run commands on remote LAB devices
hosts: all
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: Configure SNMP information with template
eos_config:
provider: "{{arista_credentials}}"
src: "inputs/template-config.j2"
The main difference is src
field where you put a template file instead of a plan text configuration.
As you can see in extract below, content is built on a per device approach:
$ ansible-playbook pb.config.template.yaml --diff
PLAY [Run commands on remote LAB devices] ********
TASK [include_vars] ********
ok: [ceos1]
ok: [ceos2]
TASK [Configure SNMP information with template] ********
--- system:/running-config
+++ session:/********_1551713015-session-config
@@ -3,6 +3,10 @@
transceiver qsfp default-mode 4x10G
!
hostname ceos1
+!
+snmp-server chassis-id ceos1
+snmp- server contact demo@acme.com
+snmp-server location "cEOS Virtual lab"
!
spanning-tree mode mstp
!
changed: [ceos1]
--- system:/running-config
+++ session:/********_1551713015-session-config
@@ -3,6 +3,10 @@
transceiver qsfp default-mode 4x10G
!
hostname ceos2
+!
+snmp-server chassis-id ceos2
+snmp-server contact demo@acme.com
+snmp-server location "cEOS Virtual lab"
!
spanning-tree mode mstp
!
changed: [ceos2]
PLAY RECAP ********
ceos1 : ok=2 changed=1 unreachable=0 failed=0
ceos2 : ok=2 changed=1 unreachable=0 failed=0
Intended configuration approach¶
Pushing intended configuration is probably the best approach in an automation workflow: your device configuration does not deviate from your expectations as complete configuration is pushed by ansible.
To work in this approach, you need to build complete configuration using either a complete template or by assembling rendered templates. Once it is done, you can push and replace configuration with following syntax:
tasks:
- name: Load a config in an intended way
eos_config:
provider: "{{arista_credentials}}"
src: "{{ lookup('file', 'inputs/{{inventory_hostname}}-master.cfg') }}"
replace: 'config'
This approach can also be applied with template:
tasks:
- name: Intended configuration management
eos_config:
provider: "{{arista_credentials}}"
src: "device-configuration.j2"
replace: "config"
And finally, how to save config¶
eos_config
module can automatically save config to the startup_config. It provides 3 different options to do that. The save
action is started by either save or save_when keywords:
- save: automatically save the running-config to startup-config after any execution of the task.
- save_when: gives an option to select when ansible save running-config to startup-config:
always
: Equal to save keywordmodified
: The running-config will only be copied to the startup-config if it has changed since the last save to startup-configchanged
: (ansible >= 2.5) The running-config will only be copied to the startup-config if the task has made a changenever
: Well, running will never be copied to startup-config. Can be useful for validation purpose
So the last playbook should be like this one:
---
- name: Run commands on remote LAB devices
hosts: all
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: Configure SNMP information with template
eos_config:
provider: "{{arista_credentials}}"
src: "inputs/template-config.j2"
save_when: changed
Get diff between running and intended configuration¶
In cas we generate complete configuration, it is nice to capture the deviation between our target (generated configuration) and running configuration on devices.
So to do that, eos_config
has a special option named diff_against: intended
and then we defined what we named intended configuration.
---
- name: Run commands on remote LAB devices
hosts: ceos1
connection: local
gather_facts: no
pre_tasks:
- include_vars: "authentication.yaml"
tasks:
- name: diff the running config against a master config
eos_config:
provider: "{{arista_credentials}}"
diff_against: intended
intended_config: "{{ lookup('file', 'inputs/{{inventory_hostname}}-master.cfg') }}"
Output of the pb.config.intended.yaml playbook is the following:
$ ansible-playbook pb.configure.intended.yaml --check --diff
PLAY [Run commands on remote LAB devices] ********
TASK [include_vars] ********
ok: [ceos1]
TASK [diff the running config against a master config] ********
--- before
+++ after
@@ -1,16 +1,10 @@
transceiver qsfp default-mode 4x10G
-hostname ceos1
-snmp-server chassis-id ceos1
-snmp-server contact demo@acme.com
-snmp-server location "cEOS Virtual lab"
+hostname CEOS1-TEST
spanning-tree mode mstp
no aaa root
username ******** privilege 15 secret sha512 $6$j80NtRkV0CMlgXPS$a0.JbwuO1NMvIthS4eu6dEMHIV9gNGRRFf5SI6qNu5g4I3zxinnVrSMyj8EkQ1V/x7ORAWwe5CpYmgQME2jad1
interface Ethernet1
interface Ethernet2
- description My Wonderful description
- switchport trunk allowed vlan 12
- switchport mode trunk
no ip routing
management api http-commands
no shutdown
changed: [ceos1]
PLAY RECAP ********
ceos1 : ok=2 changed=1 unreachable=0 failed=0
As you can see, we have a complete view of the configuration deviation between running and intended.
Note: this module requires to be run with –check flag.