diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..f121f4f --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +## Getting Started + +For this repository/webinar a simple topology was created and looks like the below image: + +![webinar topology](./docs/img/webinar-simple-topology.png) + +## Pre-change Validation Steps + +1. Ansible is used to generate configuration via Jinja2 templates. +2. A docker-compose with `invoke` is provided to demonstrate a local pipeline testing. +3. Update `vars` files based on required changes. + +### Create Virtual Environment and Install + +```bash +cd webinars/batfish-routing +``` + +```bash +poetry shell +``` + +```bash +poetry install +``` + +## Running the Pipeline (locally) + +``` +invoke tests +``` + +Invoke test will build two docker containers. One with this `application` and the other is `batfish` itself. + +## Invoke Tests In Action + +*What does invoke tests do?* + +1. Bring up containers. +2. Generates the configurations. +3. Run `tests`. + +``` +▶ invoke tests +Running docker-compose command "ps --services --filter status=running" +Running docker-compose command "run --entrypoint 'yamllint .' batfish-routing" +[dim]PYTHON_VER=3.9 \ + docker-compose \ + --project-name "batfish_routing" \ + --project-directory "/Users/jeffkala/2022-ntc-content/webinars/batfish-routing/development/" \ + -f "/Users/jeffkala/2022-ntc-content/webinars/batfish-routing/development/docker-compose.yml" \ + run --entrypoint 'yamllint .' batfish-routing[/dim] +Creating batfish_routing_batfish-routing_run ... done +Running docker-compose command "ps --services --filter status=running" +Running docker-compose command "run --entrypoint 'ansible-playbook /local/config_gen/pb_generate_configs.yml -i /local/config_gen/inventory.yml' batfish-routing" +[dim]PYTHON_VER=3.9 \ + docker-compose \ + --project-name "batfish_routing" \ + --project-directory "/Users/jeffkala/2022-ntc-content/webinars/batfish-routing/development/" \ + -f "/Users/jeffkala/2022-ntc-content/webinars/batfish-routing/development/docker-compose.yml" \ + run --entrypoint 'ansible-playbook /local/config_gen/pb_generate_configs.yml -i /local/config_gen/inventory.yml' batfish-routing[/dim] +Creating batfish_routing_batfish-routing_run ... done + +PLAY [10000 - GENERATE CONFIGURATIONS] ********************************************************************************************************************************************************************* + +TASK [10010 - GENERATE CONFIGURATIONS] ********************************************************************************************************************************************************************* +ok: [edge-1] +ok: [sw-1] +ok: [edge-2] +ok: [sw-2] +ok: [isp-0] + +PLAY RECAP ************************************************************************************************************************************************************************************************* +edge-1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +edge-2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +isp-0 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +sw-1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +sw-2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 + +Running docker-compose command "ps --services --filter status=running" +Running docker-compose command "run --entrypoint 'python /local/config_gen/tests/test_routing.py' batfish-routing" +[dim]PYTHON_VER=3.9 \ + docker-compose \ + --project-name "batfish_routing" \ + --project-directory "/Users/jeffkala/2022-ntc-content/webinars/batfish-routing/development/" \ + -f "/Users/jeffkala/2022-ntc-content/webinars/batfish-routing/development/docker-compose.yml" \ + run --entrypoint 'python /local/config_gen/tests/test_routing.py' batfish-routing[/dim] +Creating batfish_routing_batfish-routing_run ... done +Your snapshot was successfully initialized but Batfish failed to fully recognized some lines in one or more input files. Some unrecognized configuration lines are not uncommon for new networks, and it is often fine to proceed with further analysis. You can help the Batfish developers improve support for your network by running: + + bf.upload_diagnostics(dry_run=False, contact_info='') + +to share private, anonymized information. For more information, see the documentation with: + + help(bf.upload_diagnostics) +==================== +Starting Batfish Setup..... +==================== +Validated Assert No Unestablished Bgp Sessions +Validated Assert No Incompatible Bgp Sessions +Validated Assert No Incompatible Ospf Sessions +Test from @enter(sw-1[GigabitEthernet0/0]) to DNS has passed! +Test from @enter(sw-2[GigabitEthernet0/0]) to DNS has passed! +/usr/local/lib/python3.9/site-packages/pybatfish/client/asserts.py:224: BatfishAssertWarning: No node: sw-1 + warnings.warn("No node: {}".format(node), category=BatfishAssertWarning) +Desktop pod has no routes to security servers. passed! +Route to DNS must be a OSPF E2 route from Desktop pod. passed! +There is always at least one BGP session towards an ISP in Established state. passed! +All tests have passed! +``` + diff --git a/config_gen/ansible.cfg b/config_gen/ansible.cfg new file mode 100644 index 0000000..1cdc4bc --- /dev/null +++ b/config_gen/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +host_key_checking=False +interpreter_python=/usr/bin/env python diff --git a/config_gen/data/configs/edge-1.cfg b/config_gen/data/configs/edge-1.cfg new file mode 100644 index 0000000..048d557 --- /dev/null +++ b/config_gen/data/configs/edge-1.cfg @@ -0,0 +1,180 @@ +! +! Last configuration change at 17:22:06 UTC Thu Sep 8 2022 +! +version 15.9 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname edge-1 +! +boot-start-marker +boot-end-marker +! +! +enable secret 4 tnhtc92DXBhelxjYk8LWJrPV36S2i4ntXrpb4RFmfqY +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip domain name virl.info +ip cef +no ipv6 cef +! +multilink bundle-name authenticated +! +! +! +! +username cisco privilege 15 secret 9 $9$N7aRodw43LgdBt$4JeCjXGYmGkn9waA4Ib2tlxqtOIlJRs5q99ZCPYb8Ag +! +redundancy +! +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + description to GigabitEthernet3/3.sw-1 + ip address 192.168.11.1 255.255.255.252 + ip ospf 100 area 0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to GigabitEthernet2.isp-0 + ip address 192.1.11.1 255.255.255.252 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/2 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/3 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/4 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/5 + description to port2.mgmt-sw1 + ip address dhcp + duplex auto + speed auto + media-type rj45 +! +router ospf 100 + router-id 1.1.1.1 + redistribute bgp 100 subnets + passive-interface default + no passive-interface GigabitEthernet0/0 +! +router bgp 100 + bgp log-neighbor-changes + redistribute ospf 100 + neighbor 192.1.11.2 remote-as 200 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip ssh server algorithm authentication password +! +ipv6 ioam timestamp +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login local + transport input telnet ssh +! +no scheduler allocate +! +end \ No newline at end of file diff --git a/config_gen/data/configs/edge-2.cfg b/config_gen/data/configs/edge-2.cfg new file mode 100644 index 0000000..625ce79 --- /dev/null +++ b/config_gen/data/configs/edge-2.cfg @@ -0,0 +1,180 @@ +! +! Last configuration change at 17:18:57 UTC Thu Sep 8 2022 +! +version 15.9 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname edge-2 +! +boot-start-marker +boot-end-marker +! +! +enable secret 4 tnhtc92DXBhelxjYk8LWJrPV36S2i4ntXrpb4RFmfqY +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip domain name virl.info +ip cef +no ipv6 cef +! +multilink bundle-name authenticated +! +! +! +! +username cisco privilege 15 secret 9 $9$zoosVKCcDFR0sN$9pbBrLDvbDGdsmz3Yp3P7YLM5JCq4elnaitf39f4.mU +! +redundancy +! +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + description to GigabitEthernet3/3.sw-2 + ip address 192.168.22.1 255.255.255.0 + ip ospf 100 area 0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to GigabitEthernet1.isp-0 + ip address 192.1.12.1 255.255.255.252 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/2 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/3 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/4 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/5 + description to port3.mgmt-sw1 + ip address dhcp + duplex auto + speed auto + media-type rj45 +! +router ospf 100 + router-id 2.2.2.1 + redistribute bgp 100 subnets + passive-interface default + no passive-interface GigabitEthernet0/0 +! +router bgp 100 + bgp log-neighbor-changes + redistribute ospf 100 + neighbor 192.1.12.2 remote-as 200 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip ssh server algorithm authentication password +! +ipv6 ioam timestamp +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login local + transport input telnet ssh +! +no scheduler allocate +! +end diff --git a/config_gen/data/configs/isp-0.cfg b/config_gen/data/configs/isp-0.cfg new file mode 100644 index 0000000..19e9962 --- /dev/null +++ b/config_gen/data/configs/isp-0.cfg @@ -0,0 +1,228 @@ +Current configuration : 4577 bytes +! +! Last configuration change at 17:22:17 UTC Thu Sep 8 2022 +! +version 17.3 +service timestamps debug datetime msec +service timestamps log datetime msec +! Call-home is enabled by Smart-Licensing. +service call-home +platform qfp utilization monitor load 80 +platform punt-keepalive disable-kernel-core +platform console serial +! +hostname isp-0 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +! +! +! +! +no ip domain lookup +ip domain name virl.info +! +! +! +login on-success log +! +! +! +! +! +! +! +subscriber templating +! +! +! +! +! +! +multilink bundle-name authenticated +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +crypto pki trustpoint SLA-TrustPoint + enrollment pkcs12 + revocation-check crl +! +! +crypto pki certificate chain SLA-TrustPoint + certificate ca 01 + 30820321 30820209 A0030201 02020101 300D0609 2A864886 F70D0101 0B050030 + 32310E30 0C060355 040A1305 43697363 6F312030 1E060355 04031317 43697363 + 6F204C69 63656E73 696E6720 526F6F74 20434130 1E170D31 33303533 30313934 + 3834375A 170D3338 30353330 31393438 34375A30 32310E30 0C060355 040A1305 + 43697363 6F312030 1E060355 04031317 43697363 6F204C69 63656E73 696E6720 + 526F6F74 20434130 82012230 0D06092A 864886F7 0D010101 05000382 010F0030 + 82010A02 82010100 A6BCBD96 131E05F7 145EA72C 2CD686E6 17222EA1 F1EFF64D + CBB4C798 212AA147 C655D8D7 9471380D 8711441E 1AAF071A 9CAE6388 8A38E520 + 1C394D78 462EF239 C659F715 B98C0A59 5BBB5CBD 0CFEBEA3 700A8BF7 D8F256EE + 4AA4E80D DB6FD1C9 60B1FD18 FFC69C96 6FA68957 A2617DE7 104FDC5F EA2956AC + 7390A3EB 2B5436AD C847A2C5 DAB553EB 69A9A535 58E9F3E3 C0BD23CF 58BD7188 + 68E69491 20F320E7 948E71D7 AE3BCC84 F10684C7 4BC8E00F 539BA42B 42C68BB7 + C7479096 B4CB2D62 EA2F505D C7B062A4 6811D95B E8250FC4 5D5D5FB8 8F27D191 + C55F0D76 61F9A4CD 3D992327 A8BB03BD 4E6D7069 7CBADF8B DF5F4368 95135E44 + DFC7C6CF 04DD7FD1 02030100 01A34230 40300E06 03551D0F 0101FF04 04030201 + 06300F06 03551D13 0101FF04 05300301 01FF301D 0603551D 0E041604 1449DC85 + 4B3D31E5 1B3E6A17 606AF333 3D3B4C73 E8300D06 092A8648 86F70D01 010B0500 + 03820101 00507F24 D3932A66 86025D9F E838AE5C 6D4DF6B0 49631C78 240DA905 + 604EDCDE FF4FED2B 77FC460E CD636FDB DD44681E 3A5673AB 9093D3B1 6C9E3D8B + D98987BF E40CBD9E 1AECA0C2 2189BB5C 8FA85686 CD98B646 5575B146 8DFC66A8 + 467A3DF4 4D565700 6ADF0F0D CF835015 3C04FF7C 21E878AC 11BA9CD2 55A9232C + 7CA7B7E6 C1AF74F6 152E99B7 B1FCF9BB E973DE7F 5BDDEB86 C71E3B49 1765308B + 5FB0DA06 B92AFE7F 494E8A9E 07B85737 F3A58BE1 1A48A229 C37C1E69 39F08678 + 80DDCD16 D6BACECA EEBC7CF9 8428787B 35202CDC 60E4616A B623CDBD 230E3AFB + 418616A9 4093E049 4D10AB75 27E86F73 932E35B5 8862FDAE 0275156F 719BB2F0 + D697DF7F 28 + quit +! +license udi pid CSR1000V sn 9S7H0VT077M +diagnostic bootup level minimal +memory free low-watermark processor 71556 +! +! +spanning-tree extend system-id +! +username cisco privilege 15 secret 9 $9$bvgcuJ20Ob4q4k$V58dN7UcBNjpzMYSGSEr6bCuI6asx1/yX86bYhaHMyw +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface Loopback8 + ip address 8.8.8.8 255.255.255.255 +! +interface GigabitEthernet1 + description to GigabitEthernet0/1.edge-2 + ip address 192.1.12.2 255.255.255.252 + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet2 + description to GigabitEthernet0/1.edge-1 + ip address 192.1.11.2 255.255.255.252 + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet3 + description to + no ip address + shutdown + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet4 + description to + no ip address + shutdown + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet5 + description to port1.mgmt-sw1 + ip address dhcp + negotiation auto + no mop enabled + no mop sysid +! + +router bgp 200 + bgp log-neighbor-changes + network 8.8.8.8 mask 255.255.255.255 + neighbor 192.1.11.1 remote-as 100 + neighbor 192.1.12.1 remote-as 100 +! +ip forward-protocol nd +no ip http server +ip http secure-server +! +ip ssh server algorithm authentication password +! +! +! +! +! +! +! +control-plane +! +! +! +! +! +! +line con 0 + password cisco + stopbits 1 +line vty 0 4 + exec-timeout 720 0 + password cisco + login local + transport input telnet ssh +! +call-home + ! If contact email address in call-home is configured as sch-smart-licensing@cisco.com + ! the email address configured in Cisco Smart License Portal will be used as contact email address to send SCH notifications. + contact-email-addr sch-smart-licensing@cisco.com + profile "CiscoTAC-1" + active + destination transport-method http +! +! +! +! +! +end \ No newline at end of file diff --git a/config_gen/data/configs/sw-1.cfg b/config_gen/data/configs/sw-1.cfg new file mode 100644 index 0000000..9f27a34 --- /dev/null +++ b/config_gen/data/configs/sw-1.cfg @@ -0,0 +1,258 @@ +! +! Last configuration change at 19:04:38 UTC Thu Sep 8 2022 +! +version 15.2 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +service compress-config +! +hostname sw-1 +! +boot-start-marker +boot-end-marker +! +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family +! +enable password cisco +! +no aaa new-model +! +! +! +! +! +vtp domain virl.lab +vtp mode transparent +! +! +! +no ip domain-lookup +ip cef +no ip igmp snooping +no ipv6 cef +! +! +! +spanning-tree mode pvst +spanning-tree extend system-id +! +! +vlan 2 + name ank_vlan2 +! +vlan 10 +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + switchport access vlan 10 + switchport trunk allowed vlan 10 + switchport trunk encapsulation dot1q + switchport mode access + no negotiation auto +! +interface GigabitEthernet0/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/0 + switchport trunk encapsulation dot1q + switchport mode trunk + no negotiation auto +! +interface GigabitEthernet3/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/2 + description to port4.mgmt-sw1 + no switchport + ip address dhcp + duplex full + negotiation auto +! +interface GigabitEthernet3/3 + description to GigabitEthernet0/0.edge-1 + no switchport + ip address 192.168.11.2 255.255.255.252 + ip ospf 100 area 0 + duplex full + negotiation auto +! +interface Vlan10 + ip address 192.168.1.2 255.255.255.0 + standby 1 ip 192.168.1.1 +! +router ospf 100 + router-id 1.1.1.2 + passive-interface default + no passive-interface GigabitEthernet3/3 + network 192.168.1.0 0.0.0.255 area 0 +! +ip forward-protocol nd +! +no ip http server +no ip http secure-server +! +ip ssh server algorithm encryption aes128-ctr aes192-ctr aes256-ctr +ip ssh client algorithm encryption aes128-ctr aes192-ctr aes256-ctr +! +! +! +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +! +end \ No newline at end of file diff --git a/config_gen/data/configs/sw-2.cfg b/config_gen/data/configs/sw-2.cfg new file mode 100644 index 0000000..8029af0 --- /dev/null +++ b/config_gen/data/configs/sw-2.cfg @@ -0,0 +1,259 @@ +! +! Last configuration change at 19:04:35 UTC Thu Sep 8 2022 +! +version 15.2 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +service compress-config +! +hostname sw-2 +! +boot-start-marker +boot-end-marker +! +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family +! +enable password cisco +! +no aaa new-model +! +! +! +! +! +vtp domain virl.lab +vtp mode transparent +! +! +! +no ip domain-lookup +ip cef +no ip igmp snooping +no ipv6 cef +! +! +! +spanning-tree mode pvst +spanning-tree extend system-id +! +! +vlan 2 + name ank_vlan2 +! +vlan 10 + name VLAN10 +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + switchport access vlan 10 + switchport trunk allowed vlan 10 + switchport trunk encapsulation dot1q + switchport mode access + no negotiation auto +! +interface GigabitEthernet0/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/0 + switchport trunk encapsulation dot1q + switchport mode trunk + no negotiation auto +! +interface GigabitEthernet3/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/2 + description to port5.mgmt-sw1 + no switchport + ip address dhcp + duplex full + negotiation auto +! +interface GigabitEthernet3/3 + description to GigabitEthernet0/0.edge-2 + no switchport + ip address 192.168.22.2 255.255.255.0 + ip ospf 100 area 0 + duplex full + negotiation auto +! +interface Vlan10 + ip address 192.168.1.3 255.255.255.0 + standby 1 ip 192.168.1.1 +! +router ospf 100 + router-id 2.2.2.2 + passive-interface default + no passive-interface GigabitEthernet3/3 + network 192.168.1.0 0.0.0.255 area 0 +! +ip forward-protocol nd +! +no ip http server +no ip http secure-server +! +ip ssh server algorithm encryption aes128-ctr aes192-ctr aes256-ctr +ip ssh client algorithm encryption aes128-ctr aes192-ctr aes256-ctr +! +! +! +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +! +end \ No newline at end of file diff --git a/config_gen/host_vars/edge-1.yml b/config_gen/host_vars/edge-1.yml new file mode 100644 index 0000000..b3cebcf --- /dev/null +++ b/config_gen/host_vars/edge-1.yml @@ -0,0 +1,9 @@ +--- +bgp: + asn: 100 + neighbors: + 192.1.11.2: + remote_asn: 200 +ospf: + process: 100 + rid: 1.1.1.1 diff --git a/config_gen/host_vars/edge-2.yml b/config_gen/host_vars/edge-2.yml new file mode 100644 index 0000000..4291f54 --- /dev/null +++ b/config_gen/host_vars/edge-2.yml @@ -0,0 +1,9 @@ +--- +bgp: + asn: 100 + neighbors: + 192.1.12.2: + remote_asn: 200 +ospf: + process: 100 + rid: 2.2.2.1 diff --git a/config_gen/host_vars/isp-0.yml b/config_gen/host_vars/isp-0.yml new file mode 100644 index 0000000..d5253f7 --- /dev/null +++ b/config_gen/host_vars/isp-0.yml @@ -0,0 +1,10 @@ +--- +bgp: + asn: 200 + neighbors: + 192.1.11.1: + remote_asn: 100 + 192.1.12.1: + remote_asn: 100 + routes: + - network 8.8.8.8 mask 255.255.255.255 diff --git a/config_gen/inventory.yml b/config_gen/inventory.yml new file mode 100644 index 0000000..9f414da --- /dev/null +++ b/config_gen/inventory.yml @@ -0,0 +1,19 @@ +--- +all: + vars: + connection: network_cli + ansible_network_os: ios + children: + webinar: + children: + isp: + hosts: + isp-0: + edges: + hosts: + edge-1: + edge-2: + switches: + hosts: + sw-1: + sw-2: diff --git a/config_gen/pb_generate_configs.yml b/config_gen/pb_generate_configs.yml new file mode 100644 index 0000000..eec59c8 --- /dev/null +++ b/config_gen/pb_generate_configs.yml @@ -0,0 +1,10 @@ +--- +- name: "10000 - GENERATE CONFIGURATIONS" + hosts: "webinar" + connection: "local" + gather_facts: false + tasks: + - name: "10010 - GENERATE CONFIGURATIONS" + template: + src: "/local/config_gen/templates/{{ inventory_hostname }}.j2" + dest: "/local/config_gen/data/configs/{{ inventory_hostname }}.cfg" diff --git a/config_gen/templates/edge-1.j2 b/config_gen/templates/edge-1.j2 new file mode 100644 index 0000000..45709dc --- /dev/null +++ b/config_gen/templates/edge-1.j2 @@ -0,0 +1,182 @@ +! +! Last configuration change at 17:22:06 UTC Thu Sep 8 2022 +! +version 15.9 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname edge-1 +! +boot-start-marker +boot-end-marker +! +! +enable secret 4 tnhtc92DXBhelxjYk8LWJrPV36S2i4ntXrpb4RFmfqY +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip domain name virl.info +ip cef +no ipv6 cef +! +multilink bundle-name authenticated +! +! +! +! +username cisco privilege 15 secret 9 $9$N7aRodw43LgdBt$4JeCjXGYmGkn9waA4Ib2tlxqtOIlJRs5q99ZCPYb8Ag +! +redundancy +! +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + description to GigabitEthernet3/3.sw-1 + ip address 192.168.11.1 255.255.255.252 + ip ospf 100 area 0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to GigabitEthernet2.isp-0 + ip address 192.1.11.1 255.255.255.252 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/2 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/3 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/4 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/5 + description to port2.mgmt-sw1 + ip address dhcp + duplex auto + speed auto + media-type rj45 +! +router ospf {{ ospf['process'] }} + router-id {{ ospf['rid'] }} + redistribute bgp 100 subnets + passive-interface default + no passive-interface GigabitEthernet0/0 +! +router bgp {{ bgp['asn'] }} + bgp log-neighbor-changes + redistribute ospf 100 +{% for neighbor, details in bgp['neighbors'].items() %} + neighbor {{ neighbor }} remote-as {{ details['remote_asn'] }} +{% endfor %} +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip ssh server algorithm authentication password +! +ipv6 ioam timestamp +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login local + transport input telnet ssh +! +no scheduler allocate +! +end \ No newline at end of file diff --git a/config_gen/templates/edge-2.j2 b/config_gen/templates/edge-2.j2 new file mode 100644 index 0000000..ca0a887 --- /dev/null +++ b/config_gen/templates/edge-2.j2 @@ -0,0 +1,182 @@ +! +! Last configuration change at 17:18:57 UTC Thu Sep 8 2022 +! +version 15.9 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname edge-2 +! +boot-start-marker +boot-end-marker +! +! +enable secret 4 tnhtc92DXBhelxjYk8LWJrPV36S2i4ntXrpb4RFmfqY +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip domain name virl.info +ip cef +no ipv6 cef +! +multilink bundle-name authenticated +! +! +! +! +username cisco privilege 15 secret 9 $9$zoosVKCcDFR0sN$9pbBrLDvbDGdsmz3Yp3P7YLM5JCq4elnaitf39f4.mU +! +redundancy +! +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + description to GigabitEthernet3/3.sw-2 + ip address 192.168.22.1 255.255.255.0 + ip ospf 100 area 0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to GigabitEthernet1.isp-0 + ip address 192.1.12.1 255.255.255.252 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/2 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/3 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/4 + description to + no ip address + shutdown + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/5 + description to port3.mgmt-sw1 + ip address dhcp + duplex auto + speed auto + media-type rj45 +! +router ospf {{ ospf['process'] }} + router-id {{ ospf['rid'] }} + redistribute bgp 100 subnets + passive-interface default + no passive-interface GigabitEthernet0/0 +! +router bgp {{ bgp['asn'] }} + bgp log-neighbor-changes + redistribute ospf 100 +{% for neighbor, details in bgp['neighbors'].items() %} + neighbor {{ neighbor }} remote-as {{ details['remote_asn'] }} +{% endfor %} +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip ssh server algorithm authentication password +! +ipv6 ioam timestamp +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login local + transport input telnet ssh +! +no scheduler allocate +! +end diff --git a/config_gen/templates/isp-0.j2 b/config_gen/templates/isp-0.j2 new file mode 100644 index 0000000..059baae --- /dev/null +++ b/config_gen/templates/isp-0.j2 @@ -0,0 +1,231 @@ +Current configuration : 4577 bytes +! +! Last configuration change at 17:22:17 UTC Thu Sep 8 2022 +! +version 17.3 +service timestamps debug datetime msec +service timestamps log datetime msec +! Call-home is enabled by Smart-Licensing. +service call-home +platform qfp utilization monitor load 80 +platform punt-keepalive disable-kernel-core +platform console serial +! +hostname isp-0 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +! +! +! +! +no ip domain lookup +ip domain name virl.info +! +! +! +login on-success log +! +! +! +! +! +! +! +subscriber templating +! +! +! +! +! +! +multilink bundle-name authenticated +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +crypto pki trustpoint SLA-TrustPoint + enrollment pkcs12 + revocation-check crl +! +! +crypto pki certificate chain SLA-TrustPoint + certificate ca 01 + 30820321 30820209 A0030201 02020101 300D0609 2A864886 F70D0101 0B050030 + 32310E30 0C060355 040A1305 43697363 6F312030 1E060355 04031317 43697363 + 6F204C69 63656E73 696E6720 526F6F74 20434130 1E170D31 33303533 30313934 + 3834375A 170D3338 30353330 31393438 34375A30 32310E30 0C060355 040A1305 + 43697363 6F312030 1E060355 04031317 43697363 6F204C69 63656E73 696E6720 + 526F6F74 20434130 82012230 0D06092A 864886F7 0D010101 05000382 010F0030 + 82010A02 82010100 A6BCBD96 131E05F7 145EA72C 2CD686E6 17222EA1 F1EFF64D + CBB4C798 212AA147 C655D8D7 9471380D 8711441E 1AAF071A 9CAE6388 8A38E520 + 1C394D78 462EF239 C659F715 B98C0A59 5BBB5CBD 0CFEBEA3 700A8BF7 D8F256EE + 4AA4E80D DB6FD1C9 60B1FD18 FFC69C96 6FA68957 A2617DE7 104FDC5F EA2956AC + 7390A3EB 2B5436AD C847A2C5 DAB553EB 69A9A535 58E9F3E3 C0BD23CF 58BD7188 + 68E69491 20F320E7 948E71D7 AE3BCC84 F10684C7 4BC8E00F 539BA42B 42C68BB7 + C7479096 B4CB2D62 EA2F505D C7B062A4 6811D95B E8250FC4 5D5D5FB8 8F27D191 + C55F0D76 61F9A4CD 3D992327 A8BB03BD 4E6D7069 7CBADF8B DF5F4368 95135E44 + DFC7C6CF 04DD7FD1 02030100 01A34230 40300E06 03551D0F 0101FF04 04030201 + 06300F06 03551D13 0101FF04 05300301 01FF301D 0603551D 0E041604 1449DC85 + 4B3D31E5 1B3E6A17 606AF333 3D3B4C73 E8300D06 092A8648 86F70D01 010B0500 + 03820101 00507F24 D3932A66 86025D9F E838AE5C 6D4DF6B0 49631C78 240DA905 + 604EDCDE FF4FED2B 77FC460E CD636FDB DD44681E 3A5673AB 9093D3B1 6C9E3D8B + D98987BF E40CBD9E 1AECA0C2 2189BB5C 8FA85686 CD98B646 5575B146 8DFC66A8 + 467A3DF4 4D565700 6ADF0F0D CF835015 3C04FF7C 21E878AC 11BA9CD2 55A9232C + 7CA7B7E6 C1AF74F6 152E99B7 B1FCF9BB E973DE7F 5BDDEB86 C71E3B49 1765308B + 5FB0DA06 B92AFE7F 494E8A9E 07B85737 F3A58BE1 1A48A229 C37C1E69 39F08678 + 80DDCD16 D6BACECA EEBC7CF9 8428787B 35202CDC 60E4616A B623CDBD 230E3AFB + 418616A9 4093E049 4D10AB75 27E86F73 932E35B5 8862FDAE 0275156F 719BB2F0 + D697DF7F 28 + quit +! +license udi pid CSR1000V sn 9S7H0VT077M +diagnostic bootup level minimal +memory free low-watermark processor 71556 +! +! +spanning-tree extend system-id +! +username cisco privilege 15 secret 9 $9$bvgcuJ20Ob4q4k$V58dN7UcBNjpzMYSGSEr6bCuI6asx1/yX86bYhaHMyw +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface Loopback8 + ip address 8.8.8.8 255.255.255.255 +! +interface GigabitEthernet1 + description to GigabitEthernet0/1.edge-2 + ip address 192.1.12.2 255.255.255.252 + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet2 + description to GigabitEthernet0/1.edge-1 + ip address 192.1.11.2 255.255.255.252 + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet3 + description to + no ip address + shutdown + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet4 + description to + no ip address + shutdown + negotiation auto + no mop enabled + no mop sysid +! +interface GigabitEthernet5 + description to port1.mgmt-sw1 + ip address dhcp + negotiation auto + no mop enabled + no mop sysid +! + +router bgp {{ bgp['asn'] }} + bgp log-neighbor-changes +{% for route in bgp['routes'] %} + {{ route }} +{% endfor %} +{% for neighbor, details in bgp['neighbors'].items() %} + neighbor {{ neighbor }} remote-as {{ details['remote_asn'] }} +{% endfor %} +! +ip forward-protocol nd +no ip http server +ip http secure-server +! +ip ssh server algorithm authentication password +! +! +! +! +! +! +! +control-plane +! +! +! +! +! +! +line con 0 + password cisco + stopbits 1 +line vty 0 4 + exec-timeout 720 0 + password cisco + login local + transport input telnet ssh +! +call-home + ! If contact email address in call-home is configured as sch-smart-licensing@cisco.com + ! the email address configured in Cisco Smart License Portal will be used as contact email address to send SCH notifications. + contact-email-addr sch-smart-licensing@cisco.com + profile "CiscoTAC-1" + active + destination transport-method http +! +! +! +! +! +end \ No newline at end of file diff --git a/config_gen/templates/sw-1.j2 b/config_gen/templates/sw-1.j2 new file mode 100644 index 0000000..9f27a34 --- /dev/null +++ b/config_gen/templates/sw-1.j2 @@ -0,0 +1,258 @@ +! +! Last configuration change at 19:04:38 UTC Thu Sep 8 2022 +! +version 15.2 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +service compress-config +! +hostname sw-1 +! +boot-start-marker +boot-end-marker +! +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family +! +enable password cisco +! +no aaa new-model +! +! +! +! +! +vtp domain virl.lab +vtp mode transparent +! +! +! +no ip domain-lookup +ip cef +no ip igmp snooping +no ipv6 cef +! +! +! +spanning-tree mode pvst +spanning-tree extend system-id +! +! +vlan 2 + name ank_vlan2 +! +vlan 10 +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + switchport access vlan 10 + switchport trunk allowed vlan 10 + switchport trunk encapsulation dot1q + switchport mode access + no negotiation auto +! +interface GigabitEthernet0/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/0 + switchport trunk encapsulation dot1q + switchport mode trunk + no negotiation auto +! +interface GigabitEthernet3/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/2 + description to port4.mgmt-sw1 + no switchport + ip address dhcp + duplex full + negotiation auto +! +interface GigabitEthernet3/3 + description to GigabitEthernet0/0.edge-1 + no switchport + ip address 192.168.11.2 255.255.255.252 + ip ospf 100 area 0 + duplex full + negotiation auto +! +interface Vlan10 + ip address 192.168.1.2 255.255.255.0 + standby 1 ip 192.168.1.1 +! +router ospf 100 + router-id 1.1.1.2 + passive-interface default + no passive-interface GigabitEthernet3/3 + network 192.168.1.0 0.0.0.255 area 0 +! +ip forward-protocol nd +! +no ip http server +no ip http secure-server +! +ip ssh server algorithm encryption aes128-ctr aes192-ctr aes256-ctr +ip ssh client algorithm encryption aes128-ctr aes192-ctr aes256-ctr +! +! +! +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +! +end \ No newline at end of file diff --git a/config_gen/templates/sw-2.j2 b/config_gen/templates/sw-2.j2 new file mode 100644 index 0000000..8029af0 --- /dev/null +++ b/config_gen/templates/sw-2.j2 @@ -0,0 +1,259 @@ +! +! Last configuration change at 19:04:35 UTC Thu Sep 8 2022 +! +version 15.2 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +service compress-config +! +hostname sw-2 +! +boot-start-marker +boot-end-marker +! +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family +! +enable password cisco +! +no aaa new-model +! +! +! +! +! +vtp domain virl.lab +vtp mode transparent +! +! +! +no ip domain-lookup +ip cef +no ip igmp snooping +no ipv6 cef +! +! +! +spanning-tree mode pvst +spanning-tree extend system-id +! +! +vlan 2 + name ank_vlan2 +! +vlan 10 + name VLAN10 +no cdp run +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description to + no ip address + shutdown +! +interface GigabitEthernet0/0 + switchport access vlan 10 + switchport trunk allowed vlan 10 + switchport trunk encapsulation dot1q + switchport mode access + no negotiation auto +! +interface GigabitEthernet0/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet0/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet1/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/0 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/2 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet2/3 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/0 + switchport trunk encapsulation dot1q + switchport mode trunk + no negotiation auto +! +interface GigabitEthernet3/1 + description to + no switchport + no ip address + shutdown + duplex full + negotiation auto +! +interface GigabitEthernet3/2 + description to port5.mgmt-sw1 + no switchport + ip address dhcp + duplex full + negotiation auto +! +interface GigabitEthernet3/3 + description to GigabitEthernet0/0.edge-2 + no switchport + ip address 192.168.22.2 255.255.255.0 + ip ospf 100 area 0 + duplex full + negotiation auto +! +interface Vlan10 + ip address 192.168.1.3 255.255.255.0 + standby 1 ip 192.168.1.1 +! +router ospf 100 + router-id 2.2.2.2 + passive-interface default + no passive-interface GigabitEthernet3/3 + network 192.168.1.0 0.0.0.255 area 0 +! +ip forward-protocol nd +! +no ip http server +no ip http secure-server +! +ip ssh server algorithm encryption aes128-ctr aes192-ctr aes256-ctr +ip ssh client algorithm encryption aes128-ctr aes192-ctr aes256-ctr +! +! +! +! +! +! +control-plane +! +banner exec ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner incoming ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +banner login ^C +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************^C +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +! +end \ No newline at end of file diff --git a/config_gen/tests/test_routing.py b/config_gen/tests/test_routing.py new file mode 100644 index 0000000..77bee2d --- /dev/null +++ b/config_gen/tests/test_routing.py @@ -0,0 +1,92 @@ +import logging +import sys + +from pybatfish.client.asserts import ( + assert_flows_succeed, + assert_has_no_route, + assert_has_route, + assert_no_incompatible_bgp_sessions, + assert_no_incompatible_ospf_sessions, + assert_no_unestablished_bgp_sessions, + assert_num_results, +) +from pybatfish.client.commands import bf_session +from pybatfish.datamodel.flow import HeaderConstraints +from pybatfish.question import load_questions + +logging.getLogger("pybatfish").setLevel(logging.WARN) +SNAPSHOT_DIR = '/local/data' + + +def setup(): + bf_session.host = "batfish" + load_questions() + bf_session.set_network('webinar') + bf_session.init_snapshot(SNAPSHOT_DIR, name='snapshot-1', overwrite=True) + print("=" * 20) + print("Starting Batfish Setup.....") + print("=" * 20) + + +def test_protocols(assertion_str): + result = eval(assertion_str)() + if not result: + sys.exit(1) + else: + print(f"Validated {assertion_str.title().replace('_', ' ')}") + + +def test_paths(): + locations = [ + '@enter(sw-1[GigabitEthernet0/0])', + '@enter(sw-2[GigabitEthernet0/0])' + ] + for location in locations: + path_result = assert_flows_succeed( + startLocation=location, + headers=HeaderConstraints(dstIps='8.8.8.8', srcIps='192.168.1.5'), + snapshot="snapshot-1", + session=bf_session + ) + if not path_result: + sys.exit(1) + else: + print(f"Test from {location} to DNS has passed!") + + +def test_custom_checks(): + """ + - Desktop pod has no routes to security servers. + - Route to DNS must be a OSPF E2 route from Desktop pod. + - All edge- devices must have a BGP session towards an ISP in Established state. + """ + bf_routes = bf_session.q.routes().answer().frame() + result = assert_has_no_route(routes=bf_routes, expected_route="192.168.123.0/24", node="sw-1") + if not result: + sys.exit(1) + else: + print("Desktop pod has no routes to security servers. passed!") + dns_routes = bf_session.q.routes(nodes="/sw/", network="8.8.8.8/32").answer().frame() + if not dns_routes.Protocol.all() == "ospfE2": + sys.exit(1) + else: + print("Route to DNS must be a OSPF E2 route from Desktop pod. passed!") + isp_neighbors = bf_session.q.bgpEdges(nodes="/edge/", remoteNodes="/isp/").answer().frame() + isp_result = assert_num_results(isp_neighbors, 2) + if not isp_result: + sys.exit(1) + else: + print("There is always at least one BGP session towards an ISP in Established state. passed!") + + +if __name__ == "__main__": + setup() + assert_list = [ + "assert_no_unestablished_bgp_sessions", + "assert_no_incompatible_bgp_sessions", + "assert_no_incompatible_ospf_sessions" + ] + for assertion in assert_list: + test_protocols(assertion) + test_paths() + test_custom_checks() diff --git a/development/Dockerfile b/development/Dockerfile new file mode 100644 index 0000000..f5dce43 --- /dev/null +++ b/development/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.9 + +RUN pip install --upgrade pip \ + && pip install poetry + +RUN mkdir /local + +COPY . /local + +WORKDIR /local + +RUN poetry config virtualenvs.create false \ + && poetry install --no-interaction --no-ansi + +CMD /bin/bash \ No newline at end of file diff --git a/development/docker-compose.yml b/development/docker-compose.yml new file mode 100644 index 0000000..78e28cb --- /dev/null +++ b/development/docker-compose.yml @@ -0,0 +1,21 @@ +--- +version: '3.5' +services: + batfish: + container_name: batfish + image: batfish/batfish + ports: + - 9997:9997 + - 9996:9996 + batfish-routing: + container_name: batfish-routing + build: + context: ../ + dockerfile: development/Dockerfile + stdin_open: true + tty: true + depends_on: + - "batfish" + volumes: + - ../config_gen/data/configs:/local/data/configs + - ../config_gen:/local/config_gen diff --git a/docs/img/webinar-simple-topology.png b/docs/img/webinar-simple-topology.png new file mode 100644 index 0000000..cc46996 Binary files /dev/null and b/docs/img/webinar-simple-topology.png differ diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..72ca1be --- /dev/null +++ b/poetry.lock @@ -0,0 +1,640 @@ +[[package]] +name = "ansible-core" +version = "2.13.3" +description = "Radically simple IT automation" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +cryptography = "*" +jinja2 = ">=3.0.0" +packaging = "*" +PyYAML = ">=5.1" +resolvelib = ">=0.5.3,<0.9.0" + +[[package]] +name = "attrs" +version = "22.1.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"] + +[[package]] +name = "bidict" +version = "0.22.0" +description = "The bidirectional mapping library for Python." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "certifi" +version = "2022.6.15" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "configargparse" +version = "0.15.2" +description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +yaml = ["pyyaml"] + +[[package]] +name = "cryptography" +version = "38.0.1" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] + +[[package]] +name = "deepdiff" +version = "5.8.1" +description = "Deep Difference and Search of any Python object/data." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +ordered-set = ">=4.1.0,<4.2.0" + +[package.extras] +cli = ["click (==8.0.3)", "pyyaml (==5.4.1)", "toml (==0.10.2)", "clevercsv (==0.7.1)"] + +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "invoke" +version = "1.7.1" +description = "Pythonic task execution" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "netconan" +version = "0.12.3" +description = "Netconan network configuration anonymization utilities" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +bidict = "<1.0.0" +configargparse = "<1.0.0" +passlib = "<2.0.0" +six = "<2.0.0" + +[package.extras] +dev = ["flake8 (<4.0.0)", "flake8-docstrings (<2.0.0)", "pydocstyle (<4.0.0)"] +test = ["pytest (>=4.6.0,<5.0.0)", "pytest-cov (<3.0.0)", "requests-mock (<2.0.0)", "testfixtures (<7.0.0)", "zipp (<2.2)"] + +[[package]] +name = "numpy" +version = "1.23.2" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.8" + +[[package]] +name = "ordered-set" +version = "4.1.0" +description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +dev = ["pytest", "black", "mypy"] + +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + +[[package]] +name = "pandas" +version = "1.1.5" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +numpy = ">=1.15.4" +python-dateutil = ">=2.7.3" +pytz = ">=2017.2" + +[package.extras] +test = ["hypothesis (>=3.58)", "pytest-xdist", "pytest (>=4.0.2)"] + +[[package]] +name = "passlib" +version = "1.7.4" +description = "comprehensive password hashing framework supporting over 30 schemes" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +argon2 = ["argon2-cffi (>=18.2.0)"] +bcrypt = ["bcrypt (>=3.1.0)"] +build_docs = ["sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)", "cloud-sptheme (>=1.10.1)"] +totp = ["cryptography"] + +[[package]] +name = "pathspec" +version = "0.10.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pybatfish" +version = "2022.9.7.77" +description = "Python API and utilities for Batfish" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=18.1.0" +deepdiff = "*" +deprecated = "*" +netconan = ">=0.12.0" +pandas = "<1.2" +python-dateutil = "*" +PyYAML = "*" +requests = "*" +requests-toolbelt = "*" +simplejson = "*" + +[package.extras] +capirca = ["capirca", "absl-py (>=0.8.0)"] +dev = ["black (==19.10b0)", "cerberus (==1.3.2)", "check-manifest", "coverage", "inflection", "jupyter", "mypy (<0.800)", "nbconvert", "pytest (>=4.2.0)", "pytest-cov", "pytz", "requests-mock", "responses", "sphinx (>=1.8.0)", "sphinx-rtd-theme", "capirca", "absl-py (>=0.8.0)"] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["railroad-diagrams", "jinja2"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2022.2.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "0.9.1" +description = "A utility belt for advanced users of python-requests" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "resolvelib" +version = "0.8.1" +description = "Resolve abstract dependencies into concrete ones" +category = "main" +optional = false +python-versions = "*" + +[package.extras] +test = ["pytest", "packaging", "commentjson"] +release = ["twine", "towncrier", "build"] +lint = ["types-requests", "isort", "mypy", "flake8", "black"] +examples = ["requests", "pygraphviz", "packaging", "html5lib"] + +[[package]] +name = "simplejson" +version = "3.17.6" +description = "Simple, fast, extensible JSON encoder/decoder for Python" +category = "main" +optional = false +python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" + +[package.extras] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "wrapt" +version = "1.14.1" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "yamllint" +version = "1.27.1" +description = "A linter for YAML files." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pathspec = ">=0.5.3" +pyyaml = "*" + +[metadata] +lock-version = "1.1" +python-versions = "^3.9" +content-hash = "cd4f31abd77aa6679442a5d106fe9d4760cee96bb96b2d1392ffcead65e36636" + +[metadata.files] +ansible-core = [] +attrs = [] +bidict = [] +certifi = [ + {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, + {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, +] +cffi = [] +charset-normalizer = [] +configargparse = [] +cryptography = [] +deepdiff = [] +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, +] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +invoke = [ + {file = "invoke-1.7.1-py3-none-any.whl", hash = "sha256:2dc975b4f92be0c0a174ad2d063010c8a1fdb5e9389d69871001118b4fcac4fb"}, + {file = "invoke-1.7.1.tar.gz", hash = "sha256:7b6deaf585eee0a848205d0b8c0014b9bf6f287a8eb798818a642dff1df14b19"}, +] +jinja2 = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] +markupsafe = [ + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, +] +netconan = [] +numpy = [] +ordered-set = [] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] +pandas = [] +passlib = [ + {file = "passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1"}, + {file = "passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04"}, +] +pathspec = [] +pybatfish = [] +pycparser = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] +pyparsing = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [] +pyyaml = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] +requests = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] +requests-toolbelt = [] +resolvelib = [] +simplejson = [] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +urllib3 = [] +wrapt = [ + {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, + {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, + {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, + {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, + {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, + {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, + {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, + {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, + {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, + {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, + {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, + {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, + {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, + {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, + {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, + {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, + {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, + {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, + {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, + {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, + {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, + {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, + {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, + {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, + {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, + {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, + {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, + {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, + {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, + {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, + {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, + {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +] +yamllint = [] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..666f3ad --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "batfish_routing" +version = "0.1.0" +description = "" +authors = ["Jeff Kala "] + +[tool.poetry.dependencies] +python = "^3.9" +ansible-core = "^2.13.3" +pybatfish = "^2022.9.7" + +[tool.poetry.dev-dependencies] +yamllint = "^1.27.1" +toml = "^0.10.2" +invoke = "^1.7.1" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..799559e --- /dev/null +++ b/tasks.py @@ -0,0 +1,260 @@ +"""Tasks for use with Invoke.""" +import os +import sys +from distutils.util import strtobool + +from invoke import Collection +from invoke import task as invoke_task +from invoke.exceptions import Exit + +try: + import toml +except ImportError: + sys.exit("Please make sure to `pip install toml` or enable the Poetry shell and run `poetry install`.") + + +def is_truthy(arg): + """Convert "truthy" strings into Booleans. + Args: + arg (str): Truthy string (True values are y, yes, t, true, on and 1; false values are n, no, + f, false, off and 0. Raises ValueError if val is anything else. + Examples: + >>> is_truthy('yes') + True + """ + if isinstance(arg, bool): + return arg + return bool(strtobool(arg)) + + +namespace = Collection("batfish_routing") +namespace.configure( + { + "batfish_routing": { + "project_name": "batfish_routing", + "python_ver": "3.9", + "local": False, + "compose_dir": os.path.join(os.path.dirname(__file__), "development/"), + "compose_files": [ + "docker-compose.yml", + ] + } + } +) + + +def task(function=None, *args, **kwargs): + """Task decorator to override the default Invoke task decorator.""" + + def task_wrapper(function=None): + """Wrapper around invoke.task to add the task to the namespace as well.""" + if args or kwargs: + task_func = invoke_task(*args, **kwargs)(function) + else: + task_func = invoke_task(function) + namespace.add_task(task_func) + return task_func + + if function: + # The decorator was called with no arguments + return task_wrapper(function) + # The decorator was called with arguments + return task_wrapper + +PYPROJECT_CONFIG = toml.load("pyproject.toml") +TOOL_CONFIG = PYPROJECT_CONFIG["tool"]["poetry"] + +# Can be set to a separate Python version to be used for launching or building image +PYTHON_VER = os.getenv("PYTHON_VER", "3.9") +# Name of the docker image/image +IMAGE_NAME = os.getenv("IMAGE_NAME", TOOL_CONFIG["name"]) +# Tag for the image +IMAGE_VER = os.getenv("IMAGE_VER", f"{TOOL_CONFIG['version']}-py{PYTHON_VER}") +# Gather current working directory for Docker commands +PWD = os.getcwd() +# Local or Docker execution provide "local" to run locally without docker execution +INVOKE_LOCAL = is_truthy(os.getenv("INVOKE_LOCAL", False)) # pylint: disable=W1508 +# Get project name from the toml file +PROJECT_NAME = PYPROJECT_CONFIG["tool"]["poetry"]["name"] +# Get current project version from the toml file +PROJECT_VERSION = PYPROJECT_CONFIG["tool"]["poetry"]["version"] + + +def docker_compose(context, command, **kwargs): + """Helper function for running a specific docker-compose command with all appropriate parameters and environment. + Args: + context (obj): Used to run specific commands + command (str): Command string to append to the "docker-compose ..." command, such as "build", "up", etc. + **kwargs: Passed through to the context.run() call. + """ + compose_command_tokens = [ + "docker-compose", + f'--project-name "{context.batfish_routing.project_name}"', + f'--project-directory "{context.batfish_routing.compose_dir}"', + ] + + for compose_file in context.batfish_routing.compose_files: + compose_file_path = os.path.join(context.batfish_routing.compose_dir, compose_file) + compose_command_tokens.append(f'-f "{compose_file_path}"') + + compose_command_tokens.append(command) + + # If `service` was passed as a kwarg, add it to the end. + service = kwargs.pop("service", None) + if service is not None: + compose_command_tokens.append(service) + + print(f'Running docker-compose command "{command}"') + compose_command = " \\\n ".join(compose_command_tokens) + env = kwargs.pop("env", {}) + env.update({"PYTHON_VER": context.batfish_routing.python_ver}) + if "hide" not in kwargs: + env_str = " \\\n ".join(f"{var}={value}" for var, value in env.items()) + print(f"[dim]{env_str} \\\n {compose_command}[/dim]") + return context.run(compose_command, env=env, **kwargs) + + +def run_command(context, command, **kwargs): + """Wrapper to run a command locally or inside the container.""" + if is_truthy(context.batfish_routing.local): + print(f'Running command "{command}"') + context.run(command, pty=True, **kwargs) + else: + docker_compose_status = "ps --services --filter status=running" + results = docker_compose(context, docker_compose_status, hide="out") + if "batfish_routing" in results.stdout: + compose_command = f"exec batfish-routing {command}" + else: + compose_command = f"run --entrypoint '{command}' batfish-routing" + + docker_compose(context, compose_command, pty=True) + + +# ------------------------------------------------------------------------------ +# BUILD +# ------------------------------------------------------------------------------ +@task( + help={ + "force_rm": "Always remove intermediate containers.", + "cache": "Whether to use Docker's cache when building the image. (Default: enabled)", + "poetry_parallel": "Enable/disable poetry to install packages in parallel. (Default: True)", + "pull": "Whether to pull Docker images when building the image. (Default: disabled)", + } +) +def build(context, force_rm=False, cache=True, poetry_parallel=True, pull=False): + """Build batfish_routing docker image.""" + command = f"build --build-arg PYTHON_VER={context.batfish_routing.python_ver}" + + if not cache: + command += " --no-cache" + if force_rm: + command += " --force-rm" + if poetry_parallel: + command += " --build-arg POETRY_PARALLEL=true" + if pull: + command += " --pull" + + print(f"Building batfish_routing with Python {context.batfish_routing.python_ver}...") + docker_compose(context, command, env={"DOCKER_BUILDKIT": "1", "COMPOSE_DOCKER_CLI_BUILD": "1"}) + + +# ------------------------------------------------------------------------------ +# START / STOP / DEBUG +# ------------------------------------------------------------------------------ +@task(help={"service": "If specified, only affect this service."}) +def debug(context, service=None): + """Start Batfish Routing and its dependencies in debug mode.""" + print("Starting Batfish Routing in debug mode...") + docker_compose(context, "up", service=service) + + +@task(help={"service": "If specified, only affect this service."}) +def start(context, service=None): + """Start Batfish Routing and its dependencies in detached mode.""" + print("Starting Batfish Routing in detached mode...") + docker_compose(context, "up --detach", service=service) + + +@task(help={"service": "If specified, only affect this service."}) +def restart(context, service=None): + """Gracefully restart containers.""" + print("Restarting Batfish Routing...") + docker_compose(context, "restart", service=service) + + +@task(help={"service": "If specified, only affect this service."}) +def stop(context, service=None): + """Stop Batfish Routing and its dependencies.""" + print("Stopping Batfish Routing...") + if not service: + docker_compose(context, "down") + else: + docker_compose(context, "stop", service=service) + + +@task +def clean(context): + """Remove the project specific image. + Args: + context (obj): Used to run specific commands + """ + print(f"Attempting to forcefully remove image {IMAGE_NAME}:{IMAGE_VER}") + context.run(f"docker rmi {IMAGE_NAME}:{IMAGE_VER} --force") + print(f"Successfully removed image {IMAGE_NAME}:{IMAGE_VER}") + + +@task +def rebuild(context): + """Clean the Docker image and then rebuild without using cache. + Args: + context (obj): Used to run specific commands + """ + clean(context) + build(context) + +@task +def yamllint(context): + """Run yamllint to validate formatting adheres to NTC defined YAML standards. + Args: + context (obj): Used to run specific commands + local (bool): Define as `True` to execute locally + """ + exec_cmd = "yamllint ." + run_command(context, exec_cmd) + + +@task +def generate_configurations(context): + """Run ansible playbook to generate configurations + Args: + context (obj): Used to run specific commands + local (bool): Define as `True` to execute locally + """ + exec_cmd = "ansible-playbook /local/config_gen/pb_generate_configs.yml -i /local/config_gen/inventory.yml" + run_command(context, exec_cmd) + + +@task +def test_configurations(context): + """Run ansible playbook to generate configurations + Args: + context (obj): Used to run specific commands + local (bool): Define as `True` to execute locally + """ + exec_cmd = "python /local/config_gen/tests/test_routing.py" + run_command(context, exec_cmd) + + +@task(help={"service": "Name of the service to shell into"}) +def cli(context, service="batfish-routing"): + """Launch a bash shell inside the running batfish-routing (or other) Docker container.""" + docker_compose(context, f"exec {service} bash", pty=True) + + +@task +def tests(context): + """Run all linters and unit tests.""" + yamllint(context) + generate_configurations(context) + test_configurations(context) + print("All tests have passed!")