{"id":13821361,"url":"https://github.com/Vista-Technology/netops-quickstart","last_synced_at":"2025-05-16T12:33:25.066Z","repository":{"id":171321844,"uuid":"369485561","full_name":"Vista-Technology/netops-quickstart","owner":"Vista-Technology","description":"NetOps Quickstart","archived":false,"fork":false,"pushed_at":"2023-11-29T17:01:49.000Z","size":11971,"stargazers_count":17,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-19T21:36:03.680Z","etag":null,"topics":["ansible","arista-ceos","arista-networks","automation","cicd","cloud-native","devops","gitlab-ci","monitoring","netops","network","network-programming","networking","telemetry"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Vista-Technology.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-21T09:36:33.000Z","updated_at":"2024-01-03T20:23:47.000Z","dependencies_parsed_at":"2024-05-29T15:07:39.725Z","dependency_job_id":null,"html_url":"https://github.com/Vista-Technology/netops-quickstart","commit_stats":null,"previous_names":["vista-technology/netops-quickstart"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vista-Technology%2Fnetops-quickstart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vista-Technology%2Fnetops-quickstart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vista-Technology%2Fnetops-quickstart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vista-Technology%2Fnetops-quickstart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vista-Technology","download_url":"https://codeload.github.com/Vista-Technology/netops-quickstart/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254530651,"owners_count":22086653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","arista-ceos","arista-networks","automation","cicd","cloud-native","devops","gitlab-ci","monitoring","netops","network","network-programming","networking","telemetry"],"created_at":"2024-08-04T08:01:20.669Z","updated_at":"2025-05-16T12:33:20.056Z","avatar_url":"https://github.com/Vista-Technology.png","language":"Python","readme":"# NetOps Quickstart\n\nThis is a DEMO project (thus, do not use in production environment) with the purpose of giving on overview on some example tools, methods and procedures focused on NetOps best practice.\n\nThis work is based on and is inspired by the beautiful work of [networkop](https://github.com/networkop), in his repo [https://github.com/networkop/arista-network-ci](https://github.com/networkop/arista-network-ci)\n\nWe've tried to put everything together in an all-in-one stack deployment, from code to network devices, passing passing through automation playbooks, validation and testing.\n\nIt is important to say that this is not THE Solution (with capitol S), but a possible approach that can be helpful to understand the power of NetOps and give some initial spark to those who want to investigate this subject for the first time.\n\nWe focus on the main goals of NetOps methodology, in a closed-loop telemetry/automation model:\n* **Infrascruture as Code** (aka IaC)\n* **Versioning**\n* **Automation**\n* **Monitoring**\n\n# Components\n\nBelow an architecture on our DEMO environment, the tools we have chosen and the connections between them:\n\n| ![Stack](docs/imgs/stack.png) |\n|:--:| \n| *NetOps Stack* |\n\n\u003e Note: All the tools in this architecture are deployed using Docker and Docker-compose\n\n## Arista cEOS Topology\n\nWe are testing our environment with a simple 3-nodes Spine/Leaf topology. We have chosen rely on [Arista](https://www.arista.com/en/) technology beacuse of the flexibility and semplicity they provide. In fact we are using containerized EOS images in conjunctions with [Docker-topo NG](https://github.com/Vista-Technology/docker-topo-ng), a software that allows you to replicate a network topology using docker technologies.\n\nWe also added to Host nodes, one per Leaf, useful to test network connectivity if everything is ok.\n\n## Gitalb CI/CD\n\nWe are using [Gitlab](https://about.gitlab.com/) for 2 reasons:\n* **GIT** versioning \n    * for IaC definitions of network devices\n    * for automation playbooks\n* Embedded **DevOps** functionality\n    * CI/CD Piepline triggers and definitions\n\nOur Gitlab project is composed by:\n* **automation** folder\n    * contains al Ansible-related files and folders\n* **config** folder\n    * contains the YAML definitions of the 3 devices\n* **gitlab-ci.yml** file\n    * describe the CI/CD process that take place on every change\n\nThe 3 network devices are described using YAML definitions, in order to respect **Infrastructure as Code** best practice, as follows:\n\n```yaml\n## Leaf-1\n\ninterfaces:\n  - name: Ethernet1\n    ipv4: 10.0.254.1/31\nrouterid: 1.1.1.1/32\nbgp:\n  asn: 65001\n  neighbours: \n    - ipv4: 10.0.254.0\n      remote_asn: 65100\nvlan:\n  id: 10\n  svi: 192.168.10.1/24\n  interface: Ethernet10\n```\n\n```yaml\n## Leaf-2\n\ninterfaces:\n  - name: Ethernet1\n    ipv4: 10.0.254.3/31\nrouterid: 1.1.1.2/32\nbgp:\n  asn: 65002\n  neighbours: \n    - ipv4: 10.0.254.2\n      remote_asn: 65100\nvlan:\n  id: 20\n  svi: 192.168.20.1/24\n  interface: Ethernet10\n```\n\n```yaml\n## Spine-1\n\ninterfaces:\n  - name: Ethernet1\n    ipv4: 10.0.254.0/31\n  - name: Ethernet2\n    ipv4: 10.0.254.2/31\nrouterid: 1.1.1.100/32\nbgp:\n  asn: 65100\n  neighbours:\n    - ipv4: 10.0.254.1\n      remote_asn: 65001\n    - ipv4: 10.0.254.3\n      remote_asn: 65002\n```\n\n## Ansible\nWe make use of 3 simple, demostrative, [Ansible](https://www.ansible.com/) playbooks to perform all the **automation** staff.\n\n\u003e Note: Even the creating process of all the demo environment is built with Ansible\n\nAnsible automation is launched by the Gitlan pipeline. We have devided all the stuff in 3 topics:\n* Automatically launch **validation** processes\n  * _playbooks/validate.yaml_\n* Auotmatically deploy **configurations** on devices, and configure the monitoring stack\n  * _playbooks/intended.yaml_\n* Automatically **test** the final environment\n  * _playbooks/ping.yaml_\n\nInside the _automation_ folder of this project you can find all files related to Ansible automation, regarding the NetOps process.\nWe use some collections and roles to perform the tasks (as you can see in the _requirements.yaml_ file):\n* Collections:\n  * lvrfrc87.git_acp\n  * arista.eos\n* Roles:\n  * batfish.base\n\nAs you can see, the _host_vars_ folder is empty. It will be filled with **IaC** configuration declarations by the Gitlab **pipeline**.\n\nThe arista.eos collection is the key to perform configuration deployment on the devices\n\n```yaml\n---\n- name: Configure device\n  arista.eos.eos_config:\n    src: template-config-all.j2\n    replace: config\n    match: none\n```\nWe use a jinja2 template, filled with IaC variables, to get the final configuration\n\n```python\n!\nhostname {{ inventory_hostname }}\n!\nspanning-tree mode mstp\n!\nno aaa root\n!\naaa authorization exec default local\n!\nusername {{ management.username }} privilege 15 secret sha512 {{ management.password }}\n!\nip access-list def2\n   9 permit tcp any any eq 8080\n   10 permit icmp any any\n   20 permit ip any any tracked\n   30 permit udp any any eq bfd ttl eq 255\n   40 permit udp any any eq bfd-echo ttl eq 254\n   50 permit udp any any eq multihop-bfd\n   60 permit udp any any eq micro-bfd\n   70 permit ospf any any\n   80 permit tcp any any eq ssh telnet www snmp bgp https msdp ldp netconf-ssh gnmi\n   90 permit udp any any eq bootps bootpc snmp rip ntp ldp\n   100 permit tcp any any eq mlag ttl eq 255\n   110 permit udp any any eq mlag ttl eq 255\n   120 permit vrrp any any\n   130 permit ahp any any\n   140 permit pim any any\n   150 permit igmp any any\n   160 permit tcp any any range 5900 5910\n   170 permit tcp any any range 50000 50100\n   180 permit udp any any range 51000 51100\n   190 permit tcp any any eq 3333\n   200 permit tcp any any eq nat ttl eq 255\n   210 permit tcp any eq bgp any\n   220 permit rsvp any any\n   exit\n!\nmanagement api http-commands\n   no shutdown\n   exit\n{% for intf in interfaces %}\n!\ninterface {{ intf.name }}\n   no switchport\n   ip address {{ intf.ipv4 }}\n   exit\n{% endfor %}\n!\n{% if vlan is defined %}\nvlan {{ vlan.id }}\n!\ninterface Vlan{{ vlan.id }}\n   ip address {{ vlan.svi }}\n   exit\n!\ninterface {{ vlan.interface }}\n   switchport\n   switchport mode access \n   switchport access vlan {{ vlan.id }}\n   exit\n{% endif %}\n{% if bgp is defined %}\n!\nip routing\n!\nroute-map RMAP-CONNECTED-BGP permit 1000\n!\ninterface Loopback0\n   description ROUTER-ID\n   ip address {{ routerid }}\n   exit\n!\nrouter bgp {{ bgp.asn }}\n{% set rid = routerid.split('/') %}\n   router-id {{ rid[0] }}\n{% for neighbor in bgp.neighbours %}\n{% set peer_ip = neighbor.ipv4 | ipaddr('address')  %}\n   neighbor {{ peer_ip }} remote-as {{ neighbor.remote_asn }}\n   neighbor {{ peer_ip }} send-community\n   neighbor {{ peer_ip }} maximum-routes 12000\n{% endfor %}\n   redistribute connected route-map RMAP-CONNECTED-BGP\n   maximum-paths 2\n   exit\n!\n{% endif %}\n!\nsystem control-plane\n   ip access-group def2 in\n   exit\n!\ndaemon TerminAttr\n   exec /usr/bin/TerminAttr -disableaaa\n   no shutdown\n   exit\n!\ndaemon ocprometheus\n   exec /mnt/flash/ocprometheus -config /mnt/flash/ocprometheus.yml -addr localhost:6042\n   no shutdown\n   exit\n!\nlogging host {{ logging_remote_host }} {{ logging_remote_port }} protocol tcp\nlogging format hostname fqdn\n!\nend\n\n```\n\n## Batfish\n[Batfish](https://www.batfish.org/) is an open source **network configuration analysis** tool.\n\nWe have deployed a Batfish server inside our stack and we run some simple demostrative **validation** against it. As described before, we run this validations using Ansible automation.\n\nFor example, we want to validate BGP neighbourship\n```yaml\n- name: Generate intended config to test\n  template:\n    src: config.j2\n    dest: \"validation/workshop/configs/{{inventory_hostname}}\"\n\n- name: Setup connection to Batfish service\n  bf_session:\n    host: localhost\n    name: local_batfish\n  delegate_to: localhost\n  run_once: true\n\n- name: Initialize the example network\n  bf_init_snapshot:\n    network: workshop\n    snapshot: workshop\n    snapshot_data: ../validation/workshop\n    overwrite: true\n  run_once: true\n  delegate_to: localhost\n\n- name: Retrieve Batfish Facts\n  bf_extract_facts:\n    output_directory: ../validation/workshop/data/bf_facts\n  register: bf_facts\n  run_once: true\n  delegate_to: localhost\n\n- name: Display neighbourships for all nodes\n  debug:\n    msg: \" {{item.value.BGP.Neighbors}} \"\n  with_dict: \"{{bf_facts.result.nodes}}\"\n  loop_control:\n    label: \"{{item.key}}.BGP.Neighbors\"\n  run_once: true\n  delegate_to: localhost\n\n- name: Validate the configuration of network devices\n  bf_assert:\n    assertions:\n      - type: assert_no_undefined_references\n        name: Confirm that there are NO undefined references on any network device\n      - type: assert_no_incompatible_bgp_sessions\n        name: Confirm that all BGP peers are properly configured\n      - type: assert_no_unestablished_bgp_sessions\n        name: Confirm that all compatible BGP peers establish sessions\n  run_once: true\n  delegate_to: localhost\n```\n\n## Consul\nWe have introduced [Consul]() simply to simulate a **service discovery** component inside our **automation** stack.\n\nThis kind of objects are very usefull when we have to deal with automation tasks. In this way, within the _intended.yaml_ playbook, we can *register* a device to be monitored by the monitoring tools without specify any further configuration inside Prometheus\n\n```yaml\n---\n- name: Register Consul service\n  community.general.consul:\n    service_name: \"Arista Monitoring\"\n    service_port: \"{{ metrics_port }}\"\n    service_id: \"{{ inventory_hostname }}\"\n    service_address: \"{{ ansible_host }}\"\n    host: \"{{ consul_host }}\"\n    tags: \n      - \"_device={{ inventory_hostname }}\"\n```\n\nPrometheus itself has a service discovery plugin to be able to get hosts from registered device inside Consul.\n\n## Prometheus, Loki and Grafana\nFinally, as a complete Monitoring/Telemetry/Log aggregation stack we have chosen:\n* [Prometheus](https://prometheus.io/)\n  * scrapes metrics information of the Arista devices, both directly (thanks to OCPrometheus daemon inside EOS) and via custom eAPI exporter (just for demonstration sake, it is absolutely not necessary to run both mechanisms)\n* [Loki](https://grafana.com/oss/loki/)\n  * scrapes devices logs, through the help of [Promtail](https://grafana.com/docs/loki/latest/clients/promtail/) (make log available for scraping) component and [Syslog-NG](https://www.syslog-ng.com/) ( first catches and parses logs)\n* [Grafana](https://grafana.com/oss/grafana/)\n  * provides visualization dashboards\n\n# CI/CD Process\n\n| ![CI/CD Pipeline](docs/imgs/pipeline.png) |\n|:--:| \n| *CI/CD Pipeline detail* |\nWe use the default CI/CD mechanism inside Gitlab to perform the pipeline process.\n\nTherefore we provide a simple _.gitlab-ci.yml_ file that describes all the stages\n```yaml\nstages:\n  - validate\n  - deploy\n  - test\n\nbatfish-validation:\n  stage: validate\n  script:\n    - chmod 755 automation\n    - cp configs/*.yml automation/host_vars/\n    - cd automation\n    - ansible-galaxy install -r requirements.yml\n    - ansible-playbook -e 'ansible_python_interpreter=/usr/bin/python3' playbooks/validate.yaml\n\ndeploy-configurations:\n  stage: deploy\n  script:\n    - chmod 755 automation\n    - cp configs/*.yml automation/host_vars/\n    - cd automation\n    - ansible-galaxy install -r requirements.yml\n    - ansible-playbook -e 'ansible_python_interpreter=/usr/bin/python3' playbooks/intended.yaml\n\nping-test:\n  stage: test\n  script:\n    - chmod 755 automation\n    - cp configs/*.yml automation/host_vars/\n    - cd automation\n    - chmod 400 demo.key\n    - ansible-galaxy install -r requirements.yml\n    - ansible-playbook -e 'ansible_python_interpreter=/usr/bin/python3' playbooks/ping.yaml\n```\nWe have build a custom docker image that the runner can use to perform tasks inside stages. It containes all the softwares necessary.\n\n# Pre-requisite\nYou can run all the demo environment inside a single Linux-based host.\n\nWe recommend to use a not-too-old linux distribution, with at least  4 CPUs and 16GB RAM.\n\nThis softwares has to be present before launch the installation:\n* python3\n* pip3\n* Python virtualenv\n* docker\n\n# How to install\nFirst clone this repository on your server and chanage directory inside the root.\n\nThen create the virtualenv and install all the python requirements (this action could takes long to finish)\n\n```console\nfoo@bar:~$ cd netops-quickstart\nfoo@bar:~$ virtualenv .venv\nfoo@bar:~$ source .venv/bin/activate\n(.venv)foo@bar:~$ cd build\n(.venv)foo@bar:~$ pip install -r requirements.txt\n```\n\nDownload from Arista portal the latest cEOS images and put it inside the topology folder, with the name _cEOS-Lab.tar.xz_\n\n```console\n(.venv)foo@bar:~$ ls -al topology\n\ntotal 391776\ndrwxrwxr-x 4 ubuntu ubuntu      4096 May  7 15:17 .\ndrwxrwxr-x 8 ubuntu ubuntu      4096 May  7 14:28 ..\ndrwxrwxr-x 2 ubuntu ubuntu      4096 May  7 15:15 alpine-host\n-rw-r--r-- 1 ubuntu ubuntu 401152996 May  7 15:13 cEOS-Lab.tar.xz\ndrwxrwxr-x 2 ubuntu ubuntu      4096 May  7 15:17 configs\n-rw-rw-r-- 1 ubuntu ubuntu       638 May  7 14:28 topology.yaml\n```\n\nNow within the virtual environment you can launch Ansible automation that builds all the infrastructure (it will takes approximately 7/8 minutes)\n\n```console\n(.venv)foo@bar:~$ ansible-playbook build.yml\n\n\nPLAY [lab] *************************************************************************************************************************************************************************\n\nTASK [build : Generate SSH key pair for Hosts in topology] *************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [build : Build Host docker image] *********************************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [build : Import \u0026 Build cEOS image] *******************************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [build : Generate Arista configuration from templates] ************************************************************************************************************************\nchanged: [Spine-1]\nchanged: [Leaf-1]\nchanged: [Leaf-2]\n\nTASK [build : Start Arista topology] ***********************************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [build : Pause for 30 seconds to topology creation] ***************************************************************************************************************************\nPausing for 30 seconds\n(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)\nok: [Spine-1]\n\nTASK [build : Copy OCPrometheus binary and configuration] **************************************************************************************************************************\nchanged: [Spine-1]\nchanged: [Leaf-1]\nchanged: [Leaf-2]\n\nTASK [build : Pause for 90 seconds to topology up \u0026 running] ***********************************************************************************************************************\nPausing for 90 seconds\n(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)\nok: [Spine-1]\n\nTASK [build : Build Network CI/CD docker image for Gitlab Runner] ******************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [build : Start all stack architecture] ****************************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [build : Pause for 3 minutes, waiting for the stack comes up] *****************************************************************************************************************\nPausing for 180 seconds\n(ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)\nok: [Spine-1]\n\nTASK [build : Register Gitlab Runner] **********************************************************************************************************************************************\nchanged: [Spine-1]\n\nPLAY RECAP *************************************************************************************************************************************************************************\nLeaf-1                     : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\nLeaf-2                     : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\nSpine-1                    : ok=12   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\n\n```\n\nAt the end of the playbook you will have this situation\n\n```console\n(.venv)foo@bar:~$ docker ps\n\nCONTAINER ID   IMAGE                         COMMAND                  CREATED          STATUS                   PORTS                                                                                                                                                                                                                                       NAMES\n605125504e40   grafana/loki:latest           \"/usr/bin/loki -conf…\"   5 minutes ago    Up 5 minutes             0.0.0.0:3100-\u003e3100/tcp, :::3100-\u003e3100/tcp                                                                                                                                                                                                   loki\n54d06e721082   prom/prometheus:latest        \"/bin/prometheus --w…\"   5 minutes ago    Up 5 minutes             0.0.0.0:9090-\u003e9090/tcp, :::9090-\u003e9090/tcp                                                                                                                                                                                                   prometheus\n49a918ab0d36   arista-eapi-exporter          \"python -u ./main.py\"    5 minutes ago    Up 5 minutes             0.0.0.0:9200-\u003e9200/tcp, :::9200-\u003e9200/tcp                                                                                                                                                                                                   arista-eapi-exporter\n01c192a0744b   gitlab/gitlab-ce:latest       \"/assets/wrapper\"        5 minutes ago    Up 5 minutes (healthy)   80/tcp, 443/tcp, 0.0.0.0:8822-\u003e22/tcp, :::8822-\u003e22/tcp, 0.0.0.0:8888-\u003e9080/tcp, :::8888-\u003e9080/tcp                                                                                                                                           gitlab-lab\n1785c34d6fec   gitlab/gitlab-runner:latest   \"/usr/bin/dumb-init …\"   5 minutes ago    Up 5 minutes                                                                                                                                                                                                                                                         runner-lab\n9af5d52d0f5f   grafana/grafana:latest        \"/run.sh\"                5 minutes ago    Up 5 minutes             0.0.0.0:3000-\u003e3000/tcp, :::3000-\u003e3000/tcp                                                                                                                                                                                                   grafana\nacc1d7780a5d   batfish/allinone              \"./wrapper.sh\"           5 minutes ago    Up 5 minutes             8888/tcp, 0.0.0.0:9996-9998-\u003e9996-9998/tcp, :::9996-9998-\u003e9996-9998/tcp                                                                                                                                                                     batfish\nf81482213ebb   bitnami/consul:1-debian-10    \"/opt/bitnami/script…\"   5 minutes ago    Up 5 minutes             0.0.0.0:8300-8301-\u003e8300-8301/tcp, :::8300-8301-\u003e8300-8301/tcp, 0.0.0.0:8500-\u003e8500/tcp, 0.0.0.0:8301-\u003e8301/udp, :::8500-\u003e8500/tcp, :::8301-\u003e8301/udp, 0.0.0.0:8600-\u003e8600/tcp, :::8600-\u003e8600/tcp, 0.0.0.0:8600-\u003e8600/udp, :::8600-\u003e8600/udp   consul\nf9690138a56e   balabit/syslog-ng             \"/usr/sbin/syslog-ng…\"   5 minutes ago    Up 5 minutes (healthy)   601/tcp, 514/udp, 6514/tcp, 0.0.0.0:51400-\u003e514/tcp, :::51400-\u003e514/tcp                                                                                                                                                                       syslog-ng\n6d81eb4cf9b4   grafana/promtail:latest       \"/usr/bin/promtail -…\"   5 minutes ago    Up 5 minutes             0.0.0.0:9080-\u003e9080/tcp, :::9080-\u003e9080/tcp, 0.0.0.0:15140-\u003e1514/tcp, :::15140-\u003e1514/tcp                                                                                                                                                      promtail\n07d00af9fd15   alpine-host:latest            \"/home/alpine/entryp…\"   12 minutes ago   Up 12 minutes            0.0.0.0:2001-\u003e22/tcp, :::2001-\u003e22/tcp, 0.0.0.0:8001-\u003e443/tcp, :::8001-\u003e443/tcp, 0.0.0.0:8881-\u003e8080/tcp, :::8881-\u003e8080/tcp                                                                                                                   lab_Host-2\n73f42929556d   alpine-host:latest            \"/home/alpine/entryp…\"   12 minutes ago   Up 12 minutes            0.0.0.0:2000-\u003e22/tcp, :::2000-\u003e22/tcp, 0.0.0.0:8000-\u003e443/tcp, :::8000-\u003e443/tcp, 0.0.0.0:8880-\u003e8080/tcp, :::8880-\u003e8080/tcp                                                                                                                   lab_Host-1\nb5b11322bbde   ceos:latest                   \"/sbin/init systemd.…\"   12 minutes ago   Up 12 minutes            0.0.0.0:2004-\u003e22/tcp, :::2004-\u003e22/tcp, 0.0.0.0:8004-\u003e443/tcp, :::8004-\u003e443/tcp, 0.0.0.0:8884-\u003e8080/tcp, :::8884-\u003e8080/tcp                                                                                                                   lab_Spine-1\n1823eb54a25f   ceos:latest                   \"/sbin/init systemd.…\"   12 minutes ago   Up 12 minutes            0.0.0.0:2003-\u003e22/tcp, :::2003-\u003e22/tcp, 0.0.0.0:8003-\u003e443/tcp, :::8003-\u003e443/tcp, 0.0.0.0:8883-\u003e8080/tcp, :::8883-\u003e8080/tcp                                                                                                                   lab_Leaf-2\n03646ccf2cf6   ceos:latest                   \"/sbin/init systemd.…\"   12 minutes ago   Up 12 minutes            0.0.0.0:2002-\u003e22/tcp, :::2002-\u003e22/tcp, 0.0.0.0:8002-\u003e443/tcp, :::8002-\u003e443/tcp, 0.0.0.0:8882-\u003e8080/tcp, :::8882-\u003e8080/tcp                                                                                                                   lab_Leaf-1\n```\n\n# Test your NetOps process\n\n## What we have done so far...\n\nNow that the whole stack is up\u0026running you can easily check if you can access this endpoints:\n* **Gitlab server**\n  * http://\\\u003cip address of your server\\\u003e:8888\n  * user: _root_\n  * password: _NetOpsVista21!_\n* **Grafana**\n  * http://\\\u003cip address of your server\\\u003e:3000\n  * user: _admin_\n  * password: _NetOps_\n* **Prometheus UI**\n  * http://\\\u003cip address of your server\\\u003e:9090\n* **Consul UI**\n  * http://\\\u003cip address of your server\\\u003e:8500\n\nYou can also access the 2 fake Hosts attached to Leafs, and check that ping between them is not working right now\n\n```console\n(.venv)foo@bar:~$ docker exec -it lab_Host-1 /bin/sh\n\n/ $ sudo ping 192.168.20.20\nPING 192.168.20.20 (192.168.20.20): 56 data bytes\n^C\n--- 192.168.20.20 ping statistics ---\n13 packets transmitted, 0 packets received, 100% packet loss\n/ $\n```\nSo, that means we still have to configure a lot of stuff on Arista devices... (no BGP configuration means no neighbourship means no network reachability between Hosts)\n\nAlso, accessing Grafana dashboard, you will see blank data\n\n| ![Grafana-empty](docs/imgs/grafana-empty.png) |\n|:--:| \n| *Grafana empty dashboard* |\n\nLet's start by creating our GIT project and prepare everything to deploy correct configurations on devices.\n\n## Let's do some magic!\n\n| ![Gitlab-login](docs/imgs/gitlab-login.png) |\n|:--:| \n| *Login to Gitlab server* |\n\n| ![Gitlab-create-project](docs/imgs/gitlab-create-project.png) |\n|:--:| \n| *Create a new project* |\n\n| ![Gitlab-project-info](docs/imgs/gitlab-project-info.png) |\n|:--:| \n| *Fill project info* |\n\n| ![Gitlab-project](docs/imgs/gitlab-project.png) |\n|:--:| \n| *TADAAA!* |\n\nNow you can clone your brand new repository and start adding stuff to you project.\n\n```console\nfoo@bar:~$ cd\nfoo@bar:~$ git clone http://\\\u003cip address of your server\\\u003e:8888/root/netops.git\n\nCloning into 'netops'...\nUsername for 'http://54.38.137.252:8888': root\nPassword for 'http://root@54.38.137.252:8888':\nremote: Enumerating objects: 3, done.\nremote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3\nUnpacking objects: 100% (3/3), 224 bytes | 224.00 KiB/s, done.\n\nfoo@bar:~$ cd netops\nfoo@bar:~$ ls -al\n\ntotal 16\ndrwxrwxr-x 3 ubuntu ubuntu 4096 May 11 13:09 .\ndrwxr-xr-x 9 ubuntu ubuntu 4096 May 11 13:09 ..\ndrwxrwxr-x 8 ubuntu ubuntu 4096 May 11 13:09 .git\n-rw-rw-r-- 1 ubuntu ubuntu   36 May 11 13:09 README.md\n```\n\nNow you can copy some files and folder from this demo repo to the new repo, as follows\n\n```console\nfoo@bar:~$ cd\nfoo@bar:~$ cp netops-quickstart/gitlab-ci.yml netops/.gitlab-ci.yml\nfoo@bar:~$ cp -r netops-quickstart/{configs,automation} netops/\nfoo@bar:~$ cd netops\nfoo@bar:~$ ls -al \n\ntotal 28\ndrwxrwxr-x 5 ubuntu ubuntu 4096 May 11 13:15 .\ndrwxr-xr-x 9 ubuntu ubuntu 4096 May 11 13:09 ..\ndrwxrwxr-x 8 ubuntu ubuntu 4096 May 11 13:09 .git\n-rw-rw-r-- 1 ubuntu ubuntu  996 May 11 13:15 .gitlab-ci.yml\n-rw-rw-r-- 1 ubuntu ubuntu   36 May 11 13:09 README.md\ndrwxrwxr-x 7 ubuntu ubuntu 4096 May 11 13:15 automation\ndrwxrwxr-x 2 ubuntu ubuntu 4096 May 11 13:15 configs\n```\n\nOne little small change: you need to insert your demo server IP address inside the inventory\n\n```yaml\nlab:\n  vars:\n    ansible_connection: network_cli\n    ansible_network_os: eos\n    ansible_user: arista\n    ansible_httpapi_pass: arista\n    ansible_ssh_pass: arista\n    ansible_password: arista\n    ansible_become: true\n    ansible_become_method: enable\n    ansible_httpapi_use_ssl: true\n    ansible_httpapi_validate_certs: false\n    logging_remote_host: \u003cinsert your server IP here\u003e #INSERT YOUR IP HERE!\n    logging_remote_port: 51400\n    consul_host: consul\n  children:\n    Spines:\n      hosts:\n        Spine-1\n    Leafs:\n      hosts:\n        Leaf-1\n        Leaf-2\ntesting:\n  vars:\n    ansible_become: true\n    ansible_user: alpine\n    ansible_ssh_private_key_file: demo.key\n  children:\n    alpine:\n      hosts:\n        Host-1:\n          ip_to_ping: 192.168.20.20\n        Host-2:\n          ip_to_ping: 192.168.10.10\n```\n\nNow it's time to add, commit and push!\n\n```console\nfoo@bar:~$ git config user.email \"admin@example.com\"\nfoo@bar:~$ git config user.name \"Administrator\" \nfoo@bar:~$ git add .\nfoo@bar:~$ git status\n\nOn branch master\nYour branch is up to date with 'origin/master'.\n\nChanges to be committed:\n  (use \"git restore --staged \u003cfile\u003e...\" to unstage)\n\tnew file:   .gitlab-ci.yml\n\tnew file:   automation/.gitignore\n\tnew file:   automation/ansible.cfg\n\tnew file:   automation/collections/.gitignore\n\tnew file:   automation/host_vars/.gitignore\n\tnew file:   automation/inventory.yml\n\tnew file:   automation/playbooks/intended.yaml\n\tnew file:   automation/playbooks/ping.yaml\n\tnew file:   automation/playbooks/validate.yaml\n\tnew file:   automation/requirements.yml\n\tnew file:   automation/roles/deploy/defaults/main.yml\n\tnew file:   automation/roles/deploy/tasks/main.yml\n\tnew file:   automation/roles/deploy/templates/template-config-all.j2\n\tnew file:   automation/roles/monitoring/tasks/main.yml\n\tnew file:   automation/roles/validate/defaults/main.yml\n\tnew file:   automation/roles/validate/tasks/main.yml\n\tnew file:   automation/roles/validate/templates/config.j2\n\tnew file:   automation/validation/workshop/configs/.gitignore\n\tnew file:   automation/validation/workshop/data/bf_facts/.gitignore\n\tnew file:   configs/Leaf-1.yml\n\tnew file:   configs/Leaf-2.yml\n\tnew file:   configs/Spine-1.yml\n\nfoo@bar:~$ git commit -m \"First commit\"\nfoo@bar:~$ git push\n\nUsername for 'http://54.38.137.252:8888': root\nPassword for 'http://root@54.38.137.252:8888':\nEnumerating objects: 42, done.\nCounting objects: 100% (42/42), done.\nDelta compression using up to 8 threads\nCompressing objects: 100% (28/28), done.\nWriting objects: 100% (41/41), 5.68 KiB | 969.00 KiB/s, done.\nTotal 41 (delta 3), reused 0 (delta 0)\nTo http://54.38.137.252:8888/root/netops.git\n   aabc023..c155808  master -\u003e master\n```\n\nAfter the push, he CI/CD pipeline will take place\n\n| ![Gitlab-pipeline](docs/imgs/gitlab-pipeline.png) |\n|:--:| \n| *Gitlab CI/CD Pipeline started* |\n\n| ![Gitlab-pipeline-progress](docs/imgs/gitlab-pipeline-progress.png) |\n|:--:| \n| *Gitlab CI/CD Pipeline stages, in progress* |\n\n| ![Gitlab-pipeline-finished](docs/imgs/gitlab-pipeline-finished.png) |\n|:--:| \n| *Gitlab CI/CD Pipeline stages, finished successfully* |\n\nWe can see the detail of the last stage, where Host-1 and Host-2 can ping each others\n\n| ![Gitlab-pipeline-stage-output](docs/imgs/gitlab-stage-detail.png) |\n|:--:| \n| *Gitlab CI/CD Pipeline stages output* |\n\nWe can also check from docker cli that now the 2 Hosts ping each others\n\n```console\n(.venv)foo@bar:~$ docker exec -it lab_Host-1 /bin/sh\n\n/ $ sudo ping 192.168.20.20\nPING 192.168.20.20 (192.168.20.20): 56 data bytes\n64 bytes from 192.168.20.20: seq=0 ttl=61 time=10.994 ms\n64 bytes from 192.168.20.20: seq=1 ttl=61 time=9.132 ms\n64 bytes from 192.168.20.20: seq=2 ttl=61 time=8.530 ms\n64 bytes from 192.168.20.20: seq=3 ttl=61 time=7.020 ms\n64 bytes from 192.168.20.20: seq=4 ttl=61 time=7.871 ms\n64 bytes from 192.168.20.20: seq=5 ttl=61 time=6.509 ms\n^C\n--- 192.168.20.20 ping statistics ---\n6 packets transmitted, 6 packets received, 0% packet loss\nround-trip min/avg/max = 6.509/8.342/10.994 ms\n```\n\nAlso Grafana dashboard now show some data and logs\n\n| ![Grafana](docs/imgs/grafana-data.png) |\n|:--:| \n| *Grafana* |\n\n## It's time to break everything...\n\nNow, let's try to voluntarily insert wrong data on IaC side. For example we could change an IP address on Leaf-2\n\n| ![IaC](docs/imgs/iac-broken.png) |\n|:--:| \n| *Insert a wrong IP (10.0.154.2 on the BGP configuration of Leaf-2)* |\n\nThe excpected behaviour is to fail the first validation step of the CI?CD pipeline.\n\nAnd in fact here it is\n\n| ![CI/CD Validation failed](docs/imgs/pipeline-failed.png) |\n|:--:| \n| *Failed on Validation stage* |\n\n| ![CI/CD Validation failed](docs/imgs/pipeline-failed-details.png) |\n|:--:| \n| *Failed on Validation stage, details* |\n\nSo it's working! Validation stage prevent something broken to arrive to production environment.\n\n# Clean up the demo stack\n\nIf you're tired of the playground you can simply clean all up by running an Ansible playbook\n\n```console\n(.venv)foo@bar:~$ cd netops-quickstart/build\n(.venv)foo@bar:~$ ansible-playbook clean_up.yml\n\nPLAY [lab] ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\n\nTASK [Destroy Arista topology] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [Destroy the stack] *********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\nchanged: [Spine-1]\n\nTASK [Prune docker stack] ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\nchanged: [Spine-1]\n\nPLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************\nSpine-1                    : ok=3    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\n\n```\n","funding_links":[],"categories":["monitoring"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FVista-Technology%2Fnetops-quickstart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FVista-Technology%2Fnetops-quickstart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FVista-Technology%2Fnetops-quickstart/lists"}