├── .gitignore ├── README.md ├── bugs.yml ├── daily_report.yaml ├── default.yaml ├── filter_plugins └── utils.py ├── group_vars ├── all ├── leaf └── spine ├── host_vars ├── dc1-spine1 ├── dc1-spine2 ├── dc1-tora └── dc1-torb ├── hosts ├── leaf.yaml ├── newroles.txt ├── ops.yaml ├── roles ├── bug_scrub │ ├── tasks │ │ ├── BUG_172152.yaml │ │ └── main.yml │ └── vars │ │ └── main.yml ├── ops │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── vars │ │ └── main.yml ├── reset │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── vars │ │ └── main.yml ├── upgrade │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── vars │ │ └── main.yml └── validate │ ├── README.md │ ├── defaults │ └── main.yml │ ├── handlers │ └── main.yml │ ├── meta │ └── main.yml │ ├── tasks │ └── main.yml │ └── vars │ └── main.yml ├── run_commands.yaml ├── send_probe.yaml ├── site.yaml ├── spine.yaml ├── upgrade.yaml ├── validate.yaml ├── vlans_only.yaml └── vmtracer.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | *.pyc 3 | *.DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sample BGP/MLAG/Varp Playbook 2 | 3 | 1) Install the needed roles by creating a text file: 4 | 5 | ``` 6 | # roles.txt 7 | arista.eos-bgp 8 | arista.eos-bridging 9 | arista.eos-interfaces 10 | arista.eos-ipv4 11 | arista.eos-mlag 12 | arista.eos-route-control 13 | arista.eos-system 14 | arista.eos-virtual-router 15 | arista.eos-vxlan 16 | ``` 17 | 18 | ``` 19 | sudo ansible-galaxy install -r roles.txt 20 | ``` 21 | The above command will install the need roles required to run the play book. 22 | 23 | 2) The playbook can be executed by running: 24 | 25 | ``` 26 | ansible-playbook -i hosts site.yml 27 | ``` 28 | 29 | The ```site.yml``` playbook is divided into to two child playbooks ```spine.yml``` and ```leaf.yml```. As their name implies ```spine.yml``` will run against hosts in the spine group and ```leaf.yml``` will run against hosts in the leaf group. 30 | 31 | To feed the correct IP addresses/username/acls into the play change the requiste host_var or group_var file to meet your needs. 32 | 33 | For example if my host file looks like this: 34 | 35 | ``` 36 | [leaf] 37 | dc1-tora 38 | dc1-torb 39 | 40 | [spine] 41 | dc1-spine1 42 | dc1-spine2 43 | ``` 44 | 45 | If I needed to change the IP address that will be configued on dc1-spine1 I would edit the ```host_var/dc1-spine1``` file. 46 | -------------------------------------------------------------------------------- /bugs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: webinar_lab 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - bug_scrub 8 | -------------------------------------------------------------------------------- /daily_report.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: "{{ run_hosts | mandatory }}" 3 | gather_facts: no 4 | connection: local 5 | 6 | tasks: 7 | - name: Gather System Status 8 | eos_command: 9 | commands: 10 | - command: 'show logging alerts last 25 hours' 11 | output: 'text' 12 | - command: 'show interfaces counters discards' 13 | output: 'json' 14 | - command: 'show interfaces counters discards | nz' 15 | output: 'text' 16 | provider: '{{ provider }}' 17 | register: status 18 | 19 | - name: Check for Alerts 20 | assert: 21 | that: 22 | - "status['stdout'][0] == ''" 23 | msg: "Alerts were found {{ status['stdout'][0] }}" 24 | 25 | - name: Check for Discards 26 | assert: 27 | that: 28 | - "status['stdout'][1]['inDiscardsTotal'] == 0" 29 | - "status['stdout'][1]['outDiscardsTotal'] == 0" 30 | msg: "Interface discards found. In {{ status['stdout'][1]['inDiscardsTotal'] }}, Out {{ status['stdout'][1]['outDiscardsTotal'] }}" 31 | -------------------------------------------------------------------------------- /default.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - { role: reset } 8 | - { role: upgrade, target_version: '4.16.7M' } 9 | -------------------------------------------------------------------------------- /filter_plugins/utils.py: -------------------------------------------------------------------------------- 1 | from ansible import errors 2 | import re 3 | 4 | 5 | def split_lines(value): 6 | return [s.strip() for s in value.splitlines()] 7 | 8 | 9 | def filter_vms(value, id): 10 | output = [] 11 | for vm in value['vms']: 12 | vlan = re.sub(r'[v|V]lan', '', id) 13 | if vm['vlan'] == vlan: 14 | output.append(vm) 15 | return output 16 | 17 | 18 | def format_commands(value, encoding='json'): 19 | commands = split_lines(value) 20 | formatted = list() 21 | for cmd in commands: 22 | formatted.append(dict(command=cmd, output=encoding)) 23 | return formatted 24 | 25 | 26 | def format_stdout(value, input_commands): 27 | output = list() 28 | for i, result in enumerate(value): 29 | cmd = '* Command: %s' % input_commands[i]['command'] 30 | output.append('*' * len(cmd)) 31 | output.append(cmd) 32 | output.append('*' * len(cmd)) 33 | for res in result.splitlines(): 34 | output.append(res) 35 | return output 36 | 37 | 38 | def get_packet_loss(value): 39 | print value 40 | loss = re.search(r'(\d+)%\s+packet\sloss', value, re.M) 41 | if loss: 42 | return loss.group(1) 43 | else: 44 | return 100 45 | 46 | 47 | class FilterModule(object): 48 | def filters(self): 49 | return { 50 | 'split_lines': split_lines, 51 | 'format_commands': format_commands, 52 | 'format_stdout': format_stdout, 53 | 'packet_loss': get_packet_loss, 54 | 'filter_vms': filter_vms, 55 | } 56 | -------------------------------------------------------------------------------- /group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | # make ansible play nice in a virtualenv 3 | # ansible_python_interpreter: python 4 | 5 | # Connection to the devices 6 | provider: 7 | host: '{{ ansible_host }}' 8 | username: admin 9 | password: 10 | authorize: true 11 | use_ssl: yes 12 | transport: eapi 13 | validate_certs: false 14 | 15 | pause_sec: 5 16 | 17 | # TFTP Server 18 | tftp_srv: 'tftp:172.16.130.200' 19 | config_dir: '/configs/' 20 | base_config: 'flash:config.default' 21 | 22 | # Upgrade related vars 23 | target_version: 4.16.7M 24 | swi_url: "flash:EOS-{{ target_version }}.swi" 25 | swi_dest: "flash:" 26 | install_pause: 90 27 | 28 | eos_debug: true 29 | 30 | eos_users: 31 | - name: simplebob 32 | nopassword: true 33 | privilege: 0 34 | role: network-operator 35 | -------------------------------------------------------------------------------- /group_vars/leaf: -------------------------------------------------------------------------------- 1 | --- 2 | eos_purge_vlans: no 3 | eos_ip_routing_enabled: yes 4 | 5 | # Connection to the devices 6 | provider: 7 | host: '{{ ansible_host }}' 8 | username: admin 9 | password: admin 10 | authorize: true 11 | use_ssl: no 12 | transport: eapi 13 | validate_certs: false 14 | -------------------------------------------------------------------------------- /group_vars/spine: -------------------------------------------------------------------------------- 1 | --- 2 | eos_purge_vlans: no 3 | eos_ip_routing_enabled: yes 4 | 5 | # Connection to the devices 6 | provider: 7 | host: '{{ ansible_host }}' 8 | username: admin 9 | password: admin 10 | authorize: true 11 | use_ssl: no 12 | transport: eapi 13 | validate_certs: false 14 | -------------------------------------------------------------------------------- /host_vars/dc1-spine1: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: dc1-spine1 3 | 4 | eos_host_ip: 172.16.130.201 5 | 6 | vlans: 7 | - vlanid: 1 8 | name: default 9 | - vlanid: 2 10 | name: production 11 | 12 | interfaces: 13 | - name: Loopback0 14 | enable: true 15 | - name: Loopback1 16 | enable: true 17 | - name: Ethernet1 18 | description: '[BGP]Connection to Leaf1' 19 | enable: true 20 | - name: Ethernet2 21 | description: '[BGP]Connection to Leaf2' 22 | enable: true 23 | 24 | ip_interfaces: 25 | - name: Loopback0 26 | address: 1.1.1.1/32 27 | - name: Loopback1 28 | address: 2.2.2.1/32 29 | - name: Ethernet1 30 | address: 10.1.1.0/31 31 | - name: Ethernet2 32 | address: 10.1.1.2/31 33 | 34 | 35 | acls: 36 | - name: ACL-1 37 | action: permit 38 | seqno: 50 39 | description: My wonderful acl 40 | type: standard 41 | srcaddr: 10.10.10.10 42 | srcprefixlen: 32 43 | 44 | ipv4_static_routes: 45 | - ip_dest: 0.0.0.0/0 46 | next_hop: Management1 47 | next_hop_ip: 172.16.130.2 48 | route_name: Default 49 | tag: 100 50 | 51 | 52 | bgp: 53 | enable: true 54 | bgp_as: 65001 55 | redistribute: 56 | - connected 57 | log_neighbor_changes: yes 58 | timers: 59 | keep_alive: 1 60 | hold: 3 61 | neighbors: 62 | - name: 10.1.1.1 63 | remote_as: 65002 64 | peer_group: demoleaf 65 | enable: true 66 | - name: 10.1.1.3 67 | remote_as: 65002 68 | peer_group: demoleaf 69 | enable: true 70 | -------------------------------------------------------------------------------- /host_vars/dc1-spine2: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: dc1-spine2 3 | 4 | eos_host_ip: 172.16.130.202 5 | 6 | vlans: 7 | - vlanid: 1 8 | name: default 9 | - vlanid: 2 10 | name: production 11 | 12 | interfaces: 13 | - name: Loopback0 14 | enable: true 15 | - name: Loopback1 16 | enable: true 17 | - name: Ethernet1 18 | description: "[BGP]Connection to Leaf1" 19 | enable: true 20 | - name: Ethernet2 21 | description: "[BGP]Connection to Leaf2" 22 | enable: true 23 | 24 | ip_interfaces: 25 | - name: Loopback0 26 | address: 1.1.1.2/32 27 | - name: Loopback1 28 | address: 2.2.2.2/32 29 | - name: Ethernet1 30 | address: 10.1.2.0/31 31 | - name: Ethernet2 32 | address: 10.1.2.2/31 33 | 34 | 35 | acls: 36 | - name: ACL-1 37 | action: permit 38 | seqno: 50 39 | description: My wonderful acl 40 | type: standard 41 | srcaddr: 10.10.10.10 42 | srcprefixlen: 32 43 | 44 | ipv4_static_routes: 45 | - ip_dest: 0.0.0.0/0 46 | next_hop: Management1 47 | next_hop_ip: 172.16.130.2 48 | route_name: Default 49 | tag: 100 50 | 51 | bgp: 52 | enable: true 53 | bgp_as: 65001 54 | redistribute: 55 | - connected 56 | log_neighbor_changes: yes 57 | timers: 58 | keep_alive: 1 59 | hold: 3 60 | neighbors: 61 | - name: 10.1.2.1 62 | remote_as: 65002 63 | peer_group: demoleaf 64 | enable: true 65 | - name: 10.1.2.3 66 | remote_as: 65002 67 | peer_group: demoleaf 68 | enable: true 69 | -------------------------------------------------------------------------------- /host_vars/dc1-tora: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: dc1-tora 3 | 4 | eos_host_ip: 172.16.130.203 5 | 6 | vlans: 7 | - vlanid: 1 8 | name: default 9 | - vlanid: 2 10 | name: app2 11 | 12 | interfaces: 13 | - name: Loopback0 14 | enable: true 15 | - name: Ethernet1 16 | description: "[BGP]Connection to Leaf1" 17 | enable: true 18 | - name: Ethernet2 19 | description: "[BGP]Connection to Leaf2" 20 | enable: true 21 | 22 | ip_interfaces: 23 | - name: Loopback0 24 | address: 1.1.1.10/32 25 | - name: Ethernet1 26 | address: 10.1.1.1/31 27 | - name: Ethernet2 28 | address: 10.1.2.1/31 29 | 30 | 31 | acls: 32 | - name: ACL-1 33 | action: permit 34 | seqno: 50 35 | description: My wonderful acl 36 | type: standard 37 | srcaddr: 10.10.10.10 38 | srcprefixlen: 32 39 | 40 | ipv4_static_routes: 41 | - ip_dest: 0.0.0.0/0 42 | next_hop: Management1 43 | next_hop_ip: 172.16.130.2 44 | route_name: Default 45 | tag: 100 46 | 47 | virtual_mac_addr: "00:1c:73:00:00:99" 48 | 49 | varp_interfaces: 50 | - vlanid: 1001 51 | name: Varp_Vlan1001 52 | description: My Vlan1001 53 | enable: true 54 | interface_addr: 192.168.1.3/24 55 | virtual_addrs: 56 | - 192.168.1.1 57 | - vlanid: 1002 58 | name: Varp_Vlan1002 59 | description: My Vlan1001 60 | enable: true 61 | interface_addr: 192.168.2.3/24 62 | virtual_addrs: 63 | - 192.168.2.1 64 | 65 | bgp: 66 | enable: true 67 | bgp_as: 65002 68 | redistribute: 69 | - connected 70 | log_neighbor_changes: yes 71 | timers: 72 | keep_alive: 1 73 | hold: 3 74 | listeners: 75 | - name: 10.1.0.0/16 76 | peer_group: demoleaf 77 | remote_as: 65001 78 | 79 | mlag: 80 | mlag_domain_id: mlag1 81 | mlag_trunk_group: mlagpeer 82 | mlag_shutdown: false 83 | local_if_vlan: Vlan1024 84 | local_if_ip_address: 10.0.0.1/30 85 | local_if_disable_spanning_tree: true 86 | peer_address: 10.0.0.2 87 | peer_link_if: Port-Channel10 88 | peer_link_mode: trunk 89 | peer_link_lacp_mode: active 90 | peer_link_enable: true 91 | peer_link_members: 92 | - Ethernet3 93 | - Ethernet4 94 | -------------------------------------------------------------------------------- /host_vars/dc1-torb: -------------------------------------------------------------------------------- 1 | --- 2 | hostname: dc1-torb 3 | 4 | eos_host_ip: 172.16.130.204 5 | 6 | vlans: 7 | - vlanid: 1 8 | name: default 9 | - vlanid: 2 10 | name: production 11 | 12 | interfaces: 13 | - name: Loopback0 14 | enable: true 15 | - name: Ethernet1 16 | description: "[BGP]Connection to Leaf1" 17 | enable: true 18 | - name: Ethernet2 19 | description: "[BGP]Connection to Leaf2" 20 | enable: true 21 | 22 | ip_interfaces: 23 | - name: Loopback0 24 | address: 1.1.1.11/32 25 | - name: Ethernet1 26 | address: 10.1.1.3/31 27 | - name: Ethernet2 28 | address: 10.1.2.3/31 29 | 30 | 31 | acls: 32 | - name: ACL-1 33 | action: permit 34 | seqno: 50 35 | description: My wonderful acl 36 | type: standard 37 | srcaddr: 10.10.10.10 38 | srcprefixlen: 32 39 | 40 | ipv4_static_routes: 41 | - ip_dest: 0.0.0.0/0 42 | next_hop: Management1 43 | next_hop_ip: 172.16.130.2 44 | route_name: Default 45 | tag: 100 46 | 47 | virtual_mac_addr: "00:1c:73:00:00:99" 48 | 49 | varp_interfaces: 50 | - vlanid: 1001 51 | name: Varp_Vlan1001 52 | description: My Vlan1001 53 | enable: true 54 | interface_addr: 192.168.1.4/24 55 | virtual_addrs: 56 | - 192.168.1.1 57 | - vlanid: 1002 58 | name: Varp_Vlan1002 59 | description: My Vlan1001 60 | enable: true 61 | interface_addr: 192.168.2.4/24 62 | virtual_addrs: 63 | - 192.168.2.1 64 | 65 | bgp: 66 | enable: true 67 | bgp_as: 65002 68 | redistribute: 69 | - connected 70 | log_neighbor_changes: yes 71 | timers: 72 | keep_alive: 1 73 | hold: 3 74 | listeners: 75 | - name: 10.1.0.0/16 76 | peer_group: demoleaf 77 | remote_as: 65001 78 | 79 | mlag: 80 | mlag_domain_id: mlag1 81 | mlag_trunk_group: mlagpeer 82 | mlag_shutdown: false 83 | local_if_vlan: Vlan1024 84 | local_if_ip_address: 10.0.0.2/30 85 | local_if_disable_spanning_tree: true 86 | peer_address: 10.0.0.1 87 | peer_link_if: Port-Channel10 88 | peer_link_mode: trunk 89 | peer_link_lacp_mode: active 90 | peer_link_enable: true 91 | peer_link_members: 92 | - Ethernet3 93 | - Ethernet4 94 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | [leaf] 2 | dc1-tora 3 | dc1-torb 4 | 5 | [spine] 6 | dc1-spine1 7 | dc1-spine2 8 | 9 | [webinar_lab] 10 | lf321.nh.aristanetworks.com 11 | cd262.sjc.aristanetworks.com 12 | rtp-rack20-tor01.aristanetworks.com 13 | 14 | [test] 15 | Spine01 16 | Spine02 17 | -------------------------------------------------------------------------------- /leaf.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: leaf 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - arista.eos-system 8 | - arista.eos-interfaces 9 | - arista.eos-bridging 10 | - arista.eos-ipv4 11 | - arista.eos-route-control 12 | - arista.eos-bgp 13 | - arista.eos-mlag 14 | - arista.eos-virtual-router 15 | -------------------------------------------------------------------------------- /newroles.txt: -------------------------------------------------------------------------------- 1 | arista.eos-bgp 2 | arista.eos-bridging 3 | arista.eos-interfaces 4 | arista.eos-ipv4 5 | arista.eos-mlag 6 | arista.eos-route-control 7 | arista.eos-system 8 | arista.eos-virtual-router 9 | arista.eos-vxlan 10 | -------------------------------------------------------------------------------- /ops.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - ops 8 | -------------------------------------------------------------------------------- /roles/bug_scrub/tasks/BUG_172152.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Gather show version output 3 | eos_command: 4 | commands: 5 | - 'show version' 6 | provider: "{{ provider }}" 7 | register: showver 8 | 9 | - set_fact: 10 | bug_applies: "{{'4.17' in showver['stdout'][0]['version'] and '7280' in showver['stdout'][0]['modelName'] }}" 11 | key: interface 12 | attr: virtualRouters 13 | 14 | - name: Gathering VRRP Information 15 | eos_command: 16 | commands: 17 | - 'show vrrp brief' 18 | provider: "{{ provider }}" 19 | register: bugout 20 | 21 | - name: Checking for Sub-Interfaces 22 | assert: 23 | that: 24 | - "'.' not in '{{ item[key] }}' " 25 | msg: 'This host IS a candidate for BUG_172152 because it is a 7280 running 4.17.x. and has a sub-interface configured with VRRP. Please schedule this switch to be upgraded to 4.17.5F.' 26 | with_items: "{{ bugout['stdout'][0][attr] | default([]) }}" 27 | when: "{{ bug_applies }}" 28 | -------------------------------------------------------------------------------- /roles/bug_scrub/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: BUG_172152.yaml 3 | -------------------------------------------------------------------------------- /roles/bug_scrub/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | bugs: 3 | command_info: 4 | cmd: "show vrrp brief" 5 | key: "virtualRouters" 6 | attr: "interface" 7 | name: BUG172152 8 | platform: 9 | - 7280 10 | versions: 11 | - 4.17 12 | output: . 13 | 14 | -------------------------------------------------------------------------------- /roles/ops/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/ops/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for reset 3 | -------------------------------------------------------------------------------- /roles/ops/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for common 3 | -------------------------------------------------------------------------------- /roles/ops/meta/main.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /roles/ops/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Gather Routing Table 3 | eos_command: 4 | commands: 5 | - 'show ip route summary' 6 | provider: '{{ provider }}' 7 | register: routeoutput 8 | 9 | - name: Run Ping tests 10 | eos_command: 11 | commands: 12 | - 'ping {{ item.ip_interfaces.address }} repeat 1' 13 | provider: '{{ provider }}' 14 | with: '{{ inventory_hosts }}' 15 | register: pingresults 16 | 17 | - name: Check Route Table Output 18 | assert: 19 | that: 20 | "0 < routeoutput['stdout'][0]['totalRoutes']" 21 | 22 | -------------------------------------------------------------------------------- /roles/ops/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for interfaces 3 | 4 | -------------------------------------------------------------------------------- /roles/reset/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/reset/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for reset 3 | -------------------------------------------------------------------------------- /roles/reset/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for common 3 | -------------------------------------------------------------------------------- /roles/reset/meta/main.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /roles/reset/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Revert the EOS Running Configuration to a default state 3 | eos_command: 4 | commands: 5 | - 'configure replace {{ base_config }}' 6 | - 'write memory' 7 | provider: '{{ provider }}' 8 | -------------------------------------------------------------------------------- /roles/reset/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for interfaces 3 | -------------------------------------------------------------------------------- /roles/upgrade/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/upgrade/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for reset 3 | -------------------------------------------------------------------------------- /roles/upgrade/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for common 3 | -------------------------------------------------------------------------------- /roles/upgrade/meta/main.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /roles/upgrade/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Gather Show Version Facts 3 | eos_command: 4 | commands: 5 | - 'show version' 6 | provider: '{{ provider }}' 7 | register: showvers 8 | 9 | - set_fact: perform_upgrade={{ target_version not in showvers['stdout'][0]['version'] }} 10 | 11 | - name: Install new SWI 12 | eos_command: 13 | commands: 14 | - 'install source {{ swi_url }} now' 15 | provider: '{{ provider }}' 16 | when: perform_upgrade 17 | 18 | - name: Reload the Switch 19 | eos_command: 20 | commands: 21 | - 'reload now' 22 | provider: '{{ provider }}' 23 | when: perform_upgrade 24 | ignore_errors: yes 25 | 26 | - name: Wait for switch to come back online 27 | wait_for: 28 | host={{ inventory_hostname }} 29 | delay={{ install_pause }} 30 | port=80 31 | timeout={{ reboot_timer | default(300) }} 32 | when: perform_upgrade 33 | 34 | - pause: seconds=5 35 | when: perform_upgrade 36 | 37 | - name: Gather Show Version Facts 38 | eos_command: 39 | commands: 40 | - 'show version' 41 | provider: '{{ provider }}' 42 | register: showvers_post 43 | when: perform_upgrade 44 | 45 | - name: Check EOS Version 46 | assert: 47 | that: 48 | - "'{{ target_version }}' in showvers_post['stdout'][0]['version']" 49 | when: perform_upgrade 50 | -------------------------------------------------------------------------------- /roles/upgrade/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for interfaces 3 | -------------------------------------------------------------------------------- /roles/validate/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/validate/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for reset 3 | -------------------------------------------------------------------------------- /roles/validate/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for common 3 | -------------------------------------------------------------------------------- /roles/validate/meta/main.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /roles/validate/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - pause: seconds={{ pause_sec }} 3 | 4 | - name: Gather EOS Hostname 5 | eos_command: 6 | commands: 7 | - 'show hostname' 8 | provider: '{{ provider }}' 9 | register: showhostname 10 | 11 | - name: Check EOS Hostname 12 | assert: 13 | that: 14 | - "'{{ hostname }}' == showhostname['stdout'][0]['hostname']" 15 | 16 | - name: Gather Show Version Facts 17 | eos_command: 18 | commands: 19 | - 'show version' 20 | provider: '{{ provider }}' 21 | register: showvers 22 | 23 | - name: Check EOS System Parameters 24 | assert: 25 | that: 26 | - "'{{ target_version }}' == showvers['stdout'][0]['version']" 27 | - "'vEOS' == showvers['stdout'][0]['modelName']" 28 | 29 | - name: Gather MLAG Facts 30 | eos_command: 31 | commands: 32 | - 'show mlag' 33 | provider: '{{ provider }}' 34 | register: showmlag 35 | when: mlag is defined 36 | 37 | #- name: Check MLAG Configuration 38 | # assert: 39 | # that: 40 | # - "'{{ mlag.local_if_vlan}}' == showmlag['stdout'][0]['localInterface']" 41 | # - "'{{ mlag.peer_link_if }}' == showmlag['stdout'][0]['peerLink']" 42 | # - "'active' == showmlag['stdout'][0]['state']" 43 | # - "'connected' == showmlag['stdout'][0]['negStatus']" 44 | # - "'up' == showmlag['stdout'][0]['peerLinkStatus']" 45 | # when: mlag is defined 46 | 47 | - name: Gather VARP Facts 48 | eos_command: 49 | commands: 50 | - 'show ip virtual-router' 51 | provider: '{{ provider }}' 52 | register: showvarp 53 | when: varp_interfaces is defined or virtual_mac_addr is defined 54 | 55 | - name: Check VARP Mac Address 56 | assert: 57 | that: 58 | - "'{{ virtual_mac_addr }}' == showvarp['stdout'][0]['virtualMac']" 59 | when: virtual_mac_addr is defined 60 | 61 | - name: Check Number of VARP Interfaces 62 | assert: 63 | that: 64 | - "{{ varp_interfaces|length }} == {{ showvarp['stdout'][0]['virtualRouters'] | length }}" 65 | when: varp_interfaces is defined 66 | -------------------------------------------------------------------------------- /roles/validate/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for interfaces 3 | -------------------------------------------------------------------------------- /run_commands.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: "{{ run_hosts | mandatory }}" 3 | gather_facts: no 4 | connection: local 5 | 6 | tasks: 7 | - name: Run Specified Commands 8 | eos_command: 9 | commands: '{{ run_commands | format_commands(encoding) }}' 10 | provider: '{{ provider }}' 11 | register: commands_out 12 | 13 | - set_fact: output='{{ commands_out['stdout'] | format_stdout(run_commands | format_commands(encoding)) }}' 14 | 15 | - debug: var=output 16 | -------------------------------------------------------------------------------- /send_probe.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: "{{ run_hosts | mandatory }}" 3 | gather_facts: no 4 | connection: local 5 | 6 | tasks: 7 | - name: Send probe 8 | eos_command: 9 | commands: 10 | - command: 'ping {{ dst }} record-route repeat {{ repeat }} size {{ size }} source {{ source }} timeout {{ timeout }}' 11 | output: 'text' 12 | provider: '{{ provider }}' 13 | register: ping_result 14 | 15 | - set_fact: loss='{{ ping_result['stdout'][0] | packet_loss }}' 16 | 17 | - assert: 18 | that: 19 | - "loss == '0'" 20 | msg: "Ping reported packet loss. {{ ping_result['stdout'][0] }}" 21 | -------------------------------------------------------------------------------- /site.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: spine.yaml 3 | - include: leaf.yaml 4 | 5 | -------------------------------------------------------------------------------- /spine.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: spine 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - arista.eos-system 8 | - arista.eos-interfaces 9 | - arista.eos-bridging 10 | - arista.eos-ipv4 11 | - arista.eos-route-control 12 | - arista.eos-bgp 13 | -------------------------------------------------------------------------------- /upgrade.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: "{{ upgrade_hosts | mandatory }}" 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - upgrade 8 | -------------------------------------------------------------------------------- /validate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - validate 8 | -------------------------------------------------------------------------------- /vlans_only.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: no 4 | connection: local 5 | 6 | roles: 7 | - arista.eos-bridging 8 | -------------------------------------------------------------------------------- /vmtracer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: webinar_lab 3 | gather_facts: no 4 | connection: local 5 | 6 | tasks: 7 | - block: 8 | - name: Find VM by name 9 | eos_command: 10 | commands: 11 | - command: 'show vmtracer vm name {{ id }}' 12 | output: 'json' 13 | provider: "{{ provider }}" 14 | register: output 15 | 16 | - set_fact: 17 | info: "{{ output.stdout[0]['vms'][0] }}" 18 | interface: "{{ output.stdout[0]['vms'][0]['interface'] }}" 19 | vlan: "{{ output.stdout[0]['vms'][0]['vlan'] }}" 20 | 21 | when: "{{ output.stdout[0]['vms'] | length }}" 22 | 23 | - debug: var=info 24 | when: "{{ output.stdout[0]['vms'] | length }}" 25 | 26 | when: '"{{ id_type }}" == "vm_name"' 27 | 28 | - name: Find VM by Mac Addresss 29 | eos_command: 30 | commands: 31 | - command: 'show vmtracer vm mac {{ id }}' 32 | output: 'json' 33 | provider: "{{ provider }}" 34 | register: vmmac 35 | when: '"{{ id_type }}" == "mac_address"' 36 | 37 | - name: Find VMs on a Given Interface 38 | eos_command: 39 | commands: 40 | - 'show vmtracer interface {{ id }}' 41 | provider: "{{ provider }}" 42 | register: vmint 43 | when: '"{{ id_type }}" == "interface"' 44 | 45 | - block: 46 | - name: Find VMs on a given vlan 47 | eos_command: 48 | commands: 49 | - 'show vmtracer vm' 50 | provider: "{{ provider }}" 51 | register: vms 52 | 53 | - set_fact: 54 | filtered: "{{ vms.stdout[0] | filter_vms(id) }}" 55 | 56 | - debug: var=filtered 57 | 58 | when: ' "{{ id_type }}" == "vlan"' 59 | 60 | - name: Run Health Check 61 | eos_command: 62 | commands: 63 | - command: 'show interfaces {{ interface }} counters errors' 64 | output: 'json' 65 | - command: 'show interfaces {{ interface }} counters discards' 66 | output: 'json' 67 | - command: 'show interfaces {{ interface }} counters rates' 68 | output: 'json' 69 | provider: "{{ provider }}" 70 | register: counters 71 | when: 'interface is defined and "{{ run_check }}" == "Yes"' 72 | 73 | - debug: var=counters.stdout 74 | when: 'interface is defined and "{{ run_check }}" == "Yes"' 75 | 76 | - name: Gather Vlans Allowed on this Interface's Trunk 77 | eos_command: 78 | commands: 79 | - command: 'show interfaces {{ interface }} trunk' 80 | output: 'json' 81 | provider: "{{ provider }}" 82 | register: configout 83 | when: 'interface is defined and "{{ run_check }}" == "Yes"' 84 | 85 | - set_fact: 86 | trunkvlans: " {{configout.stdout[0]['trunks'][interface]['forwardingVlans']['vlanIds'] }}" 87 | when: 'configout is defined and interface is defined' 88 | 89 | - name: Check that the VM's Portgroup Vlan is configured on the Ethernet Interface 90 | assert: 91 | that: 92 | - '{{ vlan }} in {{ trunkvlans }}' 93 | msg: 'Vlan {{ vlan }} is NOT configured on interface {{ interface }}. Adding this as a trunk allowed Vlan will provide connectivity.' 94 | when: 'configout is defined and interface is defined' 95 | --------------------------------------------------------------------------------