diff --git a/README.md b/README.md index 78f8298..5144bd8 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ This repository contains example code used at the SReXperts conferences. Please read the license file [here](./LICENSE) -Looking for the Hackathon? find it [here](https://hack.srexperts.net) +Looking for the Hackathon? find it [here](https://hackathon.srexperts.net) diff --git a/clab/configs/client/client.sh b/clab/configs/client/client.sh index 11839c7..bee116f 100644 --- a/clab/configs/client/client.sh +++ b/clab/configs/client/client.sh @@ -5,14 +5,14 @@ ifup -a -mkdir -p /home/user/.ssh -touch /home/user/.ssh/authorized_keys -chmod 600 /home/user/.ssh/authorized_keys -cat /tmp/authorized_keys > /home/user/.ssh/authorized_keys -chown -R user:user /home/user/.ssh +mkdir -p /home/admin/.ssh +touch /home/admin/.ssh/authorized_keys +chmod 600 /home/admin/.ssh/authorized_keys +cat /tmp/authorized_keys > /home/admin/.ssh/authorized_keys +chown -R admin:admin /home/admin/.ssh -echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers -echo "user:$USER_PASSWORD" | chpasswd +echo "admin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "admin:$USER_PASSWORD" | chpasswd # Start iperf3 server -iperf3 -s -p 5201 -D \ No newline at end of file +iperf3 -s -p 5201 -D diff --git a/clab/configs/client/interfaces-client12 b/clab/configs/client/interfaces-client12 index 0ac69e5..69a80f1 100644 --- a/clab/configs/client/interfaces-client12 +++ b/clab/configs/client/interfaces-client12 @@ -51,5 +51,5 @@ auto bond0.312 iface bond0.312 address 10.30.2.12/24 address fd00:fdfd:0:3002::12/64 - post-up ip r a 10.30.0.0/16 via 10.30.2.1 dev eth1.312 - post-up ip -6 r a fd00:fdfd::/32 via fd00:fdfd:0:3002::1 dev eth1.312 \ No newline at end of file + post-up ip r a 10.30.0.0/16 via 10.30.2.1 dev bond0.312 + post-up ip -6 r a fd00:fdfd::/32 via fd00:fdfd:0:3002::1 dev bond0.312 \ No newline at end of file diff --git a/clab/configs/dns/dns.sh b/clab/configs/dns/dns.sh index 3bdee1e..be29c2c 100644 --- a/clab/configs/dns/dns.sh +++ b/clab/configs/dns/dns.sh @@ -5,14 +5,14 @@ ifup -a -mkdir -p /home/user/.ssh -touch /home/user/.ssh/authorized_keys -chmod 600 /home/user/.ssh/authorized_keys -cat /tmp/authorized_keys > /home/user/.ssh/authorized_keys -chown -R user:user /home/user/.ssh +mkdir -p /home/admin/.ssh +touch /home/admin/.ssh/authorized_keys +chmod 600 /home/admin/.ssh/authorized_keys +cat /tmp/authorized_keys > /home/admin/.ssh/authorized_keys +chown -R admin:admin /home/admin/.ssh -echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers -echo "user:$USER_PASSWORD" | chpasswd +echo "admin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "admin:$USER_PASSWORD" | chpasswd dnsmasq diff --git a/clab/configs/netbox/config/postgres-init/srx-netbox.sql.gz b/clab/configs/netbox/config/postgres-init/srx-netbox.sql.gz index 917529d..5669b1f 100644 Binary files a/clab/configs/netbox/config/postgres-init/srx-netbox.sql.gz and b/clab/configs/netbox/config/postgres-init/srx-netbox.sql.gz differ diff --git a/clab/configs/radius/radius.sh b/clab/configs/radius/radius.sh index 6b60772..3e8f6eb 100644 --- a/clab/configs/radius/radius.sh +++ b/clab/configs/radius/radius.sh @@ -5,13 +5,13 @@ ifup -a -mkdir -p /home/user/.ssh -touch /home/user/.ssh/authorized_keys -chmod 600 /home/user/.ssh/authorized_keys -cat /tmp/authorized_keys > /home/user/.ssh/authorized_keys -chown -R user:user /home/user/.ssh +mkdir -p /home/admin/.ssh +touch /home/admin/.ssh/authorized_keys +chmod 600 /home/admin/.ssh/authorized_keys +cat /tmp/authorized_keys > /home/admin/.ssh/authorized_keys +chown -R admin:admin /home/admin/.ssh -echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers -echo "user:$USER_PASSWORD" | chpasswd +echo "admin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "admin:$USER_PASSWORD" | chpasswd /usr/sbin/radiusd -x diff --git a/clab/configs/subscribers/subscribers.sh b/clab/configs/subscribers/subscribers.sh index ceff5d5..199d704 100644 --- a/clab/configs/subscribers/subscribers.sh +++ b/clab/configs/subscribers/subscribers.sh @@ -7,11 +7,11 @@ ifup -a sudo echo '*/5 * * * * ifdown eth1.100; ifup eth1.100' > /etc/crontabs/root -mkdir -p /home/user/.ssh -touch /home/user/.ssh/authorized_keys -chmod 600 /home/user/.ssh/authorized_keys -cat /tmp/authorized_keys > /home/user/.ssh/authorized_keys -chown -R user:user /home/user/.ssh +mkdir -p /home/admin/.ssh +touch /home/admin/.ssh/authorized_keys +chmod 600 /home/admin/.ssh/authorized_keys +cat /tmp/authorized_keys > /home/admin/.ssh/authorized_keys +chown -R admin:admin /home/admin/.ssh -echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers -echo "user:$USER_PASSWORD" | chpasswd +echo "admin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "admin:$USER_PASSWORD" | chpasswd diff --git a/clab/configs/transit/client.sh b/clab/configs/transit/client.sh index 25dc194..5159e5b 100644 --- a/clab/configs/transit/client.sh +++ b/clab/configs/transit/client.sh @@ -5,14 +5,14 @@ ifup -a -mkdir -p /home/user/.ssh -touch /home/user/.ssh/authorized_keys -chmod 600 /home/user/.ssh/authorized_keys -cat /tmp/authorized_keys > /home/user/.ssh/authorized_keys -chown -R user:user /home/user/.ssh +mkdir -p /home/admin/.ssh +touch /home/admin/.ssh/authorized_keys +chmod 600 /home/admin/.ssh/authorized_keys +cat /tmp/authorized_keys > /home/admin/.ssh/authorized_keys +chown -R admin:admin /home/admin/.ssh -echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers -echo "user:$USER_PASSWORD" | chpasswd +echo "admin ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers +echo "admin:$USER_PASSWORD" | chpasswd # Download RIS data curl -fsSL https://data.ris.ripe.net/rrc00/latest-bview.gz -o /tmp/latest-bview.gz @@ -28,4 +28,4 @@ gobgp mrt inject global --no-ipv6 /tmp/latest-bview 100 gobgp mrt inject global --no-ipv4 /tmp/latest-bview 100 gobgp global rib add -a ipv6 2406:c800::/32 aspath "38016" gobgp global rib add -a ipv6 2406:c800:a1ca::/48 aspath "38016" -gobgp global rib add -a ipv6 2406:c800:e000::/48 aspath "38016" \ No newline at end of file +gobgp global rib add -a ipv6 2406:c800:e000::/48 aspath "38016" diff --git a/clab/srx.clab.yml b/clab/srx.clab.yml index edf270c..d6d574e 100644 --- a/clab/srx.clab.yml +++ b/clab/srx.clab.yml @@ -1,4 +1,3 @@ - # Copyright 2024 Nokia # Licensed under the BSD 3-Clause License. # SPDX-License-Identifier: BSD-3-Clause @@ -18,9 +17,7 @@ topology: image: vr-sros:25.3.R1 license: /opt/srexperts/license-sros25.txt nokia_srlinux: - image: ghcr.io/nokia/srlinux:24.10.4 - exec: - - bash -c "sr_cli /tools system configuration generate-checkpoint name final-config" + image: ghcr.io/nokia/srlinux:24.10.3 binds: - configs/srl/lldp-interface-descriptions.py:/opt/srlinux/eventmgr/lldp-interface-descriptions.py:ro stages: @@ -697,11 +694,11 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + prometheus: kind: linux mgmt-ipv4: 10.128.${INSTANCE_ID}.72 - image: prom/prometheus:v2.51.2 + image: quay.io/prometheus/prometheus:v2.51.2 binds: - configs/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro ports: @@ -714,7 +711,7 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + grafana: kind: linux mgmt-ipv4: 10.128.${INSTANCE_ID}.73 @@ -746,7 +743,7 @@ topology: syslog: kind: linux mgmt-ipv4: 10.128.${INSTANCE_ID}.74 - image: linuxserver/syslog-ng:4.5.0 + image: quay.io/linuxserver.io/syslog-ng:4.5.0 binds: - configs/syslog/syslog-ng.conf:/config/syslog-ng.conf:rslave - configs/syslog/log/messages:/var/log/messages:rslave @@ -759,7 +756,7 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + promtail: kind: linux mgmt-ipv4: 10.128.${INSTANCE_ID}.75 @@ -773,7 +770,7 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + loki: kind: linux mgmt-ipv4: 10.128.${INSTANCE_ID}.76 @@ -787,16 +784,16 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + ### NETBOX STACK ### netbox: kind: linux - image: netboxcommunity/netbox:v4.2-3.2.0 + image: quay.io/netboxcommunity/netbox:v4.2-3.2.0 mgmt-ipv4: 10.128.${INSTANCE_ID}.81 ports: - "8000:8080" user: unit:root - exec: + exec: - chown -R unit:root /opt/netbox/netbox/media/ - chown -R unit:root /opt/netbox/netbox/reports/ - chown -R unit:root /opt/netbox/netbox/scripts/ @@ -808,7 +805,7 @@ topology: env-files: - configs/netbox/envs/netbox.env healthcheck: - test: + test: - curl -f http://localhost:8080/login/ || exit 1 start-period: 90 timeout: 3 @@ -819,14 +816,14 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + netbox-worker: kind: linux - image: netboxcommunity/netbox:v4.2-3.2.0 + image: quay.io/netboxcommunity/netbox:v4.2-3.2.0 ports: # none mgmt-ipv4: 10.128.${INSTANCE_ID}.82 user: unit:root - exec: + exec: - chown -R unit:root /opt/netbox/netbox/media/ - chown -R unit:root /opt/netbox/netbox/reports/ - chown -R unit:root /opt/netbox/netbox/scripts/ @@ -838,8 +835,8 @@ topology: env-files: - configs/netbox/envs/netbox.env cmd: /opt/netbox/venv/bin/python /opt/netbox/netbox/manage.py rqworker - healthcheck: - test: + healthcheck: + test: - ps -aux | grep -v grep | grep -q rqworker || exit 1 start-period: 20 timeout: 3 @@ -850,14 +847,14 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + netbox-housekeeping: kind: linux - image: netboxcommunity/netbox:v4.2-3.2.0 + image: quay.io/netboxcommunity/netbox:v4.2-3.2.0 ports: # none mgmt-ipv4: 10.128.${INSTANCE_ID}.83 user: unit:root - exec: + exec: - chown -R unit:root /opt/netbox/netbox/media/ - chown -R unit:root /opt/netbox/netbox/reports/ - chown -R unit:root /opt/netbox/netbox/scripts/ @@ -870,7 +867,7 @@ topology: - configs/netbox/envs/netbox.env cmd: /opt/netbox/housekeeping.sh healthcheck: - test: + test: - ps -aux | grep -v grep | grep -q housekeeping || exit 1 start-period: 20 timeout: 3 @@ -881,41 +878,41 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + postgres: kind: linux image: postgres:17-alpine mgmt-ipv4: 10.128.${INSTANCE_ID}.84 healthcheck: - test: + test: - pg_isready -q -t 2 -d netbox -U netbox start-period: 20 timeout: 30 interval: 10 retries: 5 - env-files: + env-files: - configs/netbox/envs/postgres.env binds: - - ./configs/netbox/config/postgres-init:/docker-entrypoint-initdb.d + - ./configs/netbox/config/postgres-init:/docker-entrypoint-initdb.d labels: graph-posX: "665" graph-posY: "465" graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - + redis: kind: linux - image: valkey/valkey:8.0-alpine + image: ghcr.io/valkey-io/valkey:8.0-alpine mgmt-ipv4: 10.128.${INSTANCE_ID}.85 healthcheck: &redis-healthcheck - test: + test: - '[ $$(valkey-cli --pass "$${REDIS_PASSWORD}" ping) = ''PONG'' ]' start-period: 5 timeout: 3 interval: 1 retries: 5 - env-files: + env-files: - configs/netbox/envs/redis.env binds: - ./configs/netbox/config/redis-data:/data @@ -928,10 +925,10 @@ topology: redis-cache: kind: linux - image: valkey/valkey:8.0-alpine + image: ghcr.io/valkey-io/valkey:8.0-alpine mgmt-ipv4: 10.128.${INSTANCE_ID}.86 healthcheck: *redis-healthcheck - env-files: + env-files: - configs/netbox/envs/redis-cache.env binds: - ./configs/netbox/config/redis-cache-data:/data @@ -941,33 +938,7 @@ topology: graph-groupLabelPos: bottom-center graph-group: Network Tools graph-level: "1" - - ### DEV TOOLS ### - codeserver: - kind: linux - user: ${NOKIA_UID}:${NOKIA_GID} - mgmt-ipv4: 10.128.${INSTANCE_ID}.90 - image: ghcr.io/coder/code-server:latest - binds: - - ${HOME}:/home/coder - - /opt/srexperts/vscode-extensions:/opt/srexperts/vscode-extensions - - ./configs/coder:/entrypoint.d - - /var/run/docker.sock:/var/run/docker.sock - - /var/lib/docker/containers:/var/lib/docker/containers - - /usr/bin/containerlab:/usr/bin/containerlab:ro - - /usr/bin/docker:/usr/bin/docker:ro - ports: - - 80:8080 - env: - PASSWORD: ${EVENT_PASSWORD} - USER: ${NOKIA_UID} - labels: - graph-posX: "565" - graph-posY: "465" - graph-groupLabelPos: bottom-center - graph-group: Network Tools - graph-level: "1" - + links: # links from P1 - endpoints: ["p1:eth1", "pe1:eth1"] diff --git a/docs/eda/advanced/service-automation.md b/docs/eda/advanced/service-automation.md index 6f31fa0..89186a4 100644 --- a/docs/eda/advanced/service-automation.md +++ b/docs/eda/advanced/service-automation.md @@ -7,12 +7,12 @@ | | | | --------------------- | -------------------------------------------------------------------------------------------- | | **Short Description** | Define an EDA virtual network integrating Layer 2/3 services using Python | -| **Difficulty** | Intermediate | +| **Difficulty** | Advanced | | **Tools used** | Python, Pydantic | | **Topology Nodes** | :material-server: client11, :material-server: client12, :material-server: client13, :material-router: leaf11, :material-router: leaf12, :material-router: leaf13 | | **References** |[EDA API Guide][api-guide], [OpenAPI Swagger spec][swagger-spec], [Pydantic EDA][pydantic-eda] | -[api-guide]: https://docs.eda.dev/development/api/ +[api-guide]: https://docs.eda.dev/25.8/development/api/ [swagger-spec]: https://github.com/eda-labs/openapi [pydantic-eda]: https://github.com/eda-labs/pydantic-eda [pydantic]: https://docs.pydantic.dev/latest/ @@ -61,10 +61,10 @@ Pydantic models are commonly derived from an OpenAPI specification, which outlin This allows developers to work with EDA resources programmatically, avoiding the need to manually craft JSON or YAML definitions. -/// note | The community project [Pydantic EDA][pydantic-eda] provides the Pydantic models for EDA generated from the EDA OpenAPI specification published in the [EDA OpenAPI spec][swagger-spec] repo. +/// note | The [Pydantic EDA][pydantic-eda] community project provides the Pydantic models for EDA API. It generates them from the EDA OpenAPI specifications published in the [EDA OpenAPI spec][swagger-spec] repo. /// -Before diving into the task of creating a **Virtual Network** with Python, let's first review the basics concepts behind a Pydantic model, and for that we will use one of the most basic Units of automation: the **Interface**. +Before diving into the task of creating a **Virtual Network** with Python, let's first review the basics concepts behind a Pydantic model, and for that we will use one of the most basic units of automation - the Interface. ### Interface Pydantic Model @@ -95,7 +95,7 @@ Let's see side by side an Interface CR and it's Pydantic definition: /// tab | Interface yaml definition ```yaml -apiVersion: interfaces.eda.nokia.com/v1alpha1 +apiVersion: interfaces.eda.nokia.com/v1 kind: Interface metadata: name: leaf11-ethernet-1-49 @@ -119,7 +119,7 @@ import pydantic_eda.com.nokia.eda.interfaces.v1alpha1 as iface # (1)! def interface(ns: str, name: str) -> iface.Interface: # (2)! iface_ = iface.Interface( - apiVersion="interfaces.eda.nokia.com/v1alpha1", + apiVersion="interfaces.eda.nokia.com/v1", kind="Interface", metadata=iface.InterfaceMetadata( # (3)! name=name, @@ -171,13 +171,18 @@ Remove any Bridge Domains, Bridge Interfaces or VLANs created in the [Bridge Dom It’s highly recommended to use a code editor with Python auto-completion and suggestions enabled, as it will significantly improve your productivity and help avoid syntax errors when working with Pydantic models. /// -Clone a Github repository that provides the basic components. You can clone it in your own personal device or your dedicated cloud instance (VM) running a copy of the lab topology. +Clone the [openapi-example-python](https://github.com/eda-labs/openapi-example-python) that provides the EDA API client implemented in Python. You can clone it to your own personal device or your dedicated hackathon instance VM running the lab topology. If you're working on your local device, make sure the [uv python package manager and installer](https://github.com/astral-sh/uv) is installed beforehand. ```bash git clone -b srx-2025 https://github.com/eda-labs/openapi-example-python.git cd openapi-example-python +``` + +After you cloned the repository, initialize the virtual environment: + +```bash uv sync ``` @@ -200,7 +205,7 @@ openapi-example-python/ The `client.py` and `logging.py` files are prebuilt and ready to use. -Your task is to implement the Virtual Network definition inside the `virtualnetwork.py` file that is then referenced in the `main.py`. The `virtualnetwork.py` file has an import block that pulls in the generated Pydantic classes for the services application that contains the VirtualNetwork resource. By importing this module, you get access to the generated classes from the [OpenAPI spec for this application](https://rest.wiki/?https://raw.githubusercontent.com/eda-labs/openapi/refs/heads/main/apps/services.eda.nokia.com/v1alpha1/services.json). +Your task is to implement the Virtual Network definition inside the `virtualnetwork.py` file that is then referenced in the `main.py`. The `virtualnetwork.py` file has an import block that pulls in the generated Pydantic classes for the services application that contains the VirtualNetwork resource. By importing this module, you get access to the generated classes from the [OpenAPI spec for this application](https://rest.wiki/?https://raw.githubusercontent.com/eda-labs/openapi/refs/tags/v25.8.1/apps/services.eda.nokia.com/v1alpha1/services.json). Since you already have an idea what the virtual network resource consists of after completing the Part 3 of this challenge, you may start by typing starting to define your virtual network: @@ -220,7 +225,7 @@ If everything works correctly, you should see output similar to the following: [*]─[~/openapi-example-python] └──> python main.py [05/10/25 14:34:41] INFO Authenticating with EDA API server client.py:54 - INFO Adding 'VirtualNetwork' resource from 'services.eda.nokia.com/v1alpha1' to the 'create' transaction list client.py:101 + INFO Adding 'VirtualNetwork' resource from 'services.eda.nokia.com/v1' to the 'create' transaction list client.py:101 INFO Transaction 183 committed client.py:160 [05/10/25 14:34:43] INFO Transaction 183 state: complete client.py:166 @@ -236,7 +241,7 @@ Your function should list the specification of the bridge domains, a router, the ```python def virtualnetwork(ns: str, name: str) -> service.VirtualNetwork: vnet = service.VirtualNetwork( - apiVersion="services.eda.nokia.com/v1alpha1", + apiVersion="services.eda.nokia.com/v1", kind="VirtualNetwork", metadata=service.VirtualNetworkMetadata(name=name, namespace=ns, labels={"role": "exercise"}), spec=service.SpecModel17( diff --git a/docs/eda/beginner/allocations.md b/docs/eda/beginner/allocations.md index 2ba63e4..5561368 100644 --- a/docs/eda/beginner/allocations.md +++ b/docs/eda/beginner/allocations.md @@ -10,7 +10,7 @@ | **Tools used** | EDA UI | | **References** | [Allocation Pools documentation][allocation-docs] | -[allocation-docs]: https://docs.eda.dev/user-guide/allocation-pools/ +[allocation-docs]: https://docs.eda.dev/25.8/user-guide/allocation-pools/ One of infamous challenges of network automation lies in the domain of Network Source of Trust, often abbreviated as NSoT. Managing IP addresses, ASN numbers, VLAN IDs and tunnel indexes without a system that allows you to both manage and enforce allocations to the network elements is a recipe for network configuration drift and sleepless nights. @@ -118,7 +118,7 @@ Many resources you find in EDA will allow you to specify either a pool to select For example, when creating a VLAN resource, you can either set the VLAN ID manually, or let EDA allocate a VLAN ID from a pool of VLANs. ```yaml linenums="1" hl_lines="12-13" -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: VLAN metadata: name: macvrf-100-vlan1 @@ -210,7 +210,7 @@ You may also use Kubernetes API and `kubectl` tool available on the server insta type: example To find the resource kind for the specific allocation, find the allocation resource in the EDA UI, and switch to the YAML view of the resource to see its kind: --{{video(url='https://gitlab.com/rdodin/pics/-/wikis/uploads/9516ffe210e798b8312013c3c29b1125/CleanShot_2025-04-15_at_13.58.35.mp4')}}- +-{{video(url='https://gitlab.com/rdodin/pics/-/wikis/uploads/79d2d2257bef8afd26e7adb39366c210/CleanShot_2025-08-14_at_13.38.08.mp4')}}- Knowing the resource kind, you can use `kubectl` and list resources by its kind: @@ -220,15 +220,15 @@ kubectl -n eda get indexallocationpools /// -### Changing AS Numbering scheme +### Find Allocated ASN Numbers Now that you know what allocation pools exist in your EDA instance, it is time to find out how these pools are used. -The SReXperts 2025 topology that is deployed in the lab environment you work on uses EDA to deploy the fabric configuration over the three leafs and two spines that make up the DC1 topology. +The SReXperts 2025 topology that is deployed in the lab environment you work on used EDA to deploy the fabric configuration over the three leafs and two spines that make up the datacenter topology. -{{ diagram(url='srexperts/hackathon-diagrams/main/eda.drawio', title='EDA Managed nodes', page=0, zoom=1.5) }}- -By creating the **Fabric** resource in EDA, we configure the full underlay/overlay topology that makes it possible to create virtual networks on top of it. The Fabric configuration translates to several configuration blocks on the managed nodes: +The pre-created **Fabric** resource configured the data center underlay to make it possible to create virtual networks on top of it. In particular, the Fabric resource is responsible for the following configuration on the managed nodes: * export/import policies * network instances @@ -238,7 +238,7 @@ By creating the **Fabric** resource in EDA, we configure the full underlay/overl And all that, by submitting a single Fabric resource, that looks like in its entirety like this: -```yaml linenums="1" hl_lines="13 26 29-30 33" +```yaml linenums="1" hl_lines="14 26 29-30 33" --8<-- "eda/fabric/40_fabric.yaml" ``` @@ -246,7 +246,27 @@ Checkout the highlighted lines in the Fabric resource YAML. This is where we ref The Fabric application that processes the Fabric resource sees the referenced allocation pools and uses EDA SDK to request a next allocation for a particular resource. -In this task you are asked to change the AS Numbers used for the leaf switches in our fabric from the the 4-byte AS Number scheme to the 2-byte AS Number scheme, while keeping spines +You can check what values have been allocated from the relevant allocation pools using EQL. We are interested in the **AS Numbers** allocated for the data center switches, and as shown in the Fabric resource definition, the `srexperts-asnpool` is the allocation pool that is used to allocate AS Numbers. + +Open the Queries page and list allocated values by submitting the following EQL query: + +``` +.namespace.allocations.v1.template.instance.allocation where ( .namespace.allocations.v1.template.name = "srexperts-asnpool" ) +``` + +This query lists the allocation key that an application used to request an AS number and the associated value. + +![allocations](https://gitlab.com/rdodin/pics/-/wikis/uploads/f5dc68342bfb509e2b21866102798a3d/CleanShot_2025-08-14_at_14.45.11.webp) + +The result of this query shows that our leafs have been allocated AS numbers from the `srexperts-asnpool`, namely: + +* leaf11 - 4200001000 +* leaf12 - 4200001001 +* leaf13 - 4200001002 + +### Changing AS Numbering scheme + +In this task you are asked to change the AS Numbers used for the data center switches in our fabric from the default starting range of 4200001000 to some other 4-byte ASN range. /// details | Hints type: example @@ -259,4 +279,4 @@ If you want a more challenging task, create a new pool and reference it from the By completing these tasks you should have a basic understanding of Allocation Pools used in EDA. What are they used for, what types of pools we have in the product and how they serve different purposes. -You also learned how to change existing and create new allocation pools, and how resources reference the pools to request identifiers from them. +You also learned how to find what allocation values have been used, change existing and create new allocation pools, and how resources reference the pools to request identifiers from them. diff --git a/docs/eda/beginner/bridge-domains.md b/docs/eda/beginner/bridge-domains.md index 265ebcb..5c01827 100644 --- a/docs/eda/beginner/bridge-domains.md +++ b/docs/eda/beginner/bridge-domains.md @@ -6,9 +6,7 @@ | --------------------- | -------------------------------------------------------------------------------------------------------------------- | | **Short Description** | Creating bridge domains with EDA to achieve layer 2 connectivity | | **Difficulty** | Beginner | -| **Tools used** | / | | **Topology Nodes** | :material-server: client11, :material-server: client13, :material-router: leaf11, :material-router: leaf13 | -| **References** | / | This is the first exercise in a 4-part series around using EDA to achieve connectivity to, from, and within your datacenter. In this exercise, we will achieve layer-2 connectivity between two hosts in the same broadcast domain. @@ -52,7 +50,7 @@ Before we start, we need to verify the IP configuration on both clients. We're i To connect to the shell of the client nodes, you should connect to the server running your lab and then ssh to each node, for example, for `client11`: ```bash title="execute from the lab server" -ssh user@clab-srexperts-client11 +ssh admin@clab-srexperts-client11 ```
@@ -160,9 +158,9 @@ You will likely won't see any subinterface with VLAN 300, and that's expected, w ### Create a bridge domain -Using the "Create" button in the top-right, you can create a new bridge domain. In the center of the screen you can see all configuration options for the new bridge domain, and on the right is a YAML representation of the same. You can either fill the form fields, or edit the YAML, whatever you prefer. +In the **Virtual Networks** → **Bridge Domains** app page click the "Create" button in the top-right to create a new bridge domain. In the center of the screen you can see all configuration options for the new bridge domain, and on the right is a YAML representation of the same. You can either fill the form fields, or edit the YAML, whatever you prefer. -![Creating a bridge domain](../../images/eda/eda_bridge_domain_creation.png) +![Creating a bridge domain](https://gitlab.com/rdodin/pics/-/wikis/uploads/bf50bf63da050fbed1422e00cd2a35f6/CleanShot_2025-08-14_at_15.49.03.webp) Create a new bridge domain, so you can attach some interfaces to it in the next step. If you're not sure which value you need to pick for a particular property, you can leave the field default or empty. The most important properties are: @@ -186,7 +184,7 @@ The solution can be found below in YAML format, if you want to refer to it. You It is enough to define the Bridge Domain like this: ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: BridgeDomain metadata: name: bridge-domain-vlan300 @@ -226,7 +224,7 @@ Once you figured out what to enter in the Bridge Interface form, don't hit the * type: success ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: BridgeInterface metadata: name: client11-bridge-domain-300 @@ -251,7 +249,7 @@ Use the Dry Run functionality in EDA to check what would change if we were to co As shown in the video snippet above, you can check the diffs that the particular transaction would emit, and there you have a chance to see what node-specific configs would be pushed to which nodes if we were to commit our transaction. -/// note | The Dry Run functionality does not touch the network elements in any way. All the potential change sets are computed by EDA. Safe and Fast. +/// note | The Dry Run functionality does not touch the network elements in any way. All the potential change sets are computed by EDA. Safe and fast. /// The change set in the diff view should indicate that a subinterface with vlan-id is created on the `leaf11` switch as well as the network instance of type `mac-vrf` that this subinterface is connected to. @@ -267,7 +265,7 @@ You should be able to see the Bridge Interface status reflected in the GUI. To s You can also navigate to your bridge domain, and find out which leaf nodes are now participating in the service. -![Status of the bridge domain](../../images/eda/eda_bridge_domain_status.png) +![Status of the bridge domain](https://gitlab.com/rdodin/pics/-/wikis/uploads/7a76509bbb07f715c43a243da68490f6/CleanShot_2025-08-14_at_15.56.27.webp) ### Testing the connectivity @@ -278,7 +276,7 @@ With Bridge Domain and two Bridge Interfaces committed to the fabric, you should Connect to the server and then SSH into the client ```bash -ssh user@clab-srexperts-client11 +ssh admin@clab-srexperts-client11 ``` Once in the shell, ping client13: @@ -313,7 +311,7 @@ rtt min/avg/max/mdev = 1.915/1.915/1.915/0.000 ms Connect to the server and then SSH into the client ```bash -ssh user@clab-srexperts-client13 +ssh admin@clab-srexperts-client13 ``` Once in the shell, ping client11: @@ -389,7 +387,7 @@ If everything was configured correctly and committed, you should now be able to type: success ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: VLAN metadata: name: bridge-domain-vlan300 @@ -418,7 +416,7 @@ To ensure that everything was configured correctly, re-check the connectivity be Connect to the server and then SSH into the client ```bash -ssh user@clab-srexperts-client11 +ssh admin@clab-srexperts-client11 ``` Once in the shell, ping client13: @@ -453,7 +451,7 @@ rtt min/avg/max/mdev = 1.915/1.915/1.915/0.000 ms Connect to the server and then SSH into the client ```bash -ssh user@clab-srexperts-client13 +ssh admin@clab-srexperts-client13 ``` Once in the shell, ping client11: diff --git a/docs/eda/beginner/declarative-intents.md b/docs/eda/beginner/declarative-intents.md index c46f883..3e2a9c6 100644 --- a/docs/eda/beginner/declarative-intents.md +++ b/docs/eda/beginner/declarative-intents.md @@ -132,7 +132,11 @@ Before you proceed with creating the `ethernet-1/5` interface, let's query the i Typically you would connect to the leaf switches and run `show` commands, or use a custom script that does the same in a more automated way. But there is a better way to interrogate the network devices... -EDA comes with a built-in network-wide query engine that allows you to query the network devices in a performant and scalable way. Using the sidebar navigation, go to the **Queries** resource and paste the following in the EQL[^1] Query input field: +EDA comes with a built-in network-wide query engine that allows you to query the network devices in a performant and scalable way. Using the sidebar navigation, go to the **Queries** page: + +![queries](https://gitlab.com/rdodin/pics/-/wikis/uploads/9ba292956fa8d11b00ad27c54331f0f3/CleanShot_2025-08-14_at_12.36.21.webp) + +And paste the following in the EQL[^1] Query input field: /// warning In the query below, replace `g1` in the node name list with the group ID you have been assigned to. @@ -149,7 +153,7 @@ For example, if your group ID is 32, then the list should look like: .namespace.node.srl.interface fields [admin-state] where (.namespace.node.name in [ "g1-leaf11","g1-leaf12","g1-leaf13" ] and .namespace.node.srl.interface.name = "ethernet-1/5") ``` -![eql](https://gitlab.com/rdodin/pics/-/wikis/uploads/d6739ceef3d3e91b5f69a35d1b2d68af/CleanShot_2025-04-08_at_15.56.48_2x.png) +![eql](https://gitlab.com/rdodin/pics/-/wikis/uploads/16fb7232bd94e945142d95c58bf84a86/CleanShot_2025-08-14_at_12.48.20.webp) > While this exercise is not about EQL specifically, it is a good opportunity to leverage the power of the query engine to understand the state of the network. @@ -173,18 +177,20 @@ The form has three distinct sections, as per the screenshot above, and as a user The form has quite some number of fields, but not all of them are relevant to our task or required to be filled in. You must provide the following fields: -* Metadata -> Name: the name of the interface -* Specification -> Members: a list of the port name + node name combinations that identify what ports to configure on which nodes +1. **Metadata** → **Name**: the name of the interface resource. + This is not the name of the interface that you will see in the node's configuration, but a name of the Interface resource that will be created in EDA. + For example, since we are tasked to create an interface ethernet-1/5 on all leaf switches, for leaf11 we might want to name the interface resource as `leaf11-ethernet-1-5`. +2. **Specification** → **Members**: a list of the port name + node name combinations that identify what ports to configure on which nodes #### Interface Members If you chose to configure the interface via the form view, you have to click **+ Add** button to invoke another modal window where interface members are configured. -You will have to provide the Interface name in the sanitized format, where spaces and `/` are replaced with `-`. For instance, `ethernet-1/5` should become `ethernet-1-5`. +You will have to provide the Interface name in the normalized format, where spaces and `/` are replaced with `-`. For instance, `ethernet-1/5` should become `ethernet-1-5`. And after the interface name is sorted, you should provide the node name using the drop down menu. -![members](https://gitlab.com/rdodin/pics/-/wikis/uploads/8030869abec5a3c6464a166e8e268a96/CleanShot_2025-04-08_at_16.24.55_2x.png) +![members](https://gitlab.com/rdodin/pics/-/wikis/uploads/a29dfc7f5ab685ce55cffc35020c0a66/CleanShot_2025-08-14_at_13.16.29.webp) /// warning | When to use multiple members? You might have an urge to configure ethernet-1/5 port on multiple nodes by adding them as members, but this would be a mistake. diff --git a/docs/eda/beginner/eda-query-language.md b/docs/eda/beginner/eda-query-language.md index 7d9f97a..ae00bd5 100644 --- a/docs/eda/beginner/eda-query-language.md +++ b/docs/eda/beginner/eda-query-language.md @@ -18,9 +18,9 @@ By completing a series of tasks, you’ll gain a solid understanding of how to u ### Queries page -The easiest way to run queries is right from the UI, in the **Tools** section, simply click `Queries`. You can also use the REST API or [`edactl`](https://docs.eda.dev/user-guide/using-the-clis/#edactl) command if you prefer. +The easiest way to run queries is right from the UI, in the **Tools** section, simply click `Queries`. You can also use the REST API or [`edactl`](https://docs.eda.dev/25.8/user-guide/using-the-clis/#edactl) command if you prefer. -![Queries page](../../images/eda/eda_queries_page.png) +![Queries page](https://gitlab.com/rdodin/pics/-/wikis/uploads/9ba292956fa8d11b00ad27c54331f0f3/CleanShot_2025-08-14_at_12.36.21.webp) The Queries UI consists of a query language selector and the query input fields. The query language selector allows to switch between the Natural Language and the EQL query language. @@ -162,13 +162,13 @@ After we covered a lot of theory on the query components, the next step is ident | Path | Description | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **.cluster** | Holds information about cluster metrics and config/state engine. For example, we can get k8s pod status with `.cluster.apps.platform.metrics.namespace.pod` or we can get execution metrics of the state engine with `.cluster.state-engine.v1.script` | -| **.namespace** | The root path for all our namespaced resources. | -| .namespace.apps | Access config and state information published by the EDA Apps | -| .namespace.alarms | All the alarms raised by nodes are written in this table. For example, we can get current alarms with `.namespace.alarms.v1.current-alarm` or past ones with `.namespace.alarms.v1.alarm.history` | -| .namespace.allocations | Access EDA allocations pools information (irb indexes, ip pools, bgp asn numbers…). We can retrieve the information with `.namespace.allocations.v1.template.instance` | -| .namespace.node | Get real time access to node's config and state. For example, to get all state info about the SR Linux interfaces - `.namespace.node.srl.interface.subinterface` or display the statistics of all the interfaces with `.namespace.node.srl.interface.statistics` | -| .namespace.resources | A table that contains the state and specifications of all EDA Custom Resources. For example, we can check the health of our Fabric with `.namespace.resources.cr-status.fabrics_eda_nokia_com.v1alpha1.fabric.status` or see the list of BridgeDomains configured in our Fabric with `.namespace.resources.cr.services_eda_nokia_com.v1alpha1.bridgedomain` | -| .namespace.topologies.topology | Everything related to the Topologies tool in EDA dashboard goes here | +| .namespace | The root path for all our namespaced resources. | +| .namespace.**apps** | Access config and state information published by the EDA Apps | +| .namespace.**alarms** | All the alarms raised by nodes are written in this table. For example, we can get current alarms with `.namespace.alarms.v1.current-alarm` or past ones with `.namespace.alarms.v1.alarm.history` | +| .namespace.**allocations** | Access EDA allocations pools information (irb indexes, ip pools, bgp asn numbers…). We can retrieve the information with `.namespace.allocations.v1.template.instance` | +| .namespace.**node** | Get real time access to node's config and state. For example, to get all state info about the SR Linux interfaces - `.namespace.node.srl.interface.subinterface` or display the statistics of all the interfaces with `.namespace.node.srl.interface.statistics`
To change the network OS, simply replace the operating system name, e.g. `.namespace.node.sros` for Nokia SR OS, or `eos` for Arista EOS. | +| .namespace.**resources** | A table that contains the state and specifications of all EDA Custom Resources. For example, we can check the health of our Fabric with `.namespace.resources.cr.fabrics_eda_nokia_com.v1alpha1.fabric fields [ status.health ]` or see the list of BridgeDomains configured in our Fabric with `.namespace.resources.cr.services_eda_nokia_com.v1.bridgedomain` | +| .namespace.**topologies**.topology | Everything related to the Topologies tool in EDA dashboard goes here | ## Tasks diff --git a/docs/eda/beginner/label-based-selection.md b/docs/eda/beginner/label-based-selection.md index 491d575..66e3eb5 100644 --- a/docs/eda/beginner/label-based-selection.md +++ b/docs/eda/beginner/label-based-selection.md @@ -51,23 +51,21 @@ Have one more look at the diagram above that depicts a leaf-spine topology manag When logged into the EDA UI you can find the list of nodes managed by EDA using the left side bar navigation and selecting **Targets** → **Nodes** menu. -![nodes](https://gitlab.com/rdodin/pics/-/wikis/uploads/1ff53dfbf11061f7ecf42f00d901a96b/CleanShot_2025-04-09_at_20.49.31_2x.png) +![nodes](https://gitlab.com/rdodin/pics/-/wikis/uploads/0767987fda89074031f79ed1fadff7c0/CleanShot_2025-08-18_at_21.11.53.png) You should see the familiar node names (we call these resources **TopoNodes**) as depicted in the diagram above and the associated metadata, specification and status. In the same table view you can find the **Labels** column that shows the labels attached to each node; they are collapsed under the `+5` icon, which means there are 5 labels attached to each node and there is no space to display them all in line. If you hover over this icon you should see the list of labels, but you can also select the **Configuration View** menu element at the end of each row to see the expanded view of the TopoNode resource: -![conf view](https://gitlab.com/rdodin/pics/-/wikis/uploads/a0e58751d2a06913a79967add24a9b49/CleanShot_2025-04-09_at_20.56.20_2x.png) +![conf view](https://gitlab.com/rdodin/pics/-/wikis/uploads/91a774298684ea02949664c24321f9a3/CleanShot_2025-08-18_at_21.14.56.png) In the configuration view labels are shown expanded, and we can see all five of them listed there, each carrying our some meaning: -![labels](https://gitlab.com/rdodin/pics/-/wikis/uploads/07e690121aa6e93b13edb459ce52bd7a/CleanShot_2025-04-09_at_20.57.30_2x.png) +![labels](https://gitlab.com/rdodin/pics/-/wikis/uploads/3cce7b1dc950b392c044894f448fef40/CleanShot_2025-08-18_at_21.30.19.png) -As I selected the `leaf13` node, the important label it has attached to it is: +For the selected `leaf13` node, the important label it has attached to it is: -- `eda.nokia.com/role = leaf` - this label carries out the role of the node in the topology - -> This label has a key - `eda.nokia.com/role` and a value - `leaf`. +- `eda.nokia.com/role = leaf` - this label carries out the role of the node in the topology and has a key - `eda.nokia.com/role` and a value - `leaf`. When onboarding the nodes of the topology to EDA we manually assigned labels to each nodes to identify their role and make it possible for EDA to select the nodes for the intents based on these labels. diff --git a/docs/eda/beginner/notifications.md b/docs/eda/beginner/notifications.md index 9f8d828..656ad1a 100644 --- a/docs/eda/beginner/notifications.md +++ b/docs/eda/beginner/notifications.md @@ -9,14 +9,14 @@ | **Topology Nodes** | :material-router: leaf1 | | **References** | [Notifier App documentation][notifier-docs] | -[notifier-docs]: https://docs.eda.dev/apps/notifier/ +[notifier-docs]: https://docs.eda.dev/25.8/apps/notifier/ Modern day data center management is far from only dealing with configuration provisioning. More so, the day2+ operations are what teams are dealing with most of the time. Things like monitoring, alarm management and notifications come to mind. EDA is not only the powerful configuration management platform, but is also no stranger to operations. It packs a powerful set of applications and integrations to simplify operations and extend the core set of capabilities. -This exercise introduces you to the EDA [**Notifier**](https://docs.eda.dev/apps/notifier/) application that allows an operator to create custom notifications based on the events registered by EDA and deliver them to popular notification and chat systems. +This exercise introduces you to the EDA [**Notifier**][notifier-docs] application that allows an operator to create custom notifications based on the events registered by EDA and deliver them to popular notification and chat systems. ## Objective @@ -35,7 +35,7 @@ Before jumping into the exercise, let's clarify what we consider an event in EDA As the name suggests, EDA - Event Driven Automation - is all about events, but what does it really mean? In a nutshell it means that all internal EDA processes are triggered by different kinds of events happening in and outside of the EDA system. EDA is a system of event producers and consumers, where everything is based on event streaming and asynchronous communication. -For example, if a transceiver dies and triggers the port to go down, this event will be immediately available in EDA thanks to streaming telemetry. Once the event of a port changing its state from UP to DOWN is available in the EDA system, all the applications that registered themselves as a consumer for such events will start and work on the basis of this event. +For example, if a transceiver dies and triggers a port to go down, this event will be immediately available in EDA thanks to streaming telemetry. Once the event of a port changing its state from UP to DOWN is available in the EDA system, all the applications that registered themselves as a consumer for such events will start and work on the basis of this event. For example: - an Interface application that is in charge of the interfaces will raise an appropriate alarm @@ -52,7 +52,7 @@ One such application - [Notifier][notifier-docs] - was written by Nokia to unloc When the Notifier app is installed, it extends the EDA API with the new Resources (aka Intents)[^1]: 1. **Notifier** - Allows an operator to configure which events/sources to use to create notification messages. Can be either a list of alarms, or a list of EQL queries. Notifier resource can act on sources from the namespace it is created in. + Allows an operator to configure which events/sources to use to create notification messages. Can be either a list of alarms, or a list of [EQL queries](eda-query-language.md). Notifier resource can act on sources from the namespace it is created in. The `ClusterNotifier` resource is a cluster-scoped version of the Notifier resource that can act on sources from all namespaces. @@ -141,7 +141,7 @@ You are tasked with configuring the Notifier app to send Interface Up/Down alarm #### Configuring the Discord Provider Start with configuring the Discord Provider. In the context of the Notifier app, a Provider resource configures the destination where alarms can be sent. -You can configure many [different providers](https://docs.eda.dev/apps/notifier/#providers) in the Notifier app, but for this task we will use Discord, as it is easy to set up in a short amount of time we have. +You can configure many [different providers](https://docs.eda.dev/25.8/apps/notifier/#notification-destination) in the Notifier app such as Discord, Teams, Telegram, etc., but for this task we will use Discord, as it is easy and quick to set it up. ##### Logging in to Discord @@ -149,14 +149,14 @@ Naturally, you will need to log in to Discord to see the notifications popping u To join the EDA Discord server follow this link - **https://eda.dev/discord** -After choosing the username, you should see a list of channels, where one of them is named `srx-hackathon-notifier`. There we will send our notifications. +After choosing the username, you should see a list of channels with one of them being named **# srx-hackathon-notifier**. This is where we will send our notifications. ##### Create Provider resource As part of this exercise, no matter what group you're assigned to, you get a Discord webhook link from us that is associated with the channel `srx-hackathon-notifier`. ``` -https://discord.com/api/webhooks/1356633431169302688/1eigFh5nBoSRYkIU93OmkVll8xo8uEoCYvOQrEiRwjCTPvDt0E5Ntpg4D5MlU3k9q3dV +https://discord.com/api/webhooks/1405656591650394193/qfNUUL1rN39szP608GDPMUPqBmhmwWTMRasWY36mS9QmWY24j118CFuyWA7xfArAmKfF ``` In the EDA UI sidebar find the **Notifier** group and choose the **Provider** menu item. Next open the Provider resource form by clicking on the Create button: @@ -184,7 +184,7 @@ metadata: spec: enabled: true uri: >- - discord://discord.com/api/webhooks/1356633431169302688/1eigFh5nBoSRYkIU93OmkVll8xo8uEoCYvOQrEiRwjCTPvDt0E5Ntpg4D5MlU3k9q3dV + discord://discord.com/api/webhooks/1405656591650394193/qfNUUL1rN39szP608GDPMUPqBmhmwWTMRasWY36mS9QmWY24j118CFuyWA7xfArAmKfF ``` /// @@ -210,11 +210,11 @@ spec: As the field's name suggest, we might want to include some alarms in the `include` list, but what exactly we need to type there? -To answer this question, have a look at the Alarms page in the EDA UI: +To answer this question, we have to look at the Alarms page in the EDA UI. In the side menu select **Alarms** from the SYSTEM category and in the Alarms dashboard click on the **View** link in the **Active Application Alarms** panel. -![pic2](https://gitlab.com/rdodin/pics/-/wikis/uploads/db3b7fdf33e594f295b2cdac586d6e32/CleanShot_2025-04-01_at_15.22.51_2x.png) +![pic2](https://gitlab.com/rdodin/pics/-/wikis/uploads/102151a88c925ca06acfbf6fb4088260/CleanShot_2025-08-20_at_13.34.13.webp) -What you see in the Type column is the Alarm Type, and the Notifier app expects you to provide this value in the `.spec.alarms.include` field. Great, one piece of a puzzle solved. But there may be many alarm types in your list, and none of them may be relevant to the interface state we are after. +What you see in the **Type** column is the Alarm Type, and the Notifier app expects you to provide this value in the `.spec.alarms.include` field. Great, one piece of a puzzle solved. But there may be many alarm types in your list, and none of them may be relevant to the interface state we are after. We need to find the relevant Alarm Type that is raised when an interface goes Up->Down or Down->Up. In future, EDA docs will have a list of alarms published, but until then, let's shut one interface down and monitor the list of alarms. @@ -244,7 +244,7 @@ All changes have been committed. Leaving candidate mode. Now have a look at the alarm list again and filter on the Last Changed column to have most recent events appear on top. You will -![pic3](https://gitlab.com/rdodin/pics/-/wikis/uploads/93c13dc4a9be61ad71be0c918ebbd612/CleanShot_2025-04-01_at_15.54.51_2x.png) +![pic3](https://gitlab.com/rdodin/pics/-/wikis/uploads/d06e3d2c3f515e19318cd2c5b2f59a39/CleanShot_2025-08-20_at_13.39.45.webp) Write down the Alarm Type that was raised when we shut down the interface. @@ -255,13 +255,15 @@ Alarm Type: `InterfaceDown` /// admonition | Restore Interface State type: warning -Bring back the interface state by running the following command in the bash shell of the server: +Bring back up the interface by running the following command in the bash shell of the server: ```shell docker exec clab-srexperts-leaf11 \ sr_cli -ec "/interface ethernet-1/1 admin-state enable" ``` +By bringing the interface up, the alarms will be automatically change their state to Cleared = True. + /// #### Configuring Notifier diff --git a/docs/eda/beginner/routers.md b/docs/eda/beginner/routers.md index 68205d3..601f908 100644 --- a/docs/eda/beginner/routers.md +++ b/docs/eda/beginner/routers.md @@ -8,9 +8,8 @@ | --------------------- | ---------------------------------------------------------------------------------------------------------- | | **Short Description** | Creating a router with EDA to achieve layer 3 connectivity | | **Difficulty** | Beginner | -| **Resources used** | **Virtual Networks** → **Routers** / **Routed Interfaces** | +| **Resources used** | **Virtual Networks** → **Routers** / **Routed Interfaces** | | **Topology Nodes** | :material-server: client11, :material-server: client13, :material-router: leaf11, :material-router: leaf13 | -| **References** | / | This is the second exercise in a 4-part series about using EDA to achieve connectivity to, from, and within your datacenter. In this exercise, we will achieve layer-3 connectivity between two hosts in different broadcast domains. @@ -77,7 +76,7 @@ Using the IP configuration provided in the [Objective](#objective) section, veri To connect to the shell of the client nodes, you should connect to the server running your lab and then ssh to each node, for example, for `client11`: ```bash title="execute from the lab server" -ssh user@clab-srexperts-client11 +ssh admin@clab-srexperts-client11 ```
@@ -181,7 +180,7 @@ Time to create your first Router and see what it gets you. Using the "Create" button in the top-right, you can create a new Router. In the center of the screen you can see all configuration options for the new Router, and on the right is a YAML representation that could be used for automation. -![Creating a router](../../images/eda/eda_router_creation.png) +![Creating a router](https://gitlab.com/rdodin/pics/-/wikis/uploads/d17e1bd394b5044e23a7ce977b3f775c/CleanShot_2025-08-14_at_18.34.55.webp) By creating a new Router resource we intend our network elements to have a VRF that will serve as a virtual routing instance for the two clients. @@ -210,7 +209,7 @@ The solution can be found below in YAML format, if you want to refer to it. You type: success ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: Router metadata: name: router @@ -243,14 +242,14 @@ Additionally, you want to give the routed interface both an IPv4 and an IPv6 add Before you commit, do a [dry-run](../beginner/declarative-intents.md#dry-run) first, just like in the previous exercise! This will allow you to inspect the configuration pushed to the nodes. After you commit this change to the fabric, you should be able to see the routed interface status reflected in the GUI. You can also navigate to your router, and find out which leaf nodes are now participating in the service. -![Status of the router](../../images/eda/eda_router_status.png) +![Status of the router](https://gitlab.com/rdodin/pics/-/wikis/uploads/8d87c3d901b90ddddcedc2aff23ccb02/CleanShot_2025-08-14_at_18.39.08.webp) /// details | Solution type: success //// tab | interface for client11 ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: RoutedInterface metadata: name: router-client11 @@ -272,7 +271,7 @@ spec: //// tab | interface for client13 ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: RoutedInterface metadata: name: router-client13 diff --git a/docs/eda/beginner/virtual-networks.md b/docs/eda/beginner/virtual-networks.md index c96169f..eca3faa 100644 --- a/docs/eda/beginner/virtual-networks.md +++ b/docs/eda/beginner/virtual-networks.md @@ -106,7 +106,9 @@ And your task is to create a service that has the following connectivity matrix: -{{ diagram(url='srexperts/hackathon-diagrams/main/eda.drawio', title='Target connectivity', page=9, zoom=1.5) }}- /// warning | IMPORTANT -Remove any Bridge Domains, Bridge Interfaces or VLANs created in the [Bridge Domains/Part 1](bridge-domains.md) and the [Routers/Part 2](routers.md) as our Virtual Network will create them or [simply reset EDA using the git time machine](../index.md#reset-eda). +Remove any Bridge Domains, Bridge Interfaces, VLANs and Routed Interfaces that you may have created in the [Bridge Domains/Part 1](bridge-domains.md) and the [Routers/Part 2](routers.md) as our Virtual Network will create them or [simply reset EDA using the git time machine](../index.md#reset-eda). + +Be careful when removing these resources and do not remove resources that have `role=hackathon-infra` tag as they are infrastructure related. But if you messed it up, don't worry, you can always [reset EDA](../index.md#reset-eda). /// You should expect that clients can't reach each other in any direction, due to no overlay services being configured. @@ -132,7 +134,7 @@ Time to create your first Virtual Network and make your clients talk to each oth Use the knowledge of the previous two exercises ([Bridge Domains](bridge-domains.md) and [Routers](routers.md)) to achieve the connectivity as shown on the diagram above. A single virtual network resource would be able to define the following: - a **Router** to create the IP-VRF of the EVPNVXLAN type -- two **Routed Interfaces** to connect the Router to the `client11` and `client12` over the respective VLANs 311 and 313 +- two **Routed Interfaces** to connect the Router to the `client11` and `client13` over the respective VLANs 311 and 313 - two **Bridge Domains** to create subnets for VLAN 300 and 312 respectively - two **VLAN** resources to create Bridge Interfaces for the respective VLANs 300 and 312 - two **IRB Interfaces** to connect the Bridge Domains to the Router @@ -155,7 +157,7 @@ When creating an IRB for example, you must specify references to both a Router a It might be tricky to solve this challenge if you see EDA for the first time, so here is a solution: ```yaml -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: VirtualNetwork metadata: name: virtual-network diff --git a/docs/eda/index.md b/docs/eda/index.md index 1d0a805..2140fe3 100644 --- a/docs/eda/index.md +++ b/docs/eda/index.md @@ -4,7 +4,7 @@ Event Driven Automation (EDA) is the state of the art automation platform that completes Nokia's Data Center portfolio: -![portfolio](https://gitlab.com/rdodin/pics/-/wikis/uploads/8a5373e38de7ea4be5af8128ffab9d3c/CleanShot_2025-04-18_at_23.53.33_2x.png) +![portfolio](https://gitlab.com/rdodin/pics/-/wikis/uploads/cad161eb76137f1034e7fbc8c196fdc8/CleanShot_2025-04-18_at_23.53.33_2x.webp) The design goals behind EDA were lofty and our ambitions were to create an infrastructure automation platform that addresses many challenges seen in the data center networking. @@ -77,7 +77,7 @@ Clients are the Linux containers connected to the switches that you would need t To access the clients you first need to login to the lab server, and then from the server's shell you SSH further to the desired client. ```bash title="run from the lab server" -ssh user@{client-hostname} +ssh admin@{client-hostname} ``` The switch hostnames are: @@ -86,7 +86,7 @@ The switch hostnames are: * `clab-srexperts-client12` * `clab-srexperts-client13` -The client's credentials are `user:multit00l` +The client's credentials are `admin:multit00l` /// @@ -102,7 +102,7 @@ Still, for the most part we expect you to follow the lead and use the UI to comp When you log in to the EDA UI you land on the **Main** page, here are the main areas of interest: -![ui-1](https://gitlab.com/rdodin/pics/-/wikis/uploads/a33d12f0cb46c95563021ceba7992d96/CleanShot_2025-05-02_at_18.54.01_2x.png) +![ui-1](https://gitlab.com/rdodin/pics/-/wikis/uploads/756d9cb79ed9deb1e450eccc6e9a1a0e/CleanShot_2025-08-14_at_11.51.59.webp) :material-numeric-1-circle: The home page features a dashboard that provides some key information about the managed nodes and their interfaces. @@ -112,15 +112,17 @@ When you log in to the EDA UI you land on the **Main** page, here are the main a :material-numeric-4-circle: Transaction basket. This is where your uncommitted transactions will be stored. Clicking on the basket icon also lets you do operations on the transactions. -:material-numeric-5-circle: User menu. This is where you can change your password, log out, and access the help and about pages. +:material-numeric-5-circle: Workflows. This menu icon lists the recently run workflows. -:material-numeric-6-circle: Side menu toggle. Expands/collapses the left side menu where all EDA apps and menu items are. +:material-numeric-6-circle: User menu. This is where you can change your password, log out, and access the help and about pages. -:material-numeric-7-circle: Application icon. Clicking on the icon in the collapsed view opens up the application page. +:material-numeric-7-circle: Side menu toggle. Expands/collapses the left side menu where all EDA apps and menu items are. -:material-numeric-8-circle: Application category toggle. Can be used to hide/show the application category. +:material-numeric-8-circle: Panel selector. EDA provides two default panels - Main and System Administration. The panels control what apps are visible in the side menu. Users can create their own panels and switch between them based on the use case. -:material-numeric-9-circle: Application search. Type in the search term and the apps list will be filtered. +:material-numeric-9-circle: Application icon. Clicking on the icon in the collapsed view opens up the application page. + +:material-numeric-10-circle: Application category toggle. Can be used to hide/show the application category. ### App page @@ -188,4 +190,8 @@ bash /opt/srexperts/restore-eda.sh This script will immediately revert all changes happened in EDA since you first logged in so you can start fresh. +## Where to next? + +After this brief introduction to the EDA UI you are ready to start exploring the next generation of network automation by either starting ["The tour of EDA"](./beginner/declarative-intents.md) that we have prepared for you, or venturing into self-paced exploration. + [^1]: Pending vendors' support for YANG and modern management interfaces. diff --git a/docs/eda/intermediate/api.md b/docs/eda/intermediate/api.md index 79cc192..d503c05 100644 --- a/docs/eda/intermediate/api.md +++ b/docs/eda/intermediate/api.md @@ -8,7 +8,7 @@ | **Topology Nodes** | leaf11, leaf12, leaf13, spine11, spine12 | | **References** | [EDA API Guide][api-guide], [EDA OpenAPI Swagger spec][swagger-spec][^1] |{: .foo} -[api-guide]: https://docs.eda.dev/development/api/ +[api-guide]: https://docs.eda.dev/25.8/development/api/ [swagger-spec]: https://github.com/eda-labs/openapi EDA is an API-first platform where every client, be it the EDA UI, a CLI tool or a higher-level orchestrator talks to EDA via one of its APIs. @@ -28,13 +28,13 @@ The objectives of this challenge are: ## Technology Explanation -EDA API follows a very similar model as the Kubernetes Resource Model. Every custom resource that gets added through the installation of an App, becomes available through the EDA API in a similar way as custom resources in Kubernetes become available through the Kubernetes API. This model provides that powerful extensibility where a system can be extended on-the-fly, by simply installing the EDA App via the EDA Store, and the app will plug its API to the common API layer of the system. +EDA API is extensible. Every EDA resource that gets added when a user installs the application, becomes extends the EDA API surface in a similar way as custom resources in Kubernetes become available through the Kubernetes API. This model provides that powerful extensibility where a system can be customized on-the-fly, by simply installing the EDA App via the EDA Store, and the app will plug its API to the common API layer of the system. -Based on this, the EDA API may be seen as comprised of the two APIs sets: +EDA's API have two API sets that users typically interact with: 1. **Core API** This is the EDA Core system API. Things like Transactions, Alarms, and User management are all part of the this API set. - It can not be extended without installing a new version of the EDA Core. + It extends with installing a new version of the EDA platform. 2. **Apps API** Every applications onboarded to the EDA platform (both provided by Nokia or anyone else) will extend the Apps API by adding the applications API to the common API layer. This is how extensibility of the API is achieved in EDA. @@ -42,9 +42,7 @@ Based on this, the EDA API may be seen as comprised of the two APIs sets: ### API Server -Both Core and Apps API are served by the EDA's API Server implemented as a horizontally scalable `eda-api` deployment running in the EDA's Kubernetes cluster. The API server deployment is exposed via `eda-api` service. - -You access the API server using the EDA's external address. +Both Core and Apps API are served by the EDA's API Server implemented as a horizontally scalable `eda-api` deployment running in the EDA's Kubernetes cluster. The API server deployment is exposed via `eda-api` Kubernetes service. ### API Documentation @@ -64,7 +62,7 @@ As you would expect, only authorized and authenticated users can make use of the The API client directly authenticates with Keycloak, and uses the token received for further API calls to the EDA API. The API client is also responsible for refreshing or renewing their token. -Open a tab with the [authentication docs](https://docs.eda.dev/development/api/#authentication) as you will need it later when we get to running our first API call. +Open a tab with the [authentication docs](https://docs.eda.dev/25.8/development/api/#authentication) as you will need it later when we get to running our first API call. ### Sync, Async and Transaction APIs @@ -99,7 +97,7 @@ We will use Postman as the API client to fire off the requests. If you don't hav When installing Postman you will be asked to login to the Postman.com, you can use any of the existing OpenID providers (google, github). The registration is free and you won't be asked to provide any payment details. -When Postman is installed, grab the Postman Collection that we prepared for this exercise by clicking on this button +When Postman is installed, grab the Postman Collection that we prepared for this exercise by clicking on the button below: [Run In Postman](https://app.getpostman.com/run-collection/4909600-0b22527f-4f68-464b-9c74-70c0bb658292?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D4909600-0b22527f-4f68-464b-9c74-70c0bb658292%26entityType%3Dcollection%26workspaceId%3D6bee419c-5db7-440e-a509-f9bb4d460e34#?env%5BHackathon%20instance%5D=W3sia2V5IjoiQVBJX1NFUlZFUiIsInZhbHVlIjoiaHR0cHM6Ly8xMC4xODEuMTMxLjQxOjk0NDMiLCJlbmFibGVkIjp0cnVlLCJ0eXBlIjoiZGVmYXVsdCIsInNlc3Npb25WYWx1ZSI6Imh0dHBzOi8vMTAuMTgxLjEzMS40MTo5NDQzIiwiY29tcGxldGVTZXNzaW9uVmFsdWUiOiJodHRwczovLzEwLjE4MS4xMzEuNDE6OTQ0MyIsInNlc3Npb25JbmRleCI6MH0seyJrZXkiOiJFREFfQ0xJRU5UX1NFQ1JFVCIsInZhbHVlIjoieGoxbkFZWTRMWE9KOUlWMEtWWnppRnY1NE53YWlzNlAiLCJlbmFibGVkIjp0cnVlLCJ0eXBlIjoic2VjcmV0Iiwic2Vzc2lvblZhbHVlIjoieGoxbkFZWTRMWE9KOUlWMEtWWnppRnY1NE53YWlzNlAiLCJjb21wbGV0ZVNlc3Npb25WYWx1ZSI6InhqMW5BWVk0TFhPSjlJVjBLVlp6aUZ2NTROd2FpczZQIiwic2Vzc2lvbkluZGV4IjoxfSx7ImtleSI6IkVEQV9VU0VSIiwidmFsdWUiOiJhZG1pbiIsImVuYWJsZWQiOnRydWUsInR5cGUiOiJkZWZhdWx0Iiwic2Vzc2lvblZhbHVlIjoiYWRtaW4iLCJjb21wbGV0ZVNlc3Npb25WYWx1ZSI6ImFkbWluIiwic2Vzc2lvbkluZGV4IjoyfSx7ImtleSI6IkVEQV9VU0VSX1BXIiwidmFsdWUiOiJhZG1pbiIsImVuYWJsZWQiOnRydWUsInR5cGUiOiJkZWZhdWx0Iiwic2Vzc2lvblZhbHVlIjoiYWRtaW4iLCJjb21wbGV0ZVNlc3Npb25WYWx1ZSI6ImFkbWluIiwic2Vzc2lvbkluZGV4IjozfSx7ImtleSI6IlRPS0VOIiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlLCJ0eXBlIjoiZGVmYXVsdCIsInNlc3Npb25WYWx1ZSI6IiIsImNvbXBsZXRlU2Vzc2lvblZhbHVlIjoiIiwic2Vzc2lvbkluZGV4Ijo0fSx7ImtleSI6IktDX0FETUlOX1BXIiwidmFsdWUiOiJhZG1pbiIsImVuYWJsZWQiOnRydWUsInR5cGUiOiJkZWZhdWx0Iiwic2Vzc2lvblZhbHVlIjoiYWRtaW4iLCJjb21wbGV0ZVNlc3Npb25WYWx1ZSI6ImFkbWluIiwic2Vzc2lvbkluZGV4Ijo1fSx7ImtleSI6IktDX0FETUlOX1RPS0VOIiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlLCJ0eXBlIjoiYW55Iiwic2Vzc2lvblZhbHVlIjoiIiwiY29tcGxldGVTZXNzaW9uVmFsdWUiOiIiLCJzZXNzaW9uSW5kZXgiOjZ9XQ==) @@ -113,7 +111,7 @@ Select your Workspace where you want the collection to be imported in. The prepa In addition to the collection, the environment named "Hackathon instance" that contains the `API_SERVER` variable should appear in the top right corner of the Postman app: -![envpic](https://gitlab.com/rdodin/pics/-/wikis/uploads/05503a8ac4221aab026181e2af4db8c5/CleanShot_2025-05-07_at_14.28.08_2x.png){.img-shadow width=50%} +![envpic](https://gitlab.com/rdodin/pics/-/wikis/uploads/b33da623c4d7e20c321fa10bf75afeee/CleanShot_2025-08-19_at_11.34.05.webp) Make sure to select it. @@ -127,7 +125,7 @@ This video shows the full process: Now that you have the collection and the environment dialed in, you need to sort the authentication out. Remember, only the authenticated users can leverage the API. -The authentication process boils down to acquiring the API token from the Keycloak service that runs as part of the EDA deployment, but to get the authentication token you first need to get the `client_secret` from Keycloak. Sounds a bit cryptic? Check out the [authentication docs](https://docs.eda.dev/development/api/#authentication) to understand the flow better; there we also explain how to get the `client_secret` using the Keycloak UI. +The authentication process boils down to acquiring the API token from the Keycloak service that runs as part of the EDA deployment, but to get the access token you first need to get the `client_secret` from Keycloak. Sounds a bit cryptic? Check out the [authentication docs](https://docs.eda.dev/25.8/development/api/#authentication) to understand the flow better; there we also explain how to get the `client_secret` using the Keycloak UI. Once you get the `client_secret` string from Keycloak, set its value in the [Postman Environment](#environment) as the **Current value** of the `EDA_CLIENT_SECRET` variable. Done? @@ -190,7 +188,7 @@ Congratulations, you have completed the first task! In the previous task you listed all objects of the same kind, to be precise - all users. Now the task is to retrieve the details of a particular Interface object from EDA, namely, `leaf11-ethernet-1-49`. -To complete this task you will use the **Interface** application API, as interfaces are not part of the EDA core, but an extension brought in by the [Interface application](https://docs.eda.dev/apps/interfaces/). +To complete this task you will use the **Interface** application API, as interfaces are not part of the EDA core, but an extension brought in by the [Interface application](https://docs.eda.dev/25.8/apps/interfaces/). Using the knowledge on how to navigate the API documentation, try to complete the :material-folder-outline: **Interface** → **Interface** request so that the EDA returns everything it knows about the `leaf11-ethernet-1-49`. diff --git a/docs/eda/intermediate/custom-allocations.md b/docs/eda/intermediate/custom-allocations.md index cb84ab9..713b971 100644 --- a/docs/eda/intermediate/custom-allocations.md +++ b/docs/eda/intermediate/custom-allocations.md @@ -10,7 +10,7 @@ | **Topology Nodes** | leaf11, leaf12, leaf13, spine11, spine12 | | **References** | [Allocation Pools documentation][allocation-docs] | -[allocation-docs]: https://docs.eda.dev/user-guide/allocation-pools/ +[allocation-docs]: https://docs.eda.dev/25.8/user-guide/allocation-pools/ Allocation of identifiers such as IP addresses, VLAN IDs, subinterface indexes and so on is a critical aspect of network design and management. Given that EDA acts as an authority for configuration of the managed targets, it automates and controls how resource identifiers are assigned via the concept of Allocation Pools. @@ -62,6 +62,12 @@ Your task is to align the allocation values used in the fabric to match a specif We'll go step-by-step through the process of reviewing the current ASN assignments and then applying the new custom ASN scheme to the fabric. We'll use both the CLI and the EDA UI to accomplish this, and verify the changes with a EQL query. +/// danger + +This set of tasks changes ASN numbering in the data center fabric, impacting the peering sessions with PE devices. While this is expected, when you finish with this exercise you must [reset the EDA](../index.md#reset-eda) to its original state to ensure that the service configuration is set to the original state. + +/// + ### Concepts & Naming Conventions In this exercise you are tasked with using a specific ASN format in your fabric - **33Xxxxyyyy** - where each part of the number encodes specific information: @@ -124,8 +130,12 @@ First, let's verify what ASNs are currently assigned to the fabric devices befor resourceVersion: "1145904" uid: 2b1ec70a-3d9d-404b-8493-f87640d43638 spec: + publishAllocations: true segments: - - size: 1000 + - allocations: + - name: srexperts-fabric-spine + value: 4200001000 + size: 1000 start: 4200001000 ``` @@ -139,7 +149,7 @@ Next, let's confirm which ASN pool is being used by our Fabric via the EDA UI. T Log in to the EDA web interface using the connectivity and credential details provided. -![EDA Main](../../images/EDA_maina_CA.PNG) +![EDA Main](https://gitlab.com/rdodin/pics/-/wikis/uploads/e4e0ab87c7063977adfd3de4f91320ae/CleanShot_2025-04-08_at_14.48.42_2x.png) **2. Identify the ASN Pool used by the Leaf nodes** @@ -151,20 +161,20 @@ Let's find what allocation pool is being used for the leaf switches, by checking * Select the **Autonomous System Pool** in the left nav bar. You should see the right pane to scroll to the position where the ASN allocation pool name is set for the leaf nodes. > *For example, it might indicate “Autonomous System Pool: srexperts-asnpool” or display another pool name.* -![used-pool](https://gitlab.com/rdodin/pics/-/wikis/uploads/942bc1a8332d315124ef221de9e9e5e8/CleanShot_2025-04-16_at_13.37.14_2x.png) +![used-pool](https://gitlab.com/rdodin/pics/-/wikis/uploads/0e5ca597a4d01ee2f1c7f3e7c9b8f6ba/CleanShot_2025-08-15_at_10.45.17.webp) **3. Verify assigned AS Number** After you identified the pool name used for the leafs, check what AS Numbers have been assigned to the actual leaf nodes. Using the nav bar of the Fabric resource, follow the **Status** -> **Leaf Nodes** path to see leaf nodes and their AS Numbers that are currently assigned. -![Verify ASN Assignment](https://gitlab.com/rdodin/pics/-/wikis/uploads/0a4156292e1027caeecc08dbafbce70f/CleanShot_2025-04-16_at_14.08.11_2x.png) +![Verify ASN Assignment](https://gitlab.com/rdodin/pics/-/wikis/uploads/00fdb76c6cb9c13b3e0218493a92d2af/CleanShot_2025-08-15_at_10.53.25.webp) **4. Check Pool configuration** Using the pool name identified in step 2, find this pool in the Allocation Pools and check its configuration. -![ASN Pool Detail](../../images/ASN_pool_CA.PNG) +![ASN Pool Detail](https://gitlab.com/rdodin/pics/-/wikis/uploads/c97c923d92bca142b81a1c121f028cf0/CleanShot_2025-08-15_at_10.50.06.webp) **5. For Spine Nodes** @@ -337,10 +347,16 @@ Feel free to experiment further: * See how EDA behaves when two pools overlap. * Pre-allocate specific values to particular nodes using the allocations field. -For deeper insights, consult the [EDA documentation](https://docs.eda.dev/user-guide/allocation-pools/). +For deeper insights, consult the [EDA documentation](https://docs.eda.dev/25.8/user-guide/allocation-pools/). Congratulations! You have successfully implemented custom resource allocations in Nokia EDA and learned how to enforce naming conventions via automated network deployments. This wraps up the lab. Proceed to the next activity or apply these principles to your own network designs. Happy automating! +/// danger + +This set of tasks changes ASN numbering in the data center fabric, impacting the peering sessions with PE devices. While this is expected, when you finish with this exercise you must [reset the EDA](../index.md#reset-eda) to its original state to ensure that the service configuration is set to the original state. + +/// + ## Summary Custom allocations are useful to ensure the deterministic resource allocation when a certain naming or addressing scheme is enforced by the design. EDA allows applications to reserve values for the given keys and thus ensures the flexible model to ensure predictable allocations. diff --git a/docs/eda/intermediate/install-eda.md b/docs/eda/intermediate/install-eda.md index cc3c55a..f8cd3f1 100644 --- a/docs/eda/intermediate/install-eda.md +++ b/docs/eda/intermediate/install-eda.md @@ -33,7 +33,7 @@ EDA is a cloud-native platform for infrastructure automation. It is deployed on - and so on... If microservices and Kubernetes concepts are new to you, fear not, you don't have to be a PhD in cloud-native to install EDA in the lab environment, let alone to use it. -We call the process of installing a lab instance of EDA - **Try EDA** - and it is [documented on docs.eda.dev](https://docs.eda.dev/getting-started/try-eda/). +We call the process of installing a lab instance of EDA - **Try EDA** - and it is [documented on docs.eda.dev](https://docs.eda.dev/25.8/getting-started/try-eda/). The Try EDA installation installs the **EDA Playground** - a lab environment that consists of a [KinD](https://kind.sigs.k8s.io/) k8s cluster with EDA platform and a small virtual network topology with SR Linux nodes running on top of it. @@ -47,9 +47,9 @@ By leveraging EDA's deployment model that uses Kubernetes, we can install EDA Pl --- - Of course, you can install EDA on any compute powered by Linux. Just use the [Try EDA](https://docs.eda.dev/getting-started/try-eda/) installation guide to get started. + Of course, you can install EDA on any compute powered by Linux. Just use the [Try EDA](https://docs.eda.dev/25.8/getting-started/try-eda/) installation guide to get started. - [:octicons-arrow-right-24: Try EDA on Linux](https://docs.eda.dev/getting-started/try-eda/) + [:octicons-arrow-right-24: Try EDA on Linux](https://docs.eda.dev/25.8/getting-started/try-eda/) - :fontawesome-brands-windows:{ .middle } **Windows** @@ -57,7 +57,7 @@ By leveraging EDA's deployment model that uses Kubernetes, we can install EDA Pl You can install EDA on Windows as well! Leveraging the Windows Subsystem for Linux (WSL) you can install EDA on top of it. Check out our guide. - [:octicons-arrow-right-24: Try EDA on Windows](https://docs.eda.dev/software-install/non-production/wsl/) + [:octicons-arrow-right-24: Try EDA on Windows](https://docs.eda.dev/25.8/software-install/non-production/wsl/) - :simple-apple:{ .middle } **MacOS** @@ -67,7 +67,7 @@ By leveraging EDA's deployment model that uses Kubernetes, we can install EDA Pl By setting up Docker on your Mac you can install EDA on top of it. Check out our guide. - [:octicons-arrow-right-24: Try EDA on macOS](https://docs.eda.dev/software-install/non-production/macos/) + [:octicons-arrow-right-24: Try EDA on macOS](https://docs.eda.dev/25.8/software-install/non-production/macos/) - :simple-kubernetes:{ .middle } **Existing Kubernetes cluster** @@ -77,7 +77,7 @@ By leveraging EDA's deployment model that uses Kubernetes, we can install EDA Pl This is a more advanced path, as you will need to understand basic Kubernetes concepts and EDA installation process to get it running. - [:octicons-arrow-right-24: Playground on an existing Kubernetes cluster](https://docs.eda.dev/software-install/non-production/on-prem-cluster/) + [:octicons-arrow-right-24: Playground on an existing Kubernetes cluster](https://docs.eda.dev/25.8/software-install/non-production/on-prem-cluster/)
@@ -103,10 +103,10 @@ This is the amount of resources that your kubernetes cluster implemented by the Choose your deployment option and equip yourself with the following documentation articles to help you get going: -- [Try EDA process explained](https://docs.eda.dev/getting-started/try-eda/) - to install EDA on a Linux server. -- [macOS install instructions](https://docs.eda.dev/software-install/non-production/macos/) - to install EDA Playground on a macOS. -- [Windows install instructions](https://docs.eda.dev/software-install/non-production/wsl/) - to install EDA Playground on a Windows machine. +- [Try EDA process explained](https://docs.eda.dev/25.8/getting-started/try-eda/) - to install EDA on a Linux server. +- [macOS install instructions](https://docs.eda.dev/25.8/software-install/non-production/macos/) - to install EDA Playground on a macOS. +- [Windows install instructions](https://docs.eda.dev/25.8/software-install/non-production/wsl/) - to install EDA Playground on a Windows machine. - [`Makefile`](https://github.com/nokia-eda/playground/blob/main/Makefile) from the EDA Playground repository - to see what actually being installed and how when you run `make try-eda` command. -- [Installation process explained](https://docs.eda.dev/getting-started/installation-process/) - to have a deeper dive on how EDA is installed on a Linux server. +- [Installation process explained](https://docs.eda.dev/25.8/getting-started/installation-process/) - to have a deeper dive on how EDA is installed on a Linux server. diff --git a/docs/htmltest.yml b/docs/htmltest.yml index 7c33ca4..16d0111 100644 --- a/docs/htmltest.yml +++ b/docs/htmltest.yml @@ -16,7 +16,9 @@ IgnoreURLs: - https://github.com/orgs/nokia/packages/container/srlinux/versions - on.srlinux.dev - localhost - - https://github.com/srl-labs/learn-srlinux/edit/ + - https://github.com/srexperts/srx-hackplanning-2025 # repo is not public + - https://github.com/srexperts/srx-hackplanning-2025/edit/ + - https://github.com/nokia/SReXperts/edit/ - twitter.com - https://linkedin.com/in - https://linkedin.com/feed diff --git a/docs/images/tools-clab-vscode-plugin/01-annotated-treeview.png b/docs/images/tools-clab-vscode-plugin/01-annotated-treeview.png new file mode 100644 index 0000000..5e53f89 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/01-annotated-treeview.png differ diff --git a/docs/images/tools-clab-vscode-plugin/02-topo_viewer_editor.png b/docs/images/tools-clab-vscode-plugin/02-topo_viewer_editor.png new file mode 100644 index 0000000..4e54bd3 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/02-topo_viewer_editor.png differ diff --git a/docs/images/tools-clab-vscode-plugin/03-integrated_wireshark.png b/docs/images/tools-clab-vscode-plugin/03-integrated_wireshark.png new file mode 100644 index 0000000..7af1a0b Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/03-integrated_wireshark.png differ diff --git a/docs/images/tools-clab-vscode-plugin/04-link-impairments.png b/docs/images/tools-clab-vscode-plugin/04-link-impairments.png new file mode 100644 index 0000000..a352137 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/04-link-impairments.png differ diff --git a/docs/images/tools-clab-vscode-plugin/05-launch_topo_viewer_editor.png b/docs/images/tools-clab-vscode-plugin/05-launch_topo_viewer_editor.png new file mode 100644 index 0000000..aeabe80 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/05-launch_topo_viewer_editor.png differ diff --git a/docs/images/tools-clab-vscode-plugin/06-topo_viewer_editor_file_name_input.png b/docs/images/tools-clab-vscode-plugin/06-topo_viewer_editor_file_name_input.png new file mode 100644 index 0000000..3650e07 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/06-topo_viewer_editor_file_name_input.png differ diff --git a/docs/images/tools-clab-vscode-plugin/07-topo_viewer_editor_splitscreen.png b/docs/images/tools-clab-vscode-plugin/07-topo_viewer_editor_splitscreen.png new file mode 100644 index 0000000..db361fd Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/07-topo_viewer_editor_splitscreen.png differ diff --git a/docs/images/tools-clab-vscode-plugin/09-topo_viewer_editor_deploy.png b/docs/images/tools-clab-vscode-plugin/09-topo_viewer_editor_deploy.png new file mode 100644 index 0000000..e0e6ded Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/09-topo_viewer_editor_deploy.png differ diff --git a/docs/images/tools-clab-vscode-plugin/10-tree_view_deploy.png b/docs/images/tools-clab-vscode-plugin/10-tree_view_deploy.png new file mode 100644 index 0000000..904ee49 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/10-tree_view_deploy.png differ diff --git a/docs/images/tools-clab-vscode-plugin/11-editor_quick_deploy.png b/docs/images/tools-clab-vscode-plugin/11-editor_quick_deploy.png new file mode 100644 index 0000000..c49ac79 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/11-editor_quick_deploy.png differ diff --git a/docs/images/tools-clab-vscode-plugin/12-post_deploy_screenshot.png b/docs/images/tools-clab-vscode-plugin/12-post_deploy_screenshot.png new file mode 100644 index 0000000..38d04dc Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/12-post_deploy_screenshot.png differ diff --git a/docs/images/tools-clab-vscode-plugin/13-inspect_webivew.png b/docs/images/tools-clab-vscode-plugin/13-inspect_webivew.png new file mode 100644 index 0000000..3162172 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/13-inspect_webivew.png differ diff --git a/docs/images/tools-clab-vscode-plugin/14-draw_io_export.png b/docs/images/tools-clab-vscode-plugin/14-draw_io_export.png new file mode 100644 index 0000000..d0134a8 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/14-draw_io_export.png differ diff --git a/docs/images/tools-clab-vscode-plugin/install-ext-steps.png b/docs/images/tools-clab-vscode-plugin/install-ext-steps.png new file mode 100644 index 0000000..cec2766 Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/install-ext-steps.png differ diff --git a/docs/images/tools-clab-vscode-plugin/install-ssh.gif b/docs/images/tools-clab-vscode-plugin/install-ssh.gif new file mode 100644 index 0000000..d7ae89a Binary files /dev/null and b/docs/images/tools-clab-vscode-plugin/install-ssh.gif differ diff --git a/docs/index.md b/docs/index.md index 53598a6..7736be9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -59,7 +59,7 @@ Please refer to the paper provided by the hackathon session leader. If nothing h ### SSH -The simplest way to get going is to use your SSH client to connect to your group's hackathon VM instance and work from there. All tools and applications are pre-installed and you will have direct access to your entire network. +The simplest way to get going is to use your SSH client to connect to your group's hackathon VM instance and work from there. All tools and applications are pre-installed and you will have direct access to your entire network. SSH is also important if you want to driectly access your network from your laptop but more on that later. @@ -79,15 +79,15 @@ WiFi is important here. Without it your hackathon experience is going to be rat ### Topology -When accessing your hackathon VM instance you'll the [SReXperts GitHub repository](https://github.com/nokia/srexperts) that contains all of the documentation, examples, solutions and loads of other great stuff, has already been cloned for you. +When accessing your hackathon VM instance you'll find that the [SReXperts GitHub repository](https://github.com/nokia/srexperts) contains all of the documentation, examples, solutions and loads of other great stuff, has already been cloned for you. -In this hackathon, every group has their own complete service-provider network at their disposal. Your network comprises an IP backbone with Provider (P) and Provider Edge (PE) router, a broadband dial-in network, a peering edge network, an internet exchange point, multiple data-centers and a number of client and subscriber devices. This network is already deployed and provisioned and is ready to go! +In this hackathon, every group has their own complete service-provider network at their disposal. Your network comprises an IP backbone with Provider (P) and Provider Edge (PE) routers, a broadband dial-in network, a peering edge network, an internet exchange point, multiple data-centers and a number of client and subscriber devices. This network is already deployed and provisioned and is ready to go! *Don't worry: This is your personal group network, you cannot impact any other groups.* -{{ diagram(url='srexperts/hackathon-diagrams/main/SReXperts2025.drawio', title='Topology', page=0) }}- -The above topology contains a number of functional blocks to help you in area's you might want to focus on, it contains: +The above topology contains a number of functional blocks to help you in areas you might want to focus on, it contains: - Routing: - SR-MPLS (Dual-Stack ISIS) @@ -132,7 +132,7 @@ sudo containerlab inspect -a │ Topology │ Lab Name │ Name │ Kind/Image │ State │ IPv4/6 Address │ ├─────────────────────────────┼───────────┼────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ SReXperts/clab/srx.clab.yml │ srexperts │ clab-srexperts-agg1 │ nokia_srlinux │ running │ 10.128.1.52 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-client01 │ linux │ running │ 10.128.1.25 │ │ │ │ │ ghcr.io/srl-labs/network-multitool │ │ N/A │ @@ -171,19 +171,19 @@ sudo containerlab inspect -a │ │ │ │ grafana/grafana:10.3.5 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-ixp1 │ nokia_srlinux │ running │ 10.128.1.51 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-leaf11 │ nokia_srlinux │ running │ 10.128.1.33 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-leaf12 │ nokia_srlinux │ running │ 10.128.1.34 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-leaf13 │ nokia_srlinux │ running │ 10.128.1.35 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-leaf21 │ nokia_srlinux │ running │ 10.128.1.41 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-loki │ linux │ running │ 10.128.1.76 │ │ │ │ │ grafana/loki:2.9.7 │ │ N/A │ @@ -216,7 +216,7 @@ sudo containerlab inspect -a │ │ │ │ vr-sros:25.3.R1 │ (healthy) │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-peering2 │ nokia_srlinux │ running │ 10.128.1.53 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-postgres │ linux │ running │ 10.128.1.84 │ │ │ │ │ docker.io/postgres:17-alpine │ │ N/A │ @@ -240,10 +240,10 @@ sudo containerlab inspect -a │ │ │ │ rpki/stayrtr │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-spine11 │ nokia_srlinux │ running │ 10.128.1.31 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-spine12 │ nokia_srlinux │ running │ 10.128.1.32 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-sub1 │ linux │ running │ 10.128.1.61 │ │ │ │ │ ghcr.io/srl-labs/network-multitool │ │ N/A │ @@ -261,13 +261,13 @@ sudo containerlab inspect -a │ │ │ │ ghcr.io/srl-labs/network-multitool │ │ N/A │ │ │ ├────────────────────────────────────┼─────────────────────────────────────────────┼───────────┼────────────────┤ │ │ │ clab-srexperts-vRR │ nokia_srlinux │ running │ 10.128.1.13 │ -│ │ │ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ │ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ╰─────────────────────────────┴───────────┴────────────────────────────────────┴─────────────────────────────────────────────┴───────────┴────────────────╯ ``` /// -Using the names from the above output, we can login to the a node using the following command: +Using the names from the above output, we can login to a node using the following command: For example, to access the `clab-srexperts-pe1` node via ssh simply type: @@ -375,7 +375,7 @@ In the generic topology, linux clients are attached to a number of routers: One can start and/or stop traffic by connecting to the relevant client using SSH, and running `/traffic.sh`, for example: ``` -ssh user@clab-srexperts-client11 +ssh admin@clab-srexperts-client11 client11:~$ /traffic.sh [-a ] [-d ] ``` @@ -433,7 +433,7 @@ stopping traffic to client21.grt ### My employer/security department locked down my laptop -No worries, we have got you covered! Each instance is running a web-based VSCode code server, when accessing it at `http://.srexperts.net` should prompt you for a password (which is documented on the physical paper provided), and you should be able to access the topology through the terminal there. +No worries, we have got you covered! Each instance is running a web-based VSCode code server, when accessing it at `https://.srexperts.net` should prompt you for a password (which is documented on the physical paper provided), and you should be able to access the topology through the terminal there. ### Help! I've bricked my lab, how do I redeploy? @@ -999,7 +999,7 @@ Run 'sudo clab version upgrade' or see https://containerlab.dev/install/ for ins │ Name │ Kind/Image │ State │ IPv4/6 Address │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-agg1 │ nokia_srlinux │ running │ 10.128.15.52 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-client01 │ linux │ running │ 10.128.15.25 │ │ │ ghcr.io/srl-labs/network-multitool │ │ N/A │ @@ -1038,19 +1038,19 @@ Run 'sudo clab version upgrade' or see https://containerlab.dev/install/ for ins │ │ grafana/grafana:10.3.5 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-ixp1 │ nokia_srlinux │ running │ 10.128.15.51 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-leaf11 │ nokia_srlinux │ running │ 10.128.15.33 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-leaf12 │ nokia_srlinux │ running │ 10.128.15.34 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-leaf13 │ nokia_srlinux │ running │ 10.128.15.35 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-leaf21 │ nokia_srlinux │ running │ 10.128.15.41 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-loki │ linux │ running │ 10.128.15.76 │ │ │ grafana/loki:2.9.7 │ │ N/A │ @@ -1083,7 +1083,7 @@ Run 'sudo clab version upgrade' or see https://containerlab.dev/install/ for ins │ │ vr-sros:25.3.R1 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-peering2 │ nokia_srlinux │ running │ 10.128.15.53 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-postgres │ linux │ running │ 10.128.15.84 │ │ │ docker.io/postgres:17-alpine │ │ N/A │ @@ -1107,10 +1107,10 @@ Run 'sudo clab version upgrade' or see https://containerlab.dev/install/ for ins │ │ rpki/stayrtr │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-spine11 │ nokia_srlinux │ running │ 10.128.15.31 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-spine12 │ nokia_srlinux │ running │ 10.128.15.32 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-sub1 │ linux │ running │ 10.128.15.61 │ │ │ ghcr.io/srl-labs/network-multitool │ │ N/A │ @@ -1128,7 +1128,7 @@ Run 'sudo clab version upgrade' or see https://containerlab.dev/install/ for ins │ │ ghcr.io/srl-labs/network-multitool │ │ N/A │ ├────────────────────────────────────┼─────────────────────────────────────────────┼─────────┼────────────────┤ │ clab-srexperts-vRR │ nokia_srlinux │ running │ 10.128.15.13 │ -│ │ ghcr.io/nokia/srlinux:24.10.4 │ │ N/A │ +│ │ ghcr.io/nokia/srlinux:24.10.3 │ │ N/A │ ╰────────────────────────────────────┴─────────────────────────────────────────────┴─────────┴────────────────╯ ``` @@ -1212,4 +1212,4 @@ gh repo clone nokia/SReXperts ## Thanks and contributions -As you can imagine, creating the activities that make up this hackathon is a lot of work. The hackathon team would like to thanks the following team members (in alphabetical order) for their contributions: Asad Arafat, Diogo Pinheiro, Guilherme Cale, Hans Thienpondt, James Cumming, Joao Machado, Kaelem Chandra, Laleh Kiani, Louis Van Eeckhoudt, Maged Makramalla, Miguel Redondo Ferrero, Roman Dodin, Saju Salahudeen, Samier Barguil, Shafkat Waheed, Shashi Sharma, Simon Tibbitts, Siva Sivakumar, Subba Konda, Sven Wisotzky, Thomas Hendriks, Tiago Amado. Zeno Dhaene, Tim Raphael and Vasileios Tekidis \ No newline at end of file +As you can imagine, creating the activities that make up this hackathon is a lot of work. The hackathon team would like to thank the following team members (in alphabetical order) for their contributions: Asad Arafat, Bhavish Khatri, Diogo Pinheiro, Guilherme Cale, Hans Thienpondt, James Cumming, Joao Machado, Kaelem Chandra, Laleh Kiani, Louis Van Eeckhoudt, Maged Makramalla, Miguel Redondo Ferrero, Roman Dodin, Saju Salahudeen, Samier Barguil, Shafkat Waheed, Shashi Sharma, Simon Tibbitts, Siva Sivakumar, Subba Konda, Sven Wisotzky, Thomas Hendriks, Tiago Amado. Zeno Dhaene, Tim Raphael and Vasileios Tekidis diff --git a/docs/nos/srlinux/advanced/20-SRLinux-Basic-Agent.md b/docs/nos/srlinux/advanced/20-SRLinux-Basic-Agent.md new file mode 100644 index 0000000..6e37035 --- /dev/null +++ b/docs/nos/srlinux/advanced/20-SRLinux-Basic-Agent.md @@ -0,0 +1,1322 @@ +--- +tags: + - NDK + - python + - srlinux + - srlinux agent +--- + +# NDK Agent to manage static-routes based on next-hop reachability checks + + +| | | +| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Activity name** | NDK Agent to manage static-routes based on next-hop reachability checks | +| **Activity ID** | 20 | +| **Short Description** | Nokia SRLinux NDK (NetOps Development Kit) allows users to deploy non-native apps (aka agents).


These custom apps or agents run alongside native apps on SR Linux Network OS.


| +| **Difficulty** | Intermediate | +| **Tools used** | [NDK](https://learn.srlinux.dev/ndk/), [Python](https://www.python.org/) | +| **Topology Nodes** | :material-router: leaf11, :material-router: leaf13, :material-router: client02, :material-router: client11, :material-router: client13,:material-router: pe2 | +| **References** | [SRLinux overview](https://documentation.nokia.com/srlinux/25-3/html/product/Overview.html)
[NetOps Development Kit (NDK)](https://learn.srlinux.dev/ndk/)
[NetOps Development Kit API Reference ](https://documentation.nokia.com/srlinux/25-3/title/ndk_api.html#undefined)
[Apps Catalog](https://learn.srlinux.dev/ndk/apps/)
[NDK Developers Guide](https://learn.srlinux.dev/ndk/guide/architecture/)
[SR Linux applications](https://documentation.nokia.com/srlinux/25-3/books/config-basics/sr-linux-applications.html#sr-linux-applications) | + + +In this activity you will learn about the SRLinux NDK architecture and how to deploy non-native apps (aka custom agents). +You will learn the file and folder structures and how to on-board a basic agent including the YANG data model. +Finally, you will test the agent operation, inspect the code to fix some issues, validate the proper operation and add a new feature. + +The objectives of this exercise are: + +1. Explore the SRLinux NDK architecture and how to deploy non-native apps. +2. Inspect the agents file and folder structures and the on-board process. +3. Validate the agent execution, inspect the code, the logs and validate the proper operation. +4. Add code for a new feature + +Let's first describe the use case. + +### NDK Agent use case - static route with next-hop reachability validation +Imagine that you have a data center with an SR Linux IP fabric and several servers hosting two services (Green and Blue) each with it's own VLAN as represented in the picture below. Each service has multiple PODs distributed across the servers but exposing a single Anycast Virtual IP (VIP) per service. There is no BGP, BFD or other dynamic protocol supported, as such, static routes are used: the Anycast IP is the destination and the sub-interface VLAN IP is the next-hop. + +-{{ diagram(url='tiago-amado/srx/main/activity20_srx.clab.drawio', title='Fig. 1 - SR Linux basic agent - Use case setup', page=0) }}- + + + +As long as there is a POD active for a service in a server, the VIP and the VLAN interface will remain active. The leaves will have a static-route per service with the Anycast IP as destination and the local connected servers VLAN IP as next-hop. If a server or the physical interfaces fails, the leaf detects the failure and the route becomes inactive and is no longer advertised. However, if all the PODs are moved to another server or if there's a logical failure of one service, the leaves cannot detect it and an outage occurs. +One potential solution would be to enhance the static-routes with the capability to validate the next-hop reachability, which is supported today in SROS ([cpe-check feature](https://infocenter.nokia.com/public/7750SR217R1A/index.jsp?topic=%2Fcom.nokia.Layer_3_Services_Guide_21.7.R1%2Fcpe_connectivit-d259e250.html)) but not in SR Linux. + +Your objective is to solve this problem using the NDK on SR Linux. + + +## Technology explanation + +### NetOps Development Kit (NDK) + +Nokia SR Linux provides a software development kit called **NetOps Development Kit** or **NDK** for short, that enables its users to create their own custom apps (also referred to as "agents"). These custom apps or agents run alongside native apps on SR Linux Network OS and can can deeply integrate with the rest of the SR Linux system. + +
+ ![arch](https://gitlab.com/rdodin/pics/-/wikis/uploads/6beed5e008a32cffaeca2f6f811137b2/image.png){.img-shadow width="640" } +
Fig. 2 - Custom applications run natively on SR Linux NOS
+
+ + +Applications developed with SR Linux NDK have a set of unique characteristics which set them aside from the traditional off-box automation solutions: + +1. **Native integration with SR Linux system, management and telemetry** +2. **Programming language-neutral** - NDK is based on gRPC, it is possible to use any programming language that supports protobuf, such as [Python](https://learn.srlinux.dev/ndk/guide/dev/py/) and [Go](https://learn.srlinux.dev/ndk/guide/dev/go/) +3. **Deep integration with system components** + + + > **Note:** Browse the [Apps Catalog](https://learn.srlinux.dev/ndk/apps/) with a growing list of NDK apps that Nokia or 3rd parties published. + + +### NDK Architecture + +The SRLinux NDK Architecture is illustrated in the Fig. 3. below. This shows how NDK gRPC service enables custom applications to interact with other SR Linux applications via Impart Database (IDB). +Custom NDK applications app-1 and app-2 interact with other SR Linux subsystems via gRPC-based NDK service that offers access to IDB. SR Linux native apps, like BGP, LLDP, and others also interface with IDB to read and write configuration and state data. + + +-{{image(url='../../../images/20_SRL_Agent_NDK_applications.png')}}- + + + + +In addition to the traditional tasks of reading and writing configuration, NDK-based applications gain low-level access to the SR Linux system. For example, these apps can install FIB routes or listen to LLDP events. + + > **Note:** Developers are welcomed to dig into the [NDK Developers Guide](https://learn.srlinux.dev/ndk/guide/architecture/) to learn all about NDK architecture and how to develop apps with this kit. + +#### SR Linux App logs + +There are two concepts to keep in mind regarding logs and outputs that are generated by SR Linux apps: + + - **Standard Output/Error Redirection**: All apps (native or custom) `stdout/stderr` output is redirected by default to a file (with same name as the app) under `/var/log/srlinux/stdout`. This is useful for debugging or displaying exceptional error conditions - such as an application crash or unhandled exception. + - **Operational Logging**: During normal operation, apps can produce structured log messages that describe their activity, status updates, and internal events. It's up to the app developer to decide how to implement this logic and to where send the logs to. SR Linux native apps are designed to send this logs to the system `syslog` daemon, allowing users to configure syslog rules to control how and where logs are forwarded, such as to external collectors or additional local files. In addition to user-defined rules, SR Linux includes built-in (hard-coded) syslog rules that forward a copy of all native apps logs to files under `/var/log/srlinux/debug/` for centralized access and troubleshooting. + + +## Access specific node/lab details + +For this activity we will use a subset of the main topology, with a pair of leaves (`leaf11` and `leaf13`), a pair of clients (`client11` and `client13`) configured with the Anycast IP, and a third client (`client02`) to test connectivity as illustrated in Fig. 4. below: + +-{{ diagram(url='tiago-amado/srx/main/activity20_srx.clab.drawio', title='Fig. 4 - SR Linux basic agent test setup', page=1) }}- + +Keep in mind the following: + +- An Anycast IP address is already configured at `client11` and `client13`. +- The new agent is deployed at `leaf11` and `leaf13` to allow the configuration of static routes to the anycast IP@ and allow next-hop validation. +- A complete agent solution is deployed in `leaf13`, while `leaf11` agent has missing parts that will be your challenge to complete along this activity. +- Probe client is deployed at `client02` (to test connectivity to the `client11` and `client13` probe responder). + +Let's now start with the activities! + +## Tasks + +In this section we'll provide several tasks that will allow you to learn about SR Linux native agents and the process to onboard a new agent using NDK. The agent will allow to create new static-routes with the next-hop validation capabilities. +We'll need to troubleshoot the onboard process, inspect the logs, configure the static-routes, validate the full operation and add new features to the agent. + +### Inspect the native apps/agents + +First let's briefly inspect the native apps. +Login to leaf11 `sr_cli` and verify which applications are running. Then move to linux `bash` and verify the contents of the `/opt/srlinux/appmgr/` folder. + +///note + The `sr_cli` is SR Linux CLI and the linux `bash` is the underlying Linux shell that is running on SR Linux nodes. You can move between both using the keywords `sr_cli` or `bash`. +/// + + /// tab | View system apps from the SR Linux CLI + ``` bash + /show system application + ``` + /// + /// tab | Output + + ``` bash + --{ + running }--[ ]-- + A:g15-leaf11# show system application + +---------------------+---------+--------------------+-----------------------------------------------------------+--------------------------+ + | Name | PID | State | Version | Last Change | + +=====================+=========+====================+===========================================================+==========================+ + | aaa_mgr | 2095 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.585Z | + | acl_mgr | 2119 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.586Z | + | app_mgr | 1887 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:34.368Z | + | arp_nd_mgr | 2154 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.586Z | + | bfd_mgr | 2198 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.586Z | + | bgp_mgr | 6899 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:57.184Z | + | chassis_mgr | 2224 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.591Z | + | dev_mgr | 1951 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-13T11:27:07.152Z | + | dhcp_client_mgr | 2261 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.591Z | + | dhcp_relay_mgr | | waiting-for-config | | | + | dhcp_server_mgr | | waiting-for-config | | | + | dnsmasq-mgmt | 2789787 | running | 2.89 | 2025-04-14T16:34:09.562Z | + | ethcfm_mgr | | waiting-for-config | | | + | event_mgr | 3331555 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-17T12:36:51.996Z | + | evpn_mgr | 2302 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.591Z | + | fhs_mgr | | waiting-for-config | | | + | fib_mgr | 2336 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.592Z | + | grpc_server | 3379 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:38.456Z | + | idb_server | 2058 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:31.274Z | + | igmp_mgr | | waiting-for-config | | | + | isis_mgr | | waiting-for-config | | | + | json_rpc | 7036 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:57.507Z | + | l2_mac_learn_mgr | 2366 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.592Z | + | l2_mac_mgr | 2445 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.592Z | + | l2_proxy_arp_nd_mgr | | waiting-for-config | | | + | l2_static_mac_mgr | | waiting-for-config | | | + | label_mgr | | waiting-for-config | | | + | lag_mgr | 2488 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.592Z | + | ldp_mgr | | waiting-for-config | | | + | license_mgr | 2535 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.593Z | + | linux_mgr | 2567 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.593Z | + | lldp_mgr | 6946 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:57.337Z | + | log_mgr | 2614 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.593Z | + | macsec_mgr | | waiting-for-config | | | + | mcid_mgr | 2656 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.593Z | + | mfib_mgr | 2707 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.593Z | + | mgmt_server | 2784688 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-14T16:16:50.938Z | + | mirror_mgr | | waiting-for-config | | | + | mpls_mgr | | waiting-for-config | | | + | net_inst_mgr | 2806 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.594Z | + | netconf_mgr | 2673304 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-14T10:58:23.092Z | + | oam_mgr | | waiting-for-config | | | + | oc_mgmt_server | 2672247 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-14T10:58:12.666Z | + | ospf_mgr | | waiting-for-config | | | + | pcc_mgr | | waiting-for-config | | | + | pim_mgr | | waiting-for-config | | | + | plcy_mgr | 3275 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:38.147Z | + | qos_mgr | 3289 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:38.157Z | + | radius_mgr | 2859 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.594Z | + | sdk_mgr | 2874 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:33.594Z | + | segrt_mgr | | waiting-for-config | | | + | sflow_sample_mgr | 2907 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:34.383Z | + | snmp_server-mgmt | 2785392 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-14T16:16:58.385Z | + | sshd-mgmt | 2785340 | running | OpenSSH_9.2p1 Debian-2+deb12u3, OpenSSL 3.0.15 3 Sep 2024 | 2025-04-14T16:16:58.372Z | + | sshd-mgmt-netconf | 2785352 | running | OpenSSH_9.2p1 Debian-2+deb12u3, OpenSSL 3.0.15 3 Sep 2024 | 2025-04-14T16:16:58.379Z | + | static_route_mgr | 2087713 | running | v24.10.3-201-g9d0e2b9371 | 2025-04-11T15:44:54.691Z | + | supported | 1405 | running | | 2025-03-31T15:58:30.377Z | + | te_mgr | | waiting-for-config | | | + | twamp_mgr | | waiting-for-config | | | + | vrrp_mgr | | waiting-for-config | | | + | vxlan_mgr | 3323 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:38.170Z | + | xdp_lc_1 | 2946 | running | v24.10.3-201-g9d0e2b9371 | 2025-03-31T15:58:34.421Z | + +---------------------+---------+--------------------+-----------------------------------------------------------+--------------------------+ + + --{ + running }--[ ]-- + A:g15-leaf11# + ``` + /// + + /// tab | View the native apps folder from bash + ``` bash + cd /opt/srlinux/appmgr/ && ls -al + ``` + /// + /// tab | Output - Native apps folder listing + ``` bash + admin@g15-leaf11:/etc/opt/srlinux$ cd /opt/srlinux/appmgr/ + admin@g15-leaf11:/opt/srlinux/appmgr$ ls -al + total 296 + drwxr-xr-x 4 root root 4096 Feb 19 23:18 . + drwxr-xr-x 1 root root 4096 Feb 19 23:18 .. + drwxr-xr-x 2 root root 4096 Feb 19 23:18 aaa_mgr + -rw-r--r-- 1 root root 2452 Feb 19 22:24 cgroup_profile.json + drwxr-xr-x 2 root root 4096 Feb 19 23:18 logmgr + -rw-rw-rw- 1 root root 3865 Feb 19 02:49 oc_yang_config.conf + -rw-rw-rw- 1 root root 623 Feb 19 02:49 sr_aaa_mgr_config.yml + -rw-rw-rw- 1 root root 1853 Feb 19 02:49 sr_acl_mgr_config.yml + -rw-rw-rw- 1 root root 702 Feb 19 02:49 sr_app_mgr_config.yml + -rw-rw-rw- 1 root root 712 Feb 19 02:49 sr_arp_nd_mgr_config.yml + -rw-rw-rw- 1 root root 756 Feb 19 02:49 sr_bfd_mgr_config.yml + -rw-rw-rw- 1 root root 643 Feb 19 02:49 sr_bgp_mgr_config.yml + -rw-rw-rw- 1 root root 2292 Feb 19 02:49 sr_chassis_mgr_config.yml + -rw-rw-rw- 1 root root 537 Feb 19 02:49 sr_device_mgr_config.yml + -rw-rw-rw- 1 root root 307 Feb 19 02:49 sr_dhcp_client_mgr_config.yml + -rw-rw-rw- 1 root root 676 Feb 19 02:49 sr_dhcp_relay_mgr_config.yml + -rw-rw-rw- 1 root root 585 Feb 19 02:49 sr_dhcp_server_mgr_config.yml + -rw-rw-rw- 1 root root 651 Feb 19 02:49 sr_ethcfm_mgr_config.yml + -rw-rw-rw- 1 root root 632 Feb 19 02:49 sr_event_mgr_config.yml + -rw-rw-rw- 1 root root 781 Feb 19 02:49 sr_evpn_mgr_config.yml + -rw-rw-rw- 1 root root 526 Feb 19 02:49 sr_fhs_mgr_config.yml + -rw-rw-rw- 1 root root 631 Feb 19 02:49 sr_fib_mgr_config.yml + -rw-rw-rw- 1 root root 433 Feb 19 02:49 sr_gretunnel_mgr_config.yml + -rw-rw-rw- 1 root root 728 Feb 19 02:49 sr_grpc_server_config.yml + -rw-rw-rw- 1 root root 387 Feb 19 02:49 sr_idb_server_config.yml + -rw-rw-rw- 1 root root 887 Feb 19 02:49 sr_igmp_mgr_config.yml + -rw-rw-rw- 1 root root 839 Feb 19 02:49 sr_isis_mgr_config.yml + -rw-rw-rw- 1 root root 824 Feb 19 02:49 sr_json_rpc_config.yml + -rw-rw-rw- 1 root root 847 Feb 19 02:49 sr_l2_mac_learn_mgr_config.yml + -rw-rw-rw- 1 root root 1592 Feb 19 02:49 sr_l2_mac_mgr_config.yml + -rw-rw-rw- 1 root root 654 Feb 19 02:49 sr_l2_proxy_arp_nd_mgr_config.yml + -rw-rw-rw- 1 root root 510 Feb 19 02:49 sr_l2_static_mac_mgr_config.yml + -rw-rw-rw- 1 root root 517 Feb 19 02:49 sr_label_mgr_config.yml + -rw-rw-rw- 1 root root 506 Feb 19 02:49 sr_lag_mgr_config.yml + -rw-rw-rw- 1 root root 534 Feb 19 02:49 sr_ldp_mgr_config.yml + -rw-rw-rw- 1 root root 541 Feb 19 02:49 sr_license_mgr_config.yml + -rw-rw-rw- 1 root root 3464 Feb 19 02:49 sr_linux_mgr_config.yml + -rw-rw-rw- 1 root root 598 Feb 19 02:49 sr_lldp_mgr_config.yml + -rw-rw-rw- 1 root root 431 Feb 19 02:49 sr_log_mgr_config.yml + -rw-rw-rw- 1 root root 565 Feb 19 02:49 sr_macsec_mgr_config.yml + -rw-rw-rw- 1 root root 975 Feb 19 02:49 sr_mcid_mgr_config.yml + -rw-rw-rw- 1 root root 1057 Feb 19 02:49 sr_mfib_mgr_config.yml + -rw-rw-rw- 1 root root 945 Feb 19 02:49 sr_mgmt_server_config.yml + -rw-rw-rw- 1 root root 639 Feb 19 02:49 sr_mirror_mgr_config.yml + -rw-rw-rw- 1 root root 497 Feb 19 02:49 sr_mpls_mgr_config.yml + -rw-rw-rw- 1 root root 620 Feb 19 02:49 sr_mplsoam_mgr_config.yml + -rw-rw-rw- 1 root root 992 Feb 19 02:49 sr_net_inst_mgr_config.yml + -rw-rw-rw- 1 root root 723 Feb 19 02:49 sr_netconf_mgr_config.yml + -rw-rw-rw- 1 root root 532 Feb 19 02:49 sr_oam_mgr_config.yml + -rw-rw-rw- 1 root root 635 Feb 19 02:49 sr_oc_mgmt_server_config.yml + -rw-rw-rw- 1 root root 539 Feb 19 02:49 sr_ospf_mgr_config.yml + -rw-rw-rw- 1 root root 494 Feb 19 02:49 sr_pcc_mgr_config.yml + -rw-rw-rw- 1 root root 990 Feb 19 02:49 sr_pim_mgr_config.yml + -rw-rw-rw- 1 root root 380 Feb 19 02:49 sr_pinger_config.yml + -rw-rw-rw- 1 root root 902 Feb 19 02:49 sr_plcy_mgr_config.yml + -rw-rw-rw- 1 root root 653 Feb 19 02:49 sr_pw_mgr_config.yml + -rw-rw-rw- 1 root root 830 Feb 19 02:49 sr_qos_mgr_config.yml + -rw-rw-rw- 1 root root 198 Feb 19 02:49 sr_radius_mgr_config.yml + -rw-rw-rw- 1 root root 326 Feb 19 02:49 sr_sdk_mgr_config.yml + -rw-rw-rw- 1 root root 456 Feb 19 02:49 sr_segrt_mgr_config.yml + -rw-rw-rw- 1 root root 361 Feb 19 02:49 sr_sflow_sample_mgr_config.yml + -rw-rw-rw- 1 root root 603 Feb 19 02:49 sr_static_route_mgr_config.yml + -rw-rw-rw- 1 root root 375 Feb 19 02:49 sr_supportd_config.yml + -rw-rw-rw- 1 root root 954 Feb 19 02:49 sr_te_mgr_config.yml + -rw-rw-rw- 1 root root 817 Feb 19 02:49 sr_tepolicy_mgr_config.yml + -rw-rw-rw- 1 root root 1219 Feb 19 02:49 sr_time_mgr_config.yml + -rw-rw-rw- 1 root root 838 Feb 19 02:49 sr_timing_stack_config.yml + -rw-rw-rw- 1 root root 751 Feb 19 02:49 sr_twamp_mgr_config.yml + -rw-rw-rw- 1 root root 974 Feb 19 02:49 sr_vrrp_mgr_config.yml + -rw-rw-rw- 1 root root 930 Feb 19 02:49 sr_vxlan_mgr_config.yml + -rw-rw-rw- 1 root root 405 Feb 19 02:49 sr_xdp_cpm_config.yml + -rw-rw-rw- 1 root root 542 Feb 19 02:49 sr_xdp_lc_config.yml + -rw-r--r-- 1 root root 1411 Feb 19 22:24 upgradability.json + admin@g15-leaf11:/opt/srlinux/appmgr$ + ``` + /// + + The previous outputs shows the native apps and their definition files. + + +### Inspect the custom agent + +Keep the ssh session to `leaf11` open and create a new one to `leaf13`. +Verify that a custom app `srl_basic_agent` is running. Compare the output against the one from `leaf11`. +Then move to linux bash and verify the contents of the `/etc/opt/srlinux/appmgr/` folder. + + +/// tab | View custom app from the SR Linux CLI +``` +/show system application srl_basic_agent +``` +/// +/// tab | Output +``` bash +--{ running }--[ ]-- +A:g15-leaf13# show system application srl_basic_agent ++-----------------+---------+---------+---------+--------------------------+ +| Name | PID | State | Version | Last Change | ++=================+=========+=========+=========+==========================+ +| srl_basic_agent | 2717566 | running | v1.0 | 2025-04-22T12:13:53.720Z | ++-----------------+---------+---------+---------+--------------------------+ + +--{ running }--[ ]-- +A:g15-leaf13# +``` +/// + +/// tab | List contents of custom app folder in bash +``` bash +cd /etc/opt/srlinux/appmgr/ && ls -al -R +``` +/// +/// tab | Output +``` bash +admin@g15-leaf13:/etc/opt/srlinux/appmgr$ ls -al -R +.: +total 24 +drwxrwxrwx+ 3 srlinux srlinux 4096 Apr 23 17:35 . +drwxrwxrwx+ 14 srlinux srlinux 4096 Apr 22 12:04 .. +drwxrwxrwx 3 admin ntwkuser 4096 Apr 22 12:04 srl_basic_agent +-rw-rw-r--+ 1 admin ntwkuser 887 Apr 22 11:53 srl_basic_agent.yml + +./srl_basic_agent: +total 48 +drwxrwxrwx 3 admin ntwkuser 4096 Apr 22 12:04 . +drwxrwxrwx+ 3 srlinux srlinux 4096 Apr 23 17:35 .. +-rwxrwxrwx 1 admin ntwkuser 21718 Apr 22 12:04 srl_basic_agent.py +-rwxrwxrwx 1 admin ntwkuser 786 Apr 22 11:59 srl_basic_agent.sh +-rwxrwxrwx 1 admin ntwkuser 24 Apr 22 12:02 srl_basic_agent_version.sh +drwxrwxrwx 2 admin ntwkuser 4096 Apr 22 12:01 yang + +./srl_basic_agent/yang: +total 12 +drwxrwxrwx 2 admin ntwkuser 4096 Apr 22 12:01 . +drwxrwxrwx 3 admin ntwkuser 4096 Apr 22 12:04 .. +-rwxrwxrwx 1 admin ntwkuser 2467 Apr 22 12:01 srl_basic_agent.yang +admin@g15-leaf13:/etc/opt/srlinux/appmgr$ +``` +/// + +The previous outputs shows the custom app/agent and its configuration files. +Is the `srl_basic_agent` agent running on both leafs? + +/// details | Solution + type: success +The agent is running at `leaf13` but not at `leaf11`. This is intended, because we introduce some issues that you need to solve in the following tasks! +/// + + +### Onboard agent troubleshoot + +At boot up, the SR Linux App Manager (`app_mgr`) looks for third-party apps `.yml` files in the `/etc/opt/srlinux/appmgr/` directory and loads them automatically. +The onboarding of an NDK agent onto the SR Linux consists in copying [the agent and its files](https://learn.srlinux.dev/ndk/guide/agent/) over to the SR Linux filesystem and placing them in the directories. +The agent installation procedure can be carried out in different ways: [manual, automated or with `deb` packages](https://learn.srlinux.dev/ndk/guide/agent-install-and-ops/). + +The following agent files have been onboarded to both `leaf11` and `leaf13` for you already (using the CLAB bind feature): + +| Component | Filesystem location | +| --------------- | ---------------------------------------- | +| Definition file | `/etc/opt/srlinux/appmgr/srl_basic_agent.yml` | +| Executable file | `/etc/opt/srlinux/appmgr/srl_basic_agent/srl_basic_agent.sh` | +| YANG modules | `/etc/opt/srlinux/appmgr/srl_basic_agent/yang/srl_basic_agent.yang` | +| Agent version | `/etc/opt/srlinux/appmgr/srl_basic_agent/srl_basic_agent_version.sh` | +| Agent Python code | `/etc/opt/srlinux/appmgr/srl_basic_agent/srl_basic_agent.py` | + +///warning +The agent version differs between leaf13 and leaf11. +A complete working agent solution for this activity is deployed in `leaf13`, while `leaf11` agent has missing parts that will be your challenge to complete along this activity. +/// + +///note +The agent files are located in your group's hackaton VM instance at `activities/nos/srlinux/20-SRLinux-basic-agent`. The `leaf11_agent` folder is binded to to the leaf11 `/etc/opt/srlinux/appmgr/`, so you can edit the files directly on the Hackaton VM host using Visual Studio code or any other editor. + +/// + +From the previous task we saw that the agent is running on `leaf13` but not on `leaf11`. + +Your task is to figure out why the agent is not running in `leaf11` and fix the issue. + +/// admonition | Stop and take time to think here + type: question + +- What is the first kind of file that system looks for to discover and load apps? +- Is it possible to check details about the app status, in addition to what is displayed by `show system application`? For example, how can you confirm that the parameters defined in `.yml` file were loaded as expected. +- What logs can be checked to help investigate the reason about why an app is not entering `running` state? + +/// + +/// details | Hint 1 + type: tip + - Check out [Agent Components](https://learn.srlinux.dev/ndk/guide/agent/){:target="_blank"} to know what key fields need to be filled in the definition `.yml` file. + - You may also check examples of other custom apps in the [Apps Catalog](https://learn.srlinux.dev/ndk/apps/){:target="_blank"} +/// + +///details | Hint 2 + type: tip +You need to inspect agent `.yang` file, to know what needs to be filled in `yang-modules:` section of the definition `.yml` file. + + +After modifying the app `.yml` file, how to signal the system to rediscover and process app `.yml` changes? This documentation piece can help you [Agent Installation & Operations - Loading the agent](https://learn.srlinux.dev/ndk/guide/agent-install-and-ops/#loading-the-agent){:target="_blank"} + + +/// + +///details | Hint 3 + type: tip +Search for a path in the `state` datastore that represent detailed status about loaded apps. +/// + +///warning +During your attempts to load the app, if you introduce errors in the `.yml` file that conflicts with native SR Linux apps, the system might get into an unexpected state where you observe symptoms such as: + + - missing information on `running` or `state` datastore + - lose ssh access to the leaf + +To recover, perform a restart of the `mgmt_server` native app with `tools system app-management application mgmt_server restart`. +Take this into account for the remainder tasks of the activity. +/// + +/// details | Solution + type: success + +The `/etc/opt/srlinux/appmgr/srl_basic_agent.yml` is empty at leaf11 and that's why the app is not loading. + +So you need to update your VM file at: +`activities/nos/srlinux/20-SRLinux-basic-agent/leaf11_agent/srl_basic_agent.yml`. + +You may also update leaf11's directly, e.g., with vi: +`/etc/opt/srlinux/appmgr/srl_basic_agent.yml` + + > **Note:** You can copy/paste code directly to `vi`, howhever, to keep your indentation you need to enable paste mode (Esc + `:set paste`) then move to insertation mode and paste your code. + +Once you fix the file you need to reload the app_mgr and verify that the `srl_basic_agent` is running. You may inspect the app status, version and state info with the following commands: + +/// tab | reload app_mgr +``` bash +sr_cli +/tools system app-management application app_mgr reload +/show system application srl_basic_agent +``` +/// +/// tab | output - app summary status +``` bash +--{ running }--[ ]-- +A:g15-leaf11# show system application srl_basic_agent + +-----------------+---------+---------+---------+--------------------------+ + | Name | PID | State | Version | Last Change | + +=================+=========+=========+=========+==========================+ + | srl_basic_agent | 2177265 | running | v0.5 | 2025-04-24T10:48:49.851Z | + +-----------------+---------+---------+---------+--------------------------+ +--{ running }--[ ]-- +A:g15-leaf11# +``` +/// +/// tab | Output - info state (detailed status) +``` bash +--{ running }--[ ]-- +A:g15-leaf11# info from state system app-management application srl_basic_agent + system { + app-management { + application srl_basic_agent { + pid 120406 + state running + last-change "2025-04-27T17:19:33.203Z (37 minutes ago)" + last-start-type cold + author "Nokia SReXperts" + failure-threshold 3 + failure-window 300 + failure-action wait=10 + path /etc/opt/srlinux/appmgr/srl_basic_agent/ + launch-command "sudo /etc/opt/srlinux/appmgr/srl_basic_agent/srl_basic_agent.sh" + search-command "/bin/bash /etc/opt/srlinux/appmgr/srl_basic_agent/srl_basic_agent.sh" + version v0.5 + oom-score-adj 0 + supported-restart-types [ + cold + ] + restricted-operations [ + quit + ] + statistics { + restart-count 52 + } + yang { + modules [ + srl_basic_agent + ] + source-directories [ + /opt/srl_basic_agent/yang + /opt/srlinux/models/iana + /opt/srlinux/models/ietf + /opt/srlinux/models/srl_nokia/models + ] + } + } + } + } + +--{ running }--[ ]-- +A:g15-leaf11# +``` +/// + + +/// + + + +### Inspect the Agent logs + +Open 2 new tabs to the `leaf11` bash and inspect the 2 agent logs files created under `/var/log/srlinux/stdout`: + +- srl_basic_agent.log - file created by the app_mgr to save `stdout/stderr` output of the app. You should see no errors. +- srl_basic_agent_python.log - custom log file created by `srl_basic_agent.py`. You should see keepalives + +/// tab | View agent logs +``` bash +tail -f /var/log/srlinux/stdout/srl_basic_agent.log +tail -f /var/log/srlinux/stdout/srl_basic_agent_python.log +``` +/// + +### Configure the new static routes + +Now that the agent is running on both leafs, its time to put it into action! The objective is to ensure reachability between the probe client and the probe responders' Anycast IP address. To accomplish this, you will use the custom agent to configure the static routes.

+ +The next-hop IP address reachability shall be periodically tested, such that when the next-hop becomes unreachable, respective static-route is automatically deactivated by the agent until reachability is restored. + +**Your next task is to configure the new static routes in `leaf11` and `leaf13` under `ipvrf201` as shown in the diagram below:** + + +-{{ diagram(url='tiago-amado/srx/main/activity20_srx.clab.drawio', title='Fig. 4 - SR Linux basic agent logic setup', page=2) }}- + +/// admonition + type: question + +The agent should expose a new configuration knob in `candidate` datastore that allows to manage the static routes. Can you find it out? +/// + +/// details | Tip + type: tip + +You should see that under any ip-vrf instance there's a new option available: `static-routes-ndk` + +/// tab | New agent Static-route +``` bash +--{ +! candidate shared default }--[ network-instance ipvrf201 ]-- +A:g15-leaf11# static-routes + admin-state + static-routes + static-routes-ndk + + + + +Local commands: + static-routes + static-routes-ndk + SReXperts - New static agent. + + +--{ +! candidate shared default }--[ network-instance ipvrf201 ]-- +``` +/// +/// + + +/// details | Solution + type: success + +/// tab | Leaf11 +``` bash +exit all +enter candidate +network-instance ipvrf201 +static-routes-ndk route 192.168.31.1/32 admin-state enable next-hop 192.168.30.11 cpe-check admin-state enable +commit now +``` +/// + +/// tab | Leaf13 +``` bash +exit all +enter candidate +network-instance ipvrf201 +static-routes-ndk route 192.168.31.1/32 admin-state enable next-hop 192.168.30.13 cpe-check admin-state enable +commit now +``` +/// +/// + + + +### Verify the agent normal operation + +Now that you have configured both `leaf11` and `leaf13`, you can verify the agent operation. +The agent is supposed to consume configuration and populate state under the YANG path `/network-instance static-routes-ndk`. + +/// tab | Agent validation +``` bash +info from state / network-instance ipvrf201 static-routes-ndk +/show network-instance ipvrf201 route-table ipv4-unicast prefix 192.168.31.1/32 +ping network-instance ipvrf201 192.168.31.1 -c 2 +traceroute 192.168.31.1 network-instance ipvrf201 +``` +/// +/// tab | Output leaf13 - info from state +``` bash +--{ + running }--[ ]-- +A:g15-leaf13# info from state / network-instance ipvrf201 static-routes-ndk + network-instance ipvrf201 { + static-routes-ndk { + route 192.168.31.1/32 { + admin-state enable + next-hop 192.168.30.13 + cpe-check { + admin-state enable + is-alive true + probe-statistics { + successful 17998 + failed 0 + } + } + } + } + } +``` +/// +/// tab | Output leaf11 - info from state +``` bash +--{ + running }--[ network-instance ipvrf201 static-routes-ndk ]-- +A:g15-leaf11# info from state / network-instance ipvrf201 static-routes-ndk + +``` +/// +/// tab | Output - route-table +``` bash +--{ + running }--[ ]-- +A:g15-leaf11# show network-instance ipvrf201 route-table ipv4-unicast prefix 192.168.31.1/32 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IPv4 unicast route table of network instance ipvrf201 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +| Prefix | ID | Route Type | Route Owner | Active | Origin | Metric | Pref | Next-hop (Type) | Next-hop | Backup Next-hop | Backup Next-hop | +| | | | | | Network | | | | Interface | (Type) | Interface | +| | | | | | Instance | | | | | | | ++===========================+=======+============+======================+==========+==========+=========+============+=================+=================+=================+======================+ +| 192.168.31.1/32 | 0 | bgp-evpn | bgp_evpn_mgr | False | ipvrf201 | 0 | 170 | 10.46.15.35/32 | | | | +| | | | | | | | | (indirect/vxlan | | | | +| | | | | | | | | ) | | | | +| 192.168.31.1/32 | 10 | ndk1 | srl_basic_agent | True | ipvrf201 | 10 | 10 | 192.168.30.0/24 | irb0.101 | | | +| | | | | | | | | (indirect/local | | | | +| | | | | | | | | ) | | | | ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--{ + running }--[ ]-- +A:g15-leaf11# +``` +/// + +/// tab | Output ping +``` bash +--{ + running }--[ ]-- +A:g15-leaf11# ping network-instance ipvrf201 192.168.31.1 -c 2 +Using network instance ipvrf201 +PING 192.168.31.1 (192.168.31.1) 56(84) bytes of data. +64 bytes from 192.168.31.1: icmp_seq=1 ttl=64 time=1.84 ms +64 bytes from 192.168.31.1: icmp_seq=2 ttl=64 time=2.21 ms + +--- 192.168.31.1 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1001ms +rtt min/avg/max/mdev = 1.842/2.027/2.212/0.185 ms + +--{ + running }--[ ]-- +A:g15-leaf11# +``` +/// +/// tab | Output traceroute +``` bash +--{ + running }--[ ]-- +A:g15-leaf11# traceroute 192.168.31.1 network-instance ipvrf201 +Using network instance ipvrf201 +traceroute to 192.168.31.1 (192.168.31.1), 30 hops max, 60 byte packets + 1 192.168.31.1 (192.168.31.1) 1.615 ms 1.563 ms 1.551 ms + +--{ + running }--[ ]-- +A:g15-leaf11# +``` +/// + + +Note from the output that there are 2 routes to `192.168.31.1`, the static-route installed by the agent identified as `ndk1`, and the route received from the other leaf through `bgp-evpn`. Only the local route is active, being the `bgp-evpn` in standby.

+Note that there is also no `state` populated in `leaf11`. This is one of the missing parts that you will be challenged to complete in a later task.

+ +### Verify the agent operation under failure + +To properly test the end-to-end the agent operation including failure scenarios, a probe client and probe responders will be used according to the table below: + + +| Component | Filesystem location | Nodes | +| --------------- | ---------------------------- | ------------- | +| probe client | `/probe.sh` | `client02` | +| probe responder | `/probe-responder.sh` | `client11` and `client13` | + + +The `probe-responder`is already installed and running at `client11` and `client13`. +On `client02` start the probe requests and verify that you're getting answers from both `client11` and `client13` (rate of 2 requests per second). + + +/// tab | Start probe client +``` bash +/probe.sh 192.168.31.1 +``` +/// + +/// tab | Output +``` bash +/probe.sh 192.168.31.1 +Probing 192.168.31.1:9999 using TCP... +Tue Apr 29 16:58:01 UTC 2025 - Response from client13 +Tue Apr 29 16:58:01 UTC 2025 - Response from client11 +Tue Apr 29 16:58:02 UTC 2025 - Response from client13 +Tue Apr 29 16:58:02 UTC 2025 - Response from client13 +Tue Apr 29 16:58:03 UTC 2025 - Response from client11 +Tue Apr 29 16:58:03 UTC 2025 - Response from client11 +Tue Apr 29 16:58:04 UTC 2025 - Response from client11 +^C + +``` +/// + +Recall that the destination is an anycast address and sessions are load balanced across available targets. +If you don't get the expected result, have a look to the troobleshoot tips below, otherwise skip it and proceed the exercise. + +/// details | Troubleshoot the probe operation + type: tip + +If you face any issues with the probes follow these steps: + +1. Ensure the probe client and responders files exists at the hosts as listed in the table above. +2. Verify the file execution permissions and the script code. +3. verify that the responder is running on both `client11` and `client13` with: `ps -ef | grep probe` + - If the probes are not running start them with: `setsid /probe-responder.sh` +4. Verify ip connectivity, arp, mac and routing tables. + + +/// tab | verify probe responder +``` bash +ps -ef | grep probe +``` +/// + +/// tab | Start probe responder +``` bash +setsid /probe-responder.sh +``` +/// + +/// tab | Code probe client +``` bash +#!/bin/bash +#usage: ./probe.sh [interval in seconds] + +# Activity #20 SR Linux basic agent - Probe client + +TARGET="$1" +PORT="9999" +INTERVAL="${2:-0.5}" # Default interval between probes (in seconds) +TIMEOUT=1 +echo "Probing $TARGET:$PORT using TCP..." + +while true; do + RESPONSE=$(echo "ping" | socat -T "$TIMEOUT" - TCP:"$TARGET":$PORT,connect-timeout="$TIMEOUT") + + if [ -n "$RESPONSE" ]; then + echo "$(date) - Response from $RESPONSE" + sleep "$INTERVAL" + else + echo "$(date) - No response or refused connection" + sleep $INTERVAL + fi + +done +``` +/// + +/// tab | Code probe responder +``` bash +#!/bin/bash +# start the probe responder: setsid /probe-responder.sh + +# Activity #20 SR Linux basic agent - Probe server + +#redirect stderr and stdout to a log file +exec >/tmp/"$0".log 2>&1 + +PORT=9999 +HOSTNAME=$(hostname) + +echo "Responder listening on TCP port $PORT..." +socat TCP-LISTEN:$PORT,reuseaddr,fork SYSTEM:"echo $HOSTNAME" +``` +/// + +/// + + + +Now lets introduce a failure to view the agent in action. + +1. Open a session to `client11` and `client13` to verify the routing tables before and after the failure. +2. Keep an open session for `client02` with the probe client running. +3. Log in to `client11` and shutdown the interface `eth1.101` with the commands below. + + +/// tab | Client11 ifdown +``` bash +## show the interface status +ip -br addr show dev eth1.101 +# disable the interface +sudo ifdown eth1.101 + +``` +/// + + +/// tab | Client11 ifup +``` bash +# enable the interface +sudo ifup eth1.101 +## show the interface status +ip -br addr show dev eth1.101 +``` +/// + + +/// tab | Output Client02 +``` bash +Tue Apr 29 19:03:53 UTC 2025 - Response from client13 +Tue Apr 29 19:03:53 UTC 2025 - Response from client13 +Tue Apr 29 19:03:54 UTC 2025 - Response from client11 +Tue Apr 29 19:03:54 UTC 2025 - Response from client11 +Tue Apr 29 19:03:55 UTC 2025 - Response from client13 +2025/04/29 19:03:56 socat[15650] E connecting to AF=2 192.168.31.1:9999: Operation timed out +Tue Apr 29 19:03:56 UTC 2025 - No response or refused connection +Tue Apr 29 19:03:57 UTC 2025 - Response from client13 +Tue Apr 29 19:03:57 UTC 2025 - Response from client13 +Tue Apr 29 19:03:58 UTC 2025 - Response from client13 +Tue Apr 29 19:03:58 UTC 2025 - Response from client13 +``` +/// + +/// tab | Output leaf11 +``` bash +--{ + running }--[ ]-- +A:g15-leaf11# show network-instance ipvrf201 route-table ipv4-unicast prefix 192.168.31.1/32 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IPv4 unicast route table of network instance ipvrf201 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +| Prefix | ID | Route Type | Route Owner | Active | Origin | Metric | Pref | Next-hop (Type) | Next-hop | Backup Next-hop | Backup Next-hop | +| | | | | | Network | | | | Interface | (Type) | Interface | +| | | | | | Instance | | | | | | | ++===========================+=======+============+======================+==========+==========+=========+============+=================+=================+=================+======================+ +| 192.168.31.1/32 | 0 | bgp-evpn | bgp_evpn_mgr | False | ipvrf201 | 0 | 170 | 10.46.15.35/32 | | | | +| | | | | | | | | (indirect/vxlan | | | | +| | | | | | | | | ) | | | | +| 192.168.31.1/32 | 10 | ndk1 | srl_basic_agent | True | ipvrf201 | 10 | 10 | 192.168.30.0/24 | irb0.101 | | | +| | | | | | | | | (indirect/local | | | | +| | | | | | | | | ) | | | | ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--{ + running }--[ ]-- +A:g15-leaf11# show network-instance ipvrf201 route-table ipv4-unicast prefix 192.168.31.1/32 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IPv4 unicast route table of network instance ipvrf201 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +| Prefix | ID | Route Type | Route Owner | Active | Origin | Metric | Pref | Next-hop (Type) | Next-hop | Backup Next-hop | Backup Next-hop | +| | | | | | Network | | | | Interface | (Type) | Interface | +| | | | | | Instance | | | | | | | ++===========================+=======+============+======================+==========+==========+=========+============+=================+=================+=================+======================+ +| 192.168.31.1/32 | 0 | bgp-evpn | bgp_evpn_mgr | True | ipvrf201 | 0 | 170 | 10.46.15.35/32 | | | | +| | | | | | | | | (indirect/vxlan | | | | +| | | | | | | | | ) | | | | ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--{ + running }--[ ]-- +A:g15-leaf11# +Current mode: + running +``` +/// + +/// tab | Output leaf13 +``` bash +--{ + running }--[ ]-- +A:g15-leaf13# show network-instance ipvrf201 route-table ipv4-unicast prefix 192.168.31.1/32 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IPv4 unicast route table of network instance ipvrf201 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +| Prefix | ID | Route Type | Route Owner | Active | Origin | Metric | Pref | Next-hop (Type) | Next-hop | Backup Next-hop | Backup Next-hop | +| | | | | | Network | | | | Interface | (Type) | Interface | +| | | | | | Instance | | | | | | | ++===========================+=======+============+======================+==========+==========+=========+============+=================+=================+=================+======================+ +| 192.168.31.1/32 | 0 | bgp-evpn | bgp_evpn_mgr | False | ipvrf201 | 0 | 170 | 10.46.15.33/32 | | | | +| | | | | | | | | (indirect/vxlan | | | | +| | | | | | | | | ) | | | | +| 192.168.31.1/32 | 10 | ndk1 | srl_basic_agent | True | ipvrf201 | 10 | 10 | 192.168.30.0/24 | irb0.101 | | | +| | | | | | | | | (indirect/local | | | | +| | | | | | | | | ) | | | | ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--{ + running }--[ ]-- +A:g15-leaf13# + +--{ + running }--[ ]-- +A:g15-leaf13# show network-instance ipvrf201 route-table ipv4-unicast prefix 192.168.31.1/32 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IPv4 unicast route table of network instance ipvrf201 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +| Prefix | ID | Route Type | Route Owner | Active | Origin | Metric | Pref | Next-hop (Type) | Next-hop | Backup Next-hop | Backup Next-hop | +| | | | | | Network | | | | Interface | (Type) | Interface | +| | | | | | Instance | | | | | | | ++===========================+=======+============+======================+==========+==========+=========+============+=================+=================+=================+======================+ +| 192.168.31.1/32 | 10 | ndk1 | srl_basic_agent | True | ipvrf201 | 10 | 10 | 192.168.30.0/24 | irb0.101 | | | +| | | | | | | | | (indirect/local | | | | +| | | | | | | | | ) | | | | ++---------------------------+-------+------------+----------------------+----------+----------+---------+------------+-----------------+-----------------+-----------------+----------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--{ + running }--[ ]-- +A:g15-leaf13# +``` +/// + +/// tab | Output PE2 +``` bash +[/] +A:admin@g15-pe2# show router "300" route-table 192.168.31.1 + +=============================================================================== +Route Table (Service: 300) +=============================================================================== +Dest Prefix[Flags] Type Proto Age Pref + Next Hop[Interface Name] Metric +------------------------------------------------------------------------------- +192.168.31.1/32 Remote EVPN-IFL 00h04m48s 170 + 10.46.15.33 (tunneled:VXLAN:201) 0 +192.168.31.1/32 Remote EVPN-IFL 00h04m48s 170 + 10.46.15.35 (tunneled:VXLAN:201) 0 +------------------------------------------------------------------------------- +No. of Routes: 2 +Flags: n = Number of times nexthop is repeated + B = BGP backup route available + L = LFA nexthop available + S = Sticky ECMP requested +=============================================================================== + +[/] +A:admin@g15-pe2# show router "300" route-table 192.168.31.1 + +=============================================================================== +Route Table (Service: 300) +=============================================================================== +Dest Prefix[Flags] Type Proto Age Pref + Next Hop[Interface Name] Metric +------------------------------------------------------------------------------- +192.168.31.1/32 Remote EVPN-IFL 00h58m22s 170 + 10.46.15.35 (tunneled:VXLAN:201) 0 +------------------------------------------------------------------------------- +No. of Routes: 1 +Flags: n = Number of times nexthop is repeated + B = BGP backup route available + L = LFA nexthop available + S = Sticky ECMP requested +=============================================================================== + +[/] +A:admin@g15-pe2# +``` +/// + +Note that convergence is very fast and immediately after the failure all the probes requests are responded by `leaf13` only. +The leaf11 removes its local static-route and installs the `bgp-evpn` route received from `leaf13`. +`leaf13` has only its own local route and PE2 has only one `bgp-evpn` from `leaf13`. + + +///warning +**Don't forget to bring up the interface again!** +/// + + +### Make leaf11 agent populate the state datastore +As you have observed in the "Verify the agent normal operation" task, the agent in `leaf11` is not populating the `state` datastore. +Can you find out why and fix the issue? + + +/// details | Hint 1 +Analyze the `srl_basic_agent.py` code in leaf11. Is there any method or function responsible to update the `state` datastore? +/// +/// details | Hint 2 +The function `update_state_datastore` needs to be completed. +/// +/// details | Hint 3 +- Check the [NDK documentation](https://ndk.srlinux.dev/doc/sdk?version=v0.4.0){:target="_blank"} to find what is the appropriate gRPC call to update the `state` datastore +- Check the [Python NDK bindings](https://github.com/nokia/srlinux-ndk-py/tree/v0.4.0){:target="_blank"} to find the respective Python function for the gRPC call. +- Check examples from similar code in this agent, or from the [Apps Catalog](https://learn.srlinux.dev/ndk/apps/){:target="_blank"} +/// +/// note +You need to restart the agent for the python code changes to take effect. What command you can use for this? +Check the [Agent Install and Operations](https://learn.srlinux.dev/ndk/guide/agent-install-and-ops/). +/// + +Once you complete this task the `state` will be populated as shown below: + +/// tab | Output static-routes-ndk info from state +``` +--{ + running }--[ network-instance ipvrf201 static-routes-ndk ]-- +A:g15-leaf11# info from state + route 192.168.31.1/32 { + admin-state enable + next-hop 192.168.30.11 + cpe-check { + admin-state enable + is-alive true + } + } +``` +/// + +/// details | Solution + type: success +```py +def update_state_datastore(js_path, js_data): + + # create gRPC client stub for the Telemetry Service + telemetry_stub = telemetry_service_pb2_grpc.SdkMgrTelemetryServiceStub(channel) + + # Build an telemetry update service request + telemetry_update_request = telemetry_service_pb2.TelemetryUpdateRequest() + + # Add the YANG Path and Attribute/Value pair to the request + telemetry_info = telemetry_update_request.state.add() + telemetry_info.key.js_path = js_path + telemetry_info.data.json_content = js_data + + # Log the request + logging.info(f"Telemetry_Update_Request ::\{telemetry_update_request}") + + # Call the telemetry RPC + telemetry_response = telemetry_stub.TelemetryAddOrUpdate( + request=telemetry_update_request, + metadata=metadata) + + return telemetry_response +``` +/// + +### Add a feature to store basic statistics about next-hop-check probes + +We would like really to challenge you for your final task. +Modify leaf11's agent so that users are able to track (via the `state` datastore) the total number of successful and failed next-hop-check icmp probes (per static-route). +Here's an example of what's expected: + +/// tab | Output Probe-stats +```bash hl_lines="10-11" +--{ + candidate shared default }--[ network-instance ipvrf201 static-routes-ndk route +192.168.31.1/32 ]-- +A:g15-leaf11# info from state + admin-state enable + next-hop 192.168.30.11 + cpe-check { + admin-state enable + is-alive false + probe-statistics { + successful 73 + failed 539 + } + } + +``` + +/// details | Tip + type: tip + +You first need to edit the `srl_basic_agent.yang` to include a new container `probe-statistics` under the container `cpe-check` including leaves `uint64` for each counter. + +Then you need to edit the `srl_basic_agent.py` and: + +1. add new variables for the counters; +2. update the `update_telemetry` method; +3. update the `update_aliveness` method to update the counters and telemetry. + + +Finally, reload the `app_mgr` and verify that the `srl_basic_agent` is running: + +/// + + + +/// details | Solution + type: success + +The outputs bellow shown the required code highlighted in blue. + + +/// tab | Code srl_basic_agent.yang +``` py hl_lines="58-68" linenums="1" +module srl_basic_agent { + yang-version 1.1; + namespace "urn:srl_sdk/srl_basic_agent"; + prefix srl_basic_agent; + + import srl_nokia-common { + prefix srl_nokia-comm; + } + import srl_nokia-network-instance { + prefix srl_nokia-netinst; + } + + revision 2024-07-31 { + description + "SRLinux 24.7.1"; +} + + grouping static-routes-ndk-top { + container static-routes-ndk { + presence "configure alternative static routes"; + + description + "SReXperts - ndk static-routes agent."; + list route { + max-elements 16384; + key "prefix"; + leaf prefix { + must "not(../../../srl_nokia-netinst:type = 'srl_nokia-netinst:host')" { + error-message "Static route configuration not valid in network instance of type host"; + } + type srl_nokia-comm:ip-prefix; + } + leaf admin-state { + type srl_nokia-comm:admin-state; + default "enable"; + description + "Administratively enable or disable the static route."; + } + leaf next-hop { + type srl_nokia-comm:ip-address-with-zone; + description + "The next-hop IPv4 or IPv6 address + + If the IPv6 address is a link-local address then the zoned format must be used"; + } + container cpe-check { + leaf admin-state { + type srl_nokia-comm:admin-state; + default "enable"; + description + "Probe the next-hop periodically using ICMP echo request."; + } + + leaf is-alive { + type boolean; + config false; + } + container probe-statistics { + config false; + leaf successful { + type uint64; + config false; + } + leaf failed { + type uint64; + config false; + } + } + } + } + } + } + + augment "/srl_nokia-netinst:network-instance" { + uses static-routes-ndk-top; + } +} + + +``` +/// + + +/// tab | Code srl_basic_agent.py +``` py hl_lines="9-10 36-39 44-47" linenums="1" +#(...) +class StaticRoute(): + def __init__(self, data, route, network_instance): + self.mutex = threading.Lock() + self.admin_enabled = None + self.cpe_check_enabled = None + self.cpe_check_thread = None + self.cpe_check_is_alive = None + self.cpe_check_stat_successes = 0 + self.cpe_check_stat_failures = 0 + self.next_hop = None + self.network_instance = network_instance + self.route = route + self.installed = False + self.deleted = False + self.update_config(data) + self.evaluate() + #(...) + def update_telemetry(self): + js_path = f'.network_instance{{.name=="{self.network_instance}"}}.static_routes_ndk.route{{.prefix=="{self.route}"}}' + + js_data = { + "admin_state": 'ADMIN_STATE_enable' if self.admin_enabled else 'ADMIN_STATE_disable', + "next_hop": self.next_hop, + "cpe_check": { + "admin_state": 'ADMIN_STATE_enable' if self.cpe_check_enabled else 'ADMIN_STATE_disable', + } + } + + if self.deleted: + delete_state_datastore(js_path) + return + + if self.cpe_check_thread: + js_data['cpe_check']['is-alive'] = self.cpe_check_is_alive + js_data['cpe_check']['probe-statistics'] = { + "successful": self.cpe_check_stat_successes, + "failed": self.cpe_check_stat_failures + } + + update_state_datastore(js_path=js_path, js_data=json.dumps(js_data)) + #(...) + def update_aliveness(self, alive): + if alive: + self.cpe_check_stat_successes += 1 + else: + self.cpe_check_stat_failures += 1 + + #if alive status changed, evaluate route and update telemetry + if alive != self.cpe_check_is_alive: + self.cpe_check_is_alive = alive + self.evaluate() + + self.update_telemetry() + #(...) +``` +/// + +/// tab | reload app_mgr +``` bash +sr_cli +/tools system app-management application app_mgr reload +/show system application srl_basic_agent +``` +/// +/// tab | output +``` bash +--{ running }--[ ]-- +A:g15-leaf11# show system application srl_basic_agent + +-----------------+---------+---------+---------+--------------------------+ + | Name | PID | State | Version | Last Change | + +=================+=========+=========+=========+==========================+ + | srl_basic_agent | 2177265 | running | v1.0 | 2025-04-24T10:48:49.851Z | + +-----------------+---------+---------+---------+--------------------------+ +--{ running }--[ ]-- +A:g15-leaf11# +``` +/// + +/// + + +And this concludes the activities we've prepared for you. +These activities demonstrated how SR Linux agents work, how you can use NDK to create your own agents and the flexibility you have with SR Linux custom agents. + + +## Summary and review + +Congratulations! If you have got this far you have completed this activity and achieved the following: + +- Explored the NDK architecture. +- Understood the native and custom agents/apps file and folder structure and how to onboard new agents. +- Verified agent operations, their logs and their state info. +- Configured the new `SR_CLI static-route` provided by the agent, and tested it under normal and network failure situations. +- Updated the custom agent YANG and Python scripts to include telemetry stats. + + +You may explore the references for more information about developing Python or Go SR Linux agents. + +We hope you find this information useful and that you liked the activity. +Now we invite you to try another amazing Hackathon activity. + + + diff --git a/docs/nos/srlinux/advanced/nos-srlinux-activity-18.md b/docs/nos/srlinux/advanced/nos-srlinux-activity-18.md index 270a02e..5ba801f 100644 --- a/docs/nos/srlinux/advanced/nos-srlinux-activity-18.md +++ b/docs/nos/srlinux/advanced/nos-srlinux-activity-18.md @@ -30,10 +30,10 @@ This activity demonstrates how the open-source tool Scapy (pre-installed on SR L Consider the following scenario:

Unidirectional packet loss was reported for client traffic sourced from `client11` destined for `client13`. -After some trial and error actions, customer found the issue was resolved after disabling the underlay BGP session between :material-router: spine11 and :material-router: leaf11, diverting the traffic away from that link.

+After some trial and error actions, customer found the issue was resolved after disabling the underlay BGP session between :material-router: spine11 and :material-router: leaf11, diverting the traffic away from that link.

The workaround applied on :material-router: leaf11 is: -``` +``` delete / network-instance default protocols bgp dynamic-neighbors interface ethernet-1/49.0 ``` ![DC1](../../../images/18-custom-traffic-scapy.svg) @@ -44,11 +44,11 @@ Your goal is to:

3. Verify the issue is resolved, before reactivating BGP session. ## Technology explanation -To tackle this activity you will need to combine different tools present in SR Linux that will allow to manipulate and observe network traffic.

+To tackle this activity you will need to combine different tools present in SR Linux that will allow to manipulate and observe network traffic.

A basic level of Python, Linux OS, and SR Linux CLI navigation proficiency is assumed for this activity.

-The key technologies used in this activity are described here: +The key technologies used in this activity are described here: ### SR Linux routed interfaces In SR Linux, any of the following objects is considered a routed interface: @@ -83,8 +83,8 @@ A:n1# bash network-instance default ip address show e1-1.0 /// ### Scapy -[Scapy](https://scapy.net/){:target="_blank"} is a powerful open-source interactive packet manipulation program. It is able to craft or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. -It comes already pre-installed and is available from the SR Linux python virtual-environment. We can use it to send custom packets out of SR Linux routed interfaces. +[Scapy](https://scapy.net/){:target="_blank"} is a powerful open-source interactive packet manipulation program. It is able to craft or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. +It comes already pre-installed and is available from the SR Linux python virtual-environment. We can use it to send custom packets out of SR Linux routed interfaces. /// note Make sure to launch scapy in the same network-instance as the target interface and from a user with **super-user** privilege. @@ -95,8 +95,8 @@ You can use scapy through an interactive shell or by running python scripts. ```bash title="opening interactive shell from SR Linux CLI" A:n1# bash network-instance default /opt/srlinux/python/virtual-env/bin/scapy - - aSPY//YASa + + aSPY//YASa apyyyyCY//////////YCa | sY//////YSpcs scpCY//Pp | Welcome to Scapy ayp ayyyyyyySCP//Pp syY//C | Version 2.5.0 @@ -109,17 +109,17 @@ A:n1# bash network-instance default /opt/srlinux/python/virtual-env/bin/scapy scccccp///pSP///p p//Y | day on earth. sY/////////y caa S//P | -- Lao-Tze cayCyayP//Ya pY/Ya | - sY/PsY////YCc aC//Yp - sc sccaCY//PCypaapyCP//YSs - spCPY//////YPSps - ccaacs - ->>> -``` -/// + sY/PsY////YCc aC//Yp + sc sccaCY//PCypaapyCP//YSs + spCPY//////YPSps + ccaacs + +>>> +``` +/// /// tab | script -``` title="/etc/opt/srlinux/scapytest.py" +``` title="/etc/opt/srlinux/scapytest.py" from scapy.all import * p=Ether(src='1A:CF:01:FF:00:00',dst='1A:CF:01:FF:00:01')/IP(src='192.168.1.2',dst='192.168.1.1')/ICMP(type=8)/Raw(load='hackaton2025') sendp(p,iface='e1-50.0') @@ -135,7 +135,7 @@ Sent 1 packets. This allows you to edit scripts directly from the host using Visual Studio Code or any other editor. /// /// tip | CLI alias -Create an environment [alias](https://learn.srlinux.dev/cli/#aliases){:target="_blank"} to easily run scapy scripts located in `/etc/opt/srlinux/` from your SR Linux CLI. +Create an environment [alias](https://learn.srlinux.dev/cli/#aliases){:target="_blank"} to easily run scapy scripts located in `/etc/opt/srlinux/` from your SR Linux CLI. ``` title="run-scapy alias" environment alias "run-scapy {name}" "bash network-instance default /opt/srlinux/python/virtual-env/bin/python /etc/opt/srlinux/{name}" ``` @@ -175,17 +175,17 @@ p p.show() ``` ```python -###[ Ethernet ]### +###[ Ethernet ]### dst = 1A:CF:01:FF:00:01 src = 1A:CF:01:FF:00:00 type = IPv4 -###[ IP ]### +###[ IP ]### version = 4 ihl = None tos = 0x0 len = None id = 1 - flags = + flags = frag = 0 ttl = 64 proto = icmp @@ -193,14 +193,14 @@ p.show() src = 192.168.1.2 dst = 192.168.1.1 \options \ -###[ ICMP ]### +###[ ICMP ]### type = echo-request code = 0 chksum = None id = 0x0 seq = 0x0 unused = '' -###[ Raw ]### +###[ Raw ]### load = 'hackaton2025' ``` /// @@ -212,17 +212,17 @@ p.show() p.show2() ``` ```python -###[ Ethernet ]### +###[ Ethernet ]### dst = 1a:cf:01:ff:00:01 src = 1a:cf:01:ff:00:00 type = IPv4 -###[ IP ]### +###[ IP ]### version = 4 ihl = 5 tos = 0x0 len = 40 id = 1 - flags = + flags = frag = 0 ttl = 64 proto = icmp @@ -230,14 +230,14 @@ p.show2() src = 192.168.1.2 dst = 192.168.1.1 \options \ -###[ ICMP ]### +###[ ICMP ]### type = echo-request code = 0 chksum = 0xf6ea id = 0x0 seq = 0x0 unused = '' -###[ Raw ]### +###[ Raw ]### load = 'hackaton2025' ``` /// @@ -276,7 +276,7 @@ sendp(p,iface='e1-1.0') . Sent 1 packets. ``` -/// note +/// note checksum fields are calculated automatically if not defined /// /// @@ -298,7 +298,7 @@ pkts[0] /// details | finding class arguments type: tip Use help function, or check [Scapy API reference](https://scapy.readthedocs.io/en/latest/api/scapy.html){:target="_blank"} -```python +```python help(ICMPv6EchoRequest) ``` ```python @@ -333,17 +333,17 @@ It's possible to sniff any containerlab node link by [manually executing a shell /// ## Tasks -**You should read these tasks from top-to-bottom before beginning the activity**. +**You should read these tasks from top-to-bottom before beginning the activity**. -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. /// warning -MAC and IP addresses displayed in the outputs will differ from your Hackacton VM instance. +MAC and IP addresses displayed in the outputs will differ from your Hackathon VM instance. /// ### Practice scapy This is an optional introductory exercise to get familiar with scapy.

-Goal: generate an IPv6 `echo request` with payload "hackaton2025" from leaf11 to leaf13 (using system IPv6 addresses), via spine11. +Goal: generate an IPv6 `echo request` with payload "hackaton2025" from leaf11 to leaf13 (using system IPv6 addresses), via spine11. Verify that leaf13 successfully responds with an `echo reply`.

Start by opening 3 separate CLI sessions, one to each node: leaf11, spine11, leaf13. You can connect from your Hackaton VM instance using the following commands: @@ -358,10 +358,10 @@ ssh admin@clab-srexperts-leaf13 ``` #### Test ping from CLI -Let's start by testing a regular ping using CLI.

+Let's start by testing a regular ping using CLI.

Consult the `leaf11` and `leaf13` IPv6 addresses of the system interface: -```title="example - consulting leaf11 system address" hl_lines="11" +```title="example - consulting leaf11 system address" hl_lines="11" --{ + running }--[ ]-- A:g15-leaf11# /show interface system0 ======================================================================= @@ -399,7 +399,7 @@ with `verbose` option, more details of the packet can be seen ```title="traffic-monitor using verbose option" /tools system traffic-monitor protocol icmp6 destination-address fd00:fde8::15:35 source-address fd00:fde8::15:33 verbose ``` -/// +/// /// tab | expected output ```title="traffic-monitor" A:g15-leaf13# /tools system traffic-monitor protocol icmp6 destination-address fd00:fde8::15:35 source-address fd00:fde8::15:33 @@ -518,9 +518,9 @@ ethernet-1/49 is up, speed 100G, type None ====================================================================== ``` The subinterface is `ethernet-1/49.0` SR Linux CLI, which is attached to the network-instance `default` (the instance associated with the global routing-table).
-///admonition +///admonition type: question -What is correspondent name of this subinterface on Linux? +What is corresponding name of this subinterface on Linux? /// /// @@ -537,7 +537,7 @@ Alternatively, you can login to the next-hop and directly inspect it from the in /// /// tab | expected output ```bash hl_lines="5" -A:g15-leaf11# /show arpnd neighbors +A:g15-leaf11# /show arpnd neighbors +----------------+----------------+------------------------+---------+--------------------+---------------+-------------------+-----------+ | Interface | Subinterface | Neighbor | Origin | Link layer address | Current state | Next state change | Is Router | +================+================+========================+=========+====================+===============+===================+===========+ @@ -588,8 +588,8 @@ bash network-instance default A:g15-leaf11# bash network-instance default admin@g15-leaf11:~$ /opt/srlinux/python/virtual-env/bin/scapy AutoCompletion, History are disabled. - - aSPY//YASa + + aSPY//YASa apyyyyCY//////////YCa | sY//////YSpcs scpCY//Pp | Welcome to Scapy ayp ayyyyyyySCP//Pp syY//C | Version 2.5.0 @@ -603,22 +603,22 @@ AutoCompletion, History are disabled. sY/////////y caa S//P | the wires and in the waves. cayCyayP//Ya pY/Ya | -- Jean-Claude Van Damme sY/PsY////YCc aC//Yp | - sc sccaCY//PCypaapyCP//YSs - spCPY//////YPSps - ccaacs - ->>> + sc sccaCY//PCypaapyCP//YSs + spCPY//////YPSps + ccaacs + +>>> ``` /// -Use scapy's [layer stacking](https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers){:target="_blank"} to build the packet and store it in a python variable. All Scapy functions and classes should be already loaded by default in this interactive python shell. +Use scapy's [layer stacking](https://scapy.readthedocs.io/en/latest/usage.html#stacking-layers){:target="_blank"} to build the packet and store it in a python variable. All Scapy functions and classes should be already loaded by default in this interactive python shell. ///Tip Use the following Scapy classes to build the packet

-- [Ether()](https://scapy.readthedocs.io/en/latest/api/scapy.layers.l2.html#scapy.layers.l2.Ether){:target="_blank"} -- [IPv6()](https://scapy.readthedocs.io/en/latest/api/scapy.layers.inet6.html#scapy.layers.inet6.IPv6){:target="_blank"} -- [ICMPv6EchoRequest()](https://scapy.readthedocs.io/en/latest/api/scapy.layers.inet6.html#scapy.layers.inet6.ICMPv6EchoRequest){:target="_blank"} -- [Raw()](https://scapy.readthedocs.io/en/latest/api/scapy.packet.html#scapy.packet.Raw){:target="_blank"} +- [Ether()](https://scapy.readthedocs.io/en/latest/api/scapy.layers.l2.html#scapy.layers.l2.Ether){:target="_blank"} +- [IPv6()](https://scapy.readthedocs.io/en/latest/api/scapy.layers.inet6.html#scapy.layers.inet6.IPv6){:target="_blank"} +- [ICMPv6EchoRequest()](https://scapy.readthedocs.io/en/latest/api/scapy.layers.inet6.html#scapy.layers.inet6.ICMPv6EchoRequest){:target="_blank"} +- [Raw()](https://scapy.readthedocs.io/en/latest/api/scapy.packet.html#scapy.packet.Raw){:target="_blank"} Check out [scapy recipes](#scapy-recipes) for an example of a packet built using layer stacking. /// @@ -626,11 +626,11 @@ Check out [scapy recipes](#scapy-recipes) for an example of a packet built using After you build the packet, use the `show()` method to display it. Should look like this: ```python title="displaying packet object stored in the variable pkt" >>> p.show() -###[ Ethernet ]### +###[ Ethernet ]### dst = 1A:EF:1D:FF:00:01 src = 1A:41:AA:AA:00:32 type = IPv6 -###[ IPv6 ]### +###[ IPv6 ]### version = 6 tc = 0 fl = 0 @@ -639,14 +639,14 @@ After you build the packet, use the `show()` method to display it. Should look l hlim = 64 src = fd00:fde8::15:33 dst = fd00:fde8::15:35 -###[ ICMPv6 Echo Request ]### +###[ ICMPv6 Echo Request ]### type = Echo Request code = 0 cksum = None id = 0x0 seq = 0x0 data = '' -###[ Raw ]### +###[ Raw ]### load = 'hackaton2025' ``` @@ -656,13 +656,13 @@ Continuing from the previous Scapy interactive session, use the [`sendp` functio Check out [scapy recipes](#scapy-recipes) for an example. /// -You will know to have succeeded if the custom generated ICMPv6 `echo request` hits the leaf13 ethernet-1/49.0 and an ICMPv6 `echo response` is generated back towards leaf11. +You will know to have succeeded if the custom generated ICMPv6 `echo request` hits the leaf13 ethernet-1/49.0 and an ICMPv6 `echo response` is generated back towards leaf11. The ICMP payload should read "**hackaton2025**"

- + /// tip To monitor the ICMP probes you can use `tools system traffic-monitor` from the SR Linux CLI (note that `traffic-monitor` is only able to capture on ingress direction). -On the leaf nodes you can also use `tcpdump` from the bash shell, which will display both `egress` and `ingress` direction since the probes terminate in the leafs control-plane. -On the spine, `tcpdump` from bash will not capture the ICMP packet because this is treated as transit traffic. +On the leaf nodes you can also use `tcpdump` from the bash shell, which will display both `egress` and `ingress` direction since the probes terminate in the leafs control-plane. +On the spine, `tcpdump` from bash will not capture the ICMP packet because this is treated as transit traffic. /// details | Monitoring ICMP on leaf11 with `tcpdump` type: tip /// tab | cmd @@ -765,7 +765,7 @@ Internet Control Message Protocol v6 /// #### Build & Send the packet in one-shot by executing a python script -Here you will repeat the same task but using a script instead of the Scapy interactive shell. +Here you will repeat the same task but using a script instead of the Scapy interactive shell. ///tip Check out [Scapy technology explanation - Script ](#__tabbed_2_2) for an example /// @@ -816,19 +816,19 @@ listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 For the rest of activity, we will simulate a network issue which we will diagnose. -Activate traffic between `client11` and `client13`. +Activate traffic between `client11` and `client13`. /// details | How to open a shell prompt to access client nodes type: tip From your Hackton VM, you can use either of this options: -- `ssh user@` +- `ssh admin@` - `sudo docker exec -it clab-srexperts- bash` Example - accessing client11: /// tab | ssh ``` -❯ ssh user@clab-srexperts-client11 +❯ ssh admin@clab-srexperts-client11 [*]─[client11]─[~] ``` @@ -838,7 +838,7 @@ Example - accessing client11: ❯ sudo docker exec -it clab-srexperts-client11 bash [*]─[client11]─[/] -└──> +└──> ``` /// /// @@ -846,7 +846,7 @@ Example - accessing client11: /// details | Start traffic flow between client11 and client13 /// tab | cmd ```bash title="from client11" -/traffic.sh -a start -d client13.vprn.dci +/traffic.sh -a start -d client13.vprn.dci ``` /// /// tab | expected output @@ -863,7 +863,7 @@ This creates 8 TCP flows pushing 2Mbps from client11 to client13 Verify that the traffic is being load-balanced between the two spines. You use `traffic-monitor` on leaf13 or visualize it in Grafana. You should see that leaf13 receives traffic destined for client13 from both spines. -/// details | `traffic-monitor` on leaf13 +/// details | `traffic-monitor` on leaf13 /// tab | cmd ``` tools system traffic-monitor destination-address fd00:ffdd:0:30::13 @@ -897,7 +897,7 @@ Notice that traffic destined to client13 (fd00:ffdd:0:30::13) is being received /// /// details | visualizing traffic in Grafana - type: note + type: note Connect to Grafana to have a real-time view of link utilization across fabric. ``` title="Grafana URL" http://.srexperts.net:3000/ @@ -1039,7 +1039,7 @@ scp admin@clab-srexperts-spine12:/etc/opt/srlinux/sample_clean.pcap admin@clab-s /// /// details | selecting a packet to replicate -Inspect the pcap in scapy interactive shell or wireshark/tcpdump to find an interesting packet. +Inspect the pcap in scapy interactive shell or wireshark/tcpdump to find an interesting packet. /// tab | cmd ```bash title="using tcpdump to inspect first 5 packets of a pcap file" tcpdump -n --number -c 5 -r /etc/opt/srlinux/sample_clean.pcap @@ -1085,8 +1085,8 @@ p['TCP'].sport = 22050 p['Ether'].dst = '1A:40:1E:FF:00:01' #mac-address of spine12 interface ethernet-1/1 sendp(p,iface='e1-50.0',count=1) ``` -On leaf11, we load the .pcap, pick one of the packets, modify it and finally send it via the "bad" and the "good" paths. -Ethernet destination address is modified to match the respective next-hop interfaces of spine11 and spine12. +On leaf11, we load the .pcap, pick one of the packets, modify it and finally send it via the "bad" and the "good" paths. +Ethernet destination address is modified to match the respective next-hop interfaces of spine11 and spine12. Packet is marked with different port numbers, so we can easy correlate which one failed. ```python title="alternative way to build packet instead of loading from pcap" @@ -1205,7 +1205,7 @@ commit stay /// ### Verify the issue is resolved -Using the same scapy scripts as in previous tasks, re-test the path before enabling BGP. +Using the same scapy scripts as in previous tasks, re-test the path before enabling BGP. /// details | Solution type: success @@ -1242,7 +1242,7 @@ commit stay ``` ### Revert network condition Run this on your group's VM instance to rollback changes introduced by task 3 (Introduce the network condition). -``` +``` eval "$(base64 -d <<< "Z25taWMgLWEgY2xhYi1zcmV4cGVydHMtbGVhZjExIC11IGFkbWluIC1wICRFVkVOVF9QQVNTV09SRCAtLWluc2VjdXJlIHNldCAtLXVwZGF0ZSAvOjo6anNvbl9pZXRmOjo6IntcIm5ldHdvcmstaW5zdGFuY2VcIjpbe1wibmFtZVwiOlwiZGVmYXVsdFwiLFwicHJvdG9jb2xzXCI6e1wiYmdwXCI6e1wiZHluYW1pYy1uZWlnaGJvcnNcIjp7XCJpbnRlcmZhY2VcIjpbe1wiaW50ZXJmYWNlLW5hbWVcIjpcImV0aGVybmV0LTEvNDkuMFwiLFwicGVlci1ncm91cFwiOlwiYmdwZ3JvdXAtZWJncC1zcmV4cGVydHMtZmFicmljXCIsXCJhbGxvd2VkLXBlZXItYXNcIjpbXCI0MjAwMDAxMDAwXCJdfV19fX19XX0iO2dubWljIC1hIGNsYWItc3JleHBlcnRzLXNwaW5lMTEgLXUgYWRtaW4gLXAgJEVWRU5UX1BBU1NXT1JEIC0taW5zZWN1cmUgc2V0IC0tZGVsZXRlICcvYWNsL2FjbC1maWx0ZXJbbmFtZT12eGxhbl1bdHlwZT1pcHY0XScgLS1kZWxldGUgJy9hY2wvaW50ZXJmYWNlW2ludGVyZmFjZS1pZD1ldGhlcm5ldC0xLzEuMF0n")" ``` ### Stop traffic diff --git a/docs/nos/srlinux/beginner/nos-srl-activity-04.md b/docs/nos/srlinux/beginner/nos-srl-activity-04.md index b31d1bc..fdc6a0b 100644 --- a/docs/nos/srlinux/beginner/nos-srl-activity-04.md +++ b/docs/nos/srlinux/beginner/nos-srl-activity-04.md @@ -232,7 +232,7 @@ There are 4 gRPC services enabled in this config including gRIBI. ### Configure user for gRIBI client -Create a user `grclient1` that will be used by gRIBIc client to inject routes. +Create a user `client3` that will be used by gRIBIc client to inject routes. Remember to run `enter candidate private` to change to the candidate mode and `commit now` to save your changes. @@ -240,7 +240,7 @@ Remember to run `enter candidate private` to change to the candidate mode and `c ``` bash set / system aaa authorization role gribi-clients services [ gribi ] -set / system aaa authentication user grclient1 password grclient1 role [ gribi-clients ] +set / system aaa authentication user client3 password client3 role [ gribi-clients ] ``` /// @@ -255,8 +255,8 @@ info flat from running system aaa | grep client ``` bash A:g15-leaf11# info flat from running system aaa | grep client -set / system aaa authentication user grclient1 password $y$j9T$bcd1d72367d5f71e$FgwfvyKXBZwkPv7hrI45hqgQF3i20buJoaTmBjLLK9. -set / system aaa authentication user grclient1 role [ gribi-clients ] +set / system aaa authentication user client3 password $y$j9T$bcd1d72367d5f71e$FgwfvyKXBZwkPv7hrI45hqgQF3i20buJoaTmBjLLK9. +set / system aaa authentication user client3 role [ gribi-clients ] set / system aaa authorization role gribi-clients services [ gribi ] ``` /// @@ -295,14 +295,14 @@ We will use the `gRIBI Get` RPC to get the current installed gRIBI routes. /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft ipv4 +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft ipv4 ``` /// /// tab | expected output ``` bash -❯ gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft ipv4 +❯ gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft ipv4 INFO[0000] target clab-srexperts-peering2:57400: final get response: INFO[0000] got 1 results INFO[0000] "clab-srexperts-peering2:57400": @@ -345,7 +345,7 @@ Use `gRIBI Modify` RPC to inject this route to `peering2`. Replace `file.yml` wi /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 modify --input-file file.yml +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 modify --input-file file.yml ``` /// /// tab | expected output @@ -436,13 +436,13 @@ When the firewall application use is complete, the gRIBI routes can be moved usi /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 flush --ns default --override +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 flush --ns default --override ``` /// /// tab | expected output ``` bash -❯ gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 flush --ns default --override +❯ gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 flush --ns default --override INFO[0000] got 1 results INFO[0000] "clab-srexperts-peering2:57400": timestamp: 1745865482482562426 result: OK @@ -492,13 +492,13 @@ operations: /// details | Injecting the route /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 modify --input-file gribi-input.yml +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 modify --input-file gribi-input.yml ``` /// /// tab | expected output ``` bash -❯ gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 modify --input-file gribi-input.yml +❯ gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 modify --input-file gribi-input.yml INFO[0000] trying to find variable file "gribi-input_vars.yml" INFO[0000] sending request=params:{redundancy:SINGLE_PRIMARY persistence:PRESERVE ack_type:RIB_AND_FIB_ACK} to "clab-srexperts-peering2:57400" INFO[0000] sending request=election_id:{high:1} to "clab-srexperts-peering2:57400" @@ -592,13 +592,13 @@ To see the next-hop definition: /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft nh +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft nh ``` /// /// tab | expected output ``` bash -❯ gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft nh +❯ gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft nh INFO[0000] target clab-srexperts-peering2:57400: final get response: entry:{network_instance:"default" next_hop:{index:1 next_hop:{ip_address:{value:"10.64.51.1"}}} rib_status:PROGRAMMED fib_status:PROGRAMMED} INFO[0000] got 1 results INFO[0000] "clab-srexperts-peering2:57400": @@ -624,13 +624,13 @@ To see the next-hop group definition: /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft nhg +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft nhg ``` /// /// tab | expected output ``` bash -❯ gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft nhg +❯ gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft nhg INFO[0000] target clab-srexperts-peering2:57400: final get response: entry:{network_instance:"default" next_hop_group:{id:1 next_hop_group:{next_hop:{index:1}}} rib_status:PROGRAMMED fib_status:PROGRAMMED} INFO[0000] got 1 results INFO[0000] "clab-srexperts-peering2:57400": @@ -655,13 +655,13 @@ To see the destination prefix definition: /// tab | cmd ``` bash -gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft ipv4 +gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft ipv4 ``` /// /// tab | expected output ``` bash -❯ gribic -a clab-srexperts-peering2:57400 --insecure -u grclient1 -p grclient1 get --ns default --aft ipv4 +❯ gribic -a clab-srexperts-peering2:57400 --insecure -u client3 -p client3 get --ns default --aft ipv4 INFO[0000] target clab-srexperts-peering2:57400: final get response: entry:{network_instance:"default" ipv4:{prefix:"31.10.31.11/32" ipv4_entry:{next_hop_group:{value:1}}} rib_status:PROGRAMMED fib_status:PROGRAMMED} INFO[0000] got 1 results INFO[0000] "clab-srexperts-peering2:57400": diff --git a/docs/nos/srlinux/beginner/nos-srl-gnsi-authz.md b/docs/nos/srlinux/beginner/nos-srl-gnsi-authz.md index 9356189..95ec2dc 100644 --- a/docs/nos/srlinux/beginner/nos-srl-gnsi-authz.md +++ b/docs/nos/srlinux/beginner/nos-srl-gnsi-authz.md @@ -107,16 +107,16 @@ Create 2 users described below on `leaf11`. These users will be used by gRPC cli | Username | Password | Role | |----------|----------|------| | client1 | client1 | gNOI service | -| grclient1 | grclient1 | gNMI service | +| client2 | client2 | gNMI service | /// tab | cmd ``` bash -set / system aaa authorization role ext-clients services [ gnoi ] +set / system aaa authorization role gnoi-clients services [ gnoi ] set / system aaa authentication user client1 password client1 -set / system aaa authentication user client1 role [ ext-clients ] +set / system aaa authentication user client1 role [ gnoi-clients ] set / system aaa authorization role gnmi-clients services [ gnmi ] -set / system aaa authentication user grclient1 password grclient1 role [ gnmi-clients ] +set / system aaa authentication user client2 password client2 role [ gnmi-clients ] set / system configuration role gnmi-clients rule / action write ``` @@ -132,10 +132,10 @@ info flat from running system aaa | grep client ``` bash set / system aaa authentication user client1 password $y$j9T$c0b094a538ddae13$GtCdwrCxDIrMhva6AtwPrXBR9YKFj4Gkr3RhaqRBstB -set / system aaa authentication user client1 role [ ext-clients ] -set / system aaa authentication user grclient1 password $y$j9T$720580ea832aa30d$AP.4Qi6e1kFXyU6TG82/v1xs99r4tCk/H8kBmvPenpB -set / system aaa authentication user grclient1 role [ gnmi-clients ] -set / system aaa authorization role ext-clients services [ gnoi ] +set / system aaa authentication user client1 role [ gnoi-clients ] +set / system aaa authentication user client2 password $y$j9T$720580ea832aa30d$AP.4Qi6e1kFXyU6TG82/v1xs99r4tCk/H8kBmvPenpB +set / system aaa authentication user client2 role [ gnmi-clients ] +set / system aaa authorization role gnoi-clients services [ gnoi ] set / system aaa authorization role gnmi-clients services [ gnmi ] ``` /// @@ -416,8 +416,8 @@ Refer to [SR Linux Documentation](https://documentation.nokia.com/srlinux/25-3/b Your task is to overwrite this default Authz policy with another policy that will have the following rules: -1. Allow gNOI File Stat and gNOI File Get for `client1` and role `ext-clients` -2. Deny gNOI File Put RPC for `client1` and role `ext-clients` +1. Allow gNOI File Stat and gNOI File Get for `client1` and role `gnoi-clients` +2. Deny gNOI File Put RPC for `client1` and role `gnoi-clients` Once your Authz policy is ready to be configured, use Authz Rotate RPC in the gNSIc command to push the policy to `leaf11`. Here's an example. Replace the `json payload` part with your Authz policy in JSON format (remember to use the escape character `\` for the `"` character). @@ -479,13 +479,13 @@ If you need help, refer to the Authz policy below. type: code ```json { - "name": "Ext-clients", + "name": "gnoi-clients", "allow_rules": [ { "name": "backup-access", "source": { "principals": [ - "client1","ext-clients" + "client1","gnoi-clients" ] }, "request": { @@ -501,7 +501,7 @@ If you need help, refer to the Authz policy below. "name": "backup-access", "source": { "principals": [ - "client1","ext-clients" + "client1","gnoi-clients" ] }, "request": { @@ -519,7 +519,7 @@ Here's the command to push this policy to `leaf11` using `Authz Rotate` RPC. /// tab | cmd ``` bash -gnsic -a clab-srexperts-leaf11:57401 -u admin -p $EVENT_PASSWORD --skip-verify authz rotate --policy "{\"name\":\"Ext-clients\",\"allow_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"ext-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Get\",\"/gnoi.file.File/Stat\"]}}],\"deny_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"ext-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Put\"]}}]}" +gnsic -a clab-srexperts-leaf11:57401 -u admin -p $EVENT_PASSWORD --skip-verify authz rotate --policy "{\"name\":\"gnoi-clients\",\"allow_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"gnoi-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Get\",\"/gnoi.file.File/Stat\"]}}],\"deny_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"gnoi-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Put\"]}}]}" ``` /// /// tab | expected output @@ -550,7 +550,7 @@ info flat from state /system aaa authorization authz-policy ``` bash / system aaa authorization authz-policy version "" / system aaa authorization authz-policy created-on "2417-02-18T14:54:24.465Z (392 years from now)" -/ system aaa authorization authz-policy policy "{\"name\":\"Ext-clients\",\"allow_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"ext-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Get\",\"/gnoi.file.File/Stat\"]}}],\"deny_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"ext-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Put\"]}}]}" +/ system aaa authorization authz-policy policy "{\"name\":\"gnoi-clients\",\"allow_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"gnoi-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Get\",\"/gnoi.file.File/Stat\"]}}],\"deny_rules\":[{\"name\":\"backup-access\",\"source\":{\"principals\":[\"client1\",\"gnoi-clients\"]},\"request\":{\"paths\":[\"/gnoi.file.File/Put\"]}}]}" / system aaa authorization authz-policy counters rpc /gnoi.file.File/Get access-rejects 0 / system aaa authorization authz-policy counters rpc /gnoi.file.File/Get access-accepts 1 / system aaa authorization authz-policy counters rpc /gnoi.file.File/Get last-access-accept "2025-04-29T01:56:45.028Z (6 minutes ago)" @@ -587,7 +587,7 @@ tools system aaa authorization authz-policy remove ## Additional Task -Streaming Telemetry is being sent from `leaf11` with `grclient1` username to an open source stats collector. An unauthorized 3rd party gets access to the CLI of this stats collector and uses gNMI Set RPC to disable BGP on `leaf11`. Your task is to secure `leaf11` from such an attack using gNSI Authz policies. +Streaming Telemetry is being sent from `leaf11` with `client2` username to an open source stats collector. An unauthorized 3rd party gets access to the CLI of this stats collector and uses gNMI Set RPC to disable BGP on `leaf11`. Your task is to secure `leaf11` from such an attack using gNSI Authz policies. ### gNMI commands @@ -614,23 +614,23 @@ Here are the commands to test Get, Set and Subscribe. /// tab | gNMI Get ``` bash -gnmic -a clab-srexperts-leaf11:57401 -u grclient1 -p grclient1 --skip-verify get --type state --path "/interface[name=ethernet-1/1]/statistics/in-octets/" -e json_ietf +gnmic -a clab-srexperts-leaf11:57401 -u client2 -p client2 --skip-verify get --type state --path "/interface[name=ethernet-1/1]/statistics/in-octets/" -e json_ietf ``` /// /// tab | gNMI Set ``` bash -gnmic -a clab-srexperts-leaf11:57401 -u grclient1 -p grclient1 --skip-verify set --update-path "/interface[name=ethernet-1/1]/description" --update-value "gnmi-test" +gnmic -a clab-srexperts-leaf11:57401 -u client2 -p client2 --skip-verify set --update-path "/interface[name=ethernet-1/1]/description" --update-value "gnmi-test" ``` /// /// tab | gNMI Subscribe ``` bash -gnmic -a clab-srexperts-leaf11:57401 -u grclient1 -p grclient1 --skip-verify sub --path "/interface[name=ethernet-1/1]/statistics/in-octets/" --mode once +gnmic -a clab-srexperts-leaf11:57401 -u client2 -p client2 --skip-verify sub --path "/interface[name=ethernet-1/1]/statistics/in-octets/" --mode once ``` /// Test the above commands and verify the outputs. -Then apply an Authz policy to allow `Get` and `Subscribe` RPCs while denying `Set` RPC for user `grclient1` and role `gnmi-clients`. +Then apply an Authz policy to allow `Get` and `Subscribe` RPCs while denying `Set` RPC for user `client2` and role `gnmi-clients`. Both the username and the role name should be added to the principals section. @@ -649,7 +649,7 @@ If you need help, refer to the solution below. "name": "gnmi-access", "source": { "principals": [ - "grclient1","gnmi-clients" + "client2","gnmi-clients" ] }, "request": { @@ -665,7 +665,7 @@ If you need help, refer to the solution below. "name": "gnmi-access", "source": { "principals": [ - "grclient1","gnmi-clients" + "client2","gnmi-clients" ] }, "request": { @@ -681,7 +681,7 @@ If you need help, refer to the solution below. /// details | gNSI request for gNMI Authz policy ```bash -gnsic -a clab-srexperts-leaf11:57401 -u admin -p $EVENT_PASSWORD --skip-verify authz rotate --policy "{\"name\":\"gnmi-access\",\"allow_rules\":[{\"name\":\"gnmi-access\",\"source\":{\"principals\":[\"grclient1\",\"gnmi-clients\"]},\"request\":{\"paths\":[\"/gnmi.gNMI/Get\",\"/gnmi.gNMI/Subscribe\"]}}],\"deny_rules\":[{\"name\":\"gnmi-access\",\"source\":{\"principals\":[\"grclient1\",\"gnmi-clients\"]},\"request\":{\"paths\":[\"/gnmi.gNMI/Set\"]}}]}" +gnsic -a clab-srexperts-leaf11:57401 -u admin -p $EVENT_PASSWORD --skip-verify authz rotate --policy "{\"name\":\"gnmi-access\",\"allow_rules\":[{\"name\":\"gnmi-access\",\"source\":{\"principals\":[\"client2\",\"gnmi-clients\"]},\"request\":{\"paths\":[\"/gnmi.gNMI/Get\",\"/gnmi.gNMI/Subscribe\"]}}],\"deny_rules\":[{\"name\":\"gnmi-access\",\"source\":{\"principals\":[\"client2\",\"gnmi-clients\"]},\"request\":{\"paths\":[\"/gnmi.gNMI/Set\"]}}]}" ``` /// diff --git a/docs/nos/srlinux/beginner/nos-srlinux-activity-11.md b/docs/nos/srlinux/beginner/nos-srlinux-activity-11.md index 015e763..37945ce 100644 --- a/docs/nos/srlinux/beginner/nos-srlinux-activity-11.md +++ b/docs/nos/srlinux/beginner/nos-srlinux-activity-11.md @@ -40,7 +40,7 @@ Before making configuration changes, network engineers commonly back up the curr Checkpoints are named using the format `checkpoint-<#>.json`, where `<#>` is a sequential number, 0 representing the most recent checkpoint. At any time, users can roll back the device configuration to a previously saved checkpoint, ensuring a reliable and efficient method for configuration recovery. -The list of saved checkpoint configurations can be obtained with the command `show system configuration checkpoint`. +The list of saved checkpoint configurations can be obtained with the command `info from state / system configuration checkpoint {} | as table | filter fields name comment username created` (there is often an alias to provide this long command). ### Access Control List (ACL) An Access Control List (ACL) is a set of rules used within a network environment to evaluate packets individually, determining whether to allow or deny access. Each ACL entry includes a match condition and an associated action, which can be one of the following: accept, drop, log, or a rate-limit policer. @@ -56,7 +56,7 @@ Captured traffic can be viewed directly in the CLI, either in a simplified forma ## Tasks -**You should read these tasks from top-to-bottom before beginning the activity**. +**You should read these tasks from top-to-bottom before beginning the activity**. **It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them.** @@ -117,7 +117,7 @@ After creating the checkpoint, run the `show` command to view the list of availa ``` bash save checkpoint -show system configuration checkpoint +info from state / system configuration checkpoint {} | as table | filter fields name comment username created ``` /// @@ -129,7 +129,7 @@ show system configuration checkpoint --{ + running }--[ ]-- -A:g15-spine11# show system configuration checkpoint +A:g15-spine11# info from state / system configuration checkpoint {} | as table | filter fields name comment username created +-----+---------------------------------------+-----------------------+------------------+-------------------------------+ | Id | Name | Comment | Username | Created | +=====+=======================================+=======================+==================+===============================+ @@ -296,15 +296,55 @@ To do this: 1. Create the ACL and enable statistics tracking (set statistics-per-entry to true to monitor matched packets). -2. Add an entry with matching criteria for ICMP traffic, define the match conditions (e.g. protocol type = ICMP) and specify the desired action. +2. Add an entry with matching criteria for ICMP traffic, define the match conditions (e.g. protocol type = ICMP) and specify the desired action. 3. Apply the ACL to the appropriate interface (this should be the same interface that the ICMP packets were observed on during the packet capture in the previous task). /// details | Solution (check if you get stuck) + type: success +/// tab | Commands ``` -type: success -A:g15-spine11# enter candidate +enter candidate +acl { + acl-filter ping_leaf type ipv4 { + description "ACL to capture ICMP request from leaf" + statistics-per-entry true + entry 10 { + match { + ipv4 { + protocol icmp + destination-ip { + prefix 10.46.15.31/32 + } + icmp { + type echo + } + source-ip { + prefix 10.46.15.33/32 + } + } + } + action { + accept { + } + } + } + } + interface ethernet-1/1.0 { + input { + acl-filter ping_leaf type ipv4 { + } + } + } +} +diff +commit stay +``` +/// +/// tab | Expected `diff` output +``` +--{ * candidate shared default }--[ ]-- A:g15-spine11# diff acl { + acl-filter ping_leaf type ipv4 { @@ -338,10 +378,9 @@ A:g15-spine11# diff + } + } } - ``` /// - +/// ### Check ACL statistics Repeat the ping command on the leaf, just as you did before. @@ -359,7 +398,7 @@ show acl ipv4-filter ping_leaf entry 10 /// -/// tab | expected output +/// tab | Expected output ``` bash A:g15-spine11# show acl ipv4-filter ping_leaf entry 10 @@ -397,8 +436,27 @@ To do this: This will drop ICMP packets from reaching their destination, effectively blocking the pings sent from the leaf. /// details | Solution (check if you get stuck) + type: success +/// tab | Commands +``` +enter candidate +acl { + acl-filter ping_leaf type ipv4 { + entry 10 { + action { + drop { + } + } + } + } +} +diff +commit stay +``` +/// +/// tab | Expected `diff` output ``` -A:g15-spine11# enter candidate +--{ +* candidate shared default }--[ ]-- A:g15-spine11# diff acl { acl-filter ping_leaf type ipv4 { @@ -411,9 +469,9 @@ A:g15-spine11# diff } } } - ``` /// +/// ### Clear and check ACL statistics 1. On the spine, clear the ACL statistics on the spine to reset the packet counters. diff --git a/docs/nos/srlinux/intermediate/19-SRLinux-Custom-CLI.md b/docs/nos/srlinux/intermediate/19-SRLinux-Custom-CLI.md index da07d56..59125e1 100644 --- a/docs/nos/srlinux/intermediate/19-SRLinux-Custom-CLI.md +++ b/docs/nos/srlinux/intermediate/19-SRLinux-Custom-CLI.md @@ -20,7 +20,7 @@ tags: SR Linux CLI is an open-source, Python-based, and pluggable engine. -It allows users to implement custom CLI `global`, `show`, and `tools` commands that run alongside the native CLI commands. SR Linux provides a Python framework to develop those commands. +It allows users to implement custom CLI `global`, `show`, and `tools` commands that run alongside the native CLI commands. SR Linux provides a Python framework to develop those commands. @@ -29,7 +29,7 @@ In this activity, we will explore the native CLI commands, how the Python CLI pl ## Objective -Imagine you are managing a network with SR Linux nodes, and you receive a request to create several custom `global`, `show`, and `tools` commands for the operations and engineering teams. These new commands will also be used by automation tools to collect system information efficiently. +Imagine you are managing a network with SR Linux nodes, and you receive a request to create several custom `global`, `show`, and `tools` commands for the operations and engineering teams. These new commands will also be used by automation tools to collect system information efficiently. Some examples are: @@ -41,11 +41,11 @@ Some examples are: In this activity we'll guide you through the `show traffic` custom CLI command deployment. -The objectives of this exercise are: +The objectives of this exercise are: - 1. Familiarize with the SR Linux CLI engine filesystem and explore native CLI plugins - 2. Create a modified `show version` plugin using an existing native plugin as reference with custom modifications - 3. Create a new custom CLI `show traffic` command step-by-step + 1. Familiarize with the SR Linux CLI engine filesystem and explore native CLI plugins + 2. Create a modified `show version` plugin using an existing native plugin as reference with custom modifications + 3. Create a new custom CLI `show traffic` command step-by-step With this activity you'll learn how flexible it is to modify or implement a new SRLinux custom CLI plugin. @@ -53,15 +53,15 @@ With this activity you'll learn how flexible it is to modify or implement a new ## Technology explanation -The pluggable architecture of SR Linux CLI allows you to create custom CLI commands using the same infrastructure as the native SR Linux commands. +The pluggable architecture of SR Linux CLI allows you to create custom CLI commands using the same infrastructure as the native SR Linux commands. The Python-based CLI engine allows a user to create the custom CLI commands in the following categories: -- **show** commands - These are your much-loved show commands that print out the state of the system in a human-readable format, often in a table. -- **global** commands - These are operational commands like `ping`, `traceroute`, `file`, `bash`, etc. -- **tools** commands +- **show** commands + These are your much-loved show commands that print out the state of the system in a human-readable format, often in a table. +- **global** commands + These are operational commands like `ping`, `traceroute`, `file`, `bash`, etc. +- **tools** commands These represent a run-to-completion task or an operation. Like a reboot or a request to load a configuration from a file. @@ -79,12 +79,12 @@ When SR Linux CLI is started, the available commands (native and user-defined) a ## Tasks -**You should read these tasks from top-to-bottom before beginning the activity**. +**You should read these tasks from top-to-bottom before beginning the activity**. -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -For the activity tasks you will login to `leaf11`. +For the activity tasks you will login to `leaf11`. You may use the `bash` CLI command to move to the Linux shell from the SR Linux CLI. /// tab | login with SSH to `sr_cli` @@ -96,26 +96,26 @@ ssh admin@clab-srexperts-leaf11 /// - There are 3 tasks sections below: + There are 3 tasks sections below: - 1. Explore the native CLI plugins - - 2. Create modified `show version` CLI + 1. Explore the native CLI plugins - 3. Create `show traffic` custom CLI + 2. Create modified `show version` CLI + 3. Create `show traffic` custom CLI -**Let's now start the activity tasks!** + +**Let's now start the activity tasks!** ### Explore the native CLI plugins -Before you start deploying your own custom CLI plugins you decide to inspect the existing native plugins to learn and use as examples. +Before you start deploying your own custom CLI plugins you decide to inspect the existing native plugins to learn and use as examples. -In this section you'll familiarize yourself with the SR Linux CLI engine filesystem and explore native CLI plugins. +In this section you'll familiarize yourself with the SR Linux CLI engine filesystem and explore native CLI plugins. -Customized CLI commands can be added to SR Linux using a Python plugin framework. The native `global`, `show` and `tools` SR Linux commands use this same framework, and their source code is available to any CLI user with admin access rights. -The existing native CLI commands can be used to learn how to create additional CLI commands. +Customized CLI commands can be added to SR Linux using a Python plugin framework. The native `global`, `show` and `tools` SR Linux commands use this same framework, and their source code is available to any CLI user with admin access rights. +The existing native CLI commands can be used to learn how to create additional CLI commands. 1. Login to `leaf11` and move to the linux `bash` shell. @@ -237,7 +237,7 @@ The existing native CLI commands can be used to learn how to create additional C -rw-r--r-- 1 root root 21378 Feb 19 22:24 watch.py -rw-r--r-- 1 root root 11373 Feb 19 22:24 writable_schema.py -rw-r--r-- 1 root root 3539 Feb 19 22:24 yang_models.py - admin@g15-leaf11:/opt/srlinux/python/virtual-env/lib/python3.11/dist-packages/srlinux/mgmt/cli/plugins$ + admin@g15-leaf11:/opt/srlinux/python/virtual-env/lib/python3.11/dist-packages/srlinux/mgmt/cli/plugins$ ``` /// /// @@ -246,15 +246,15 @@ The existing native CLI commands can be used to learn how to create additional C /// details | Explanation version.py - From the output file list you should recognize several of those commands, such as `clear`, `date`, `echo`, `info` or `ping`. These are some of the **global** CLI commands available in `sr_cli`. + From the output file list you should recognize several of those commands, such as `clear`, `date`, `echo`, `info` or `ping`. These are some of the **global** CLI commands available in `sr_cli`. /// -4. Do you recognize any `show` CLI command? Can you find where the `show` CLI commands are located? +4. Do you recognize any `show` CLI command? Can you find where the `show` CLI commands are located? /// details | Solution: Native `show` CLI plugins list - The native `show` CLI commands Python source code files are located under `plugins/reports` directory. + The native `show` CLI commands Python source code files are located under `plugins/reports` directory. /// tab | cmd ``` bash @@ -438,22 +438,22 @@ The existing native CLI commands can be used to learn how to create additional C -rw-r--r-- 1 root root 24245 Feb 19 22:24 tunnel_interface_reports.py -rw-r--r-- 1 root root 12390 Feb 19 22:24 tunnel_vxlan_reports.py -rw-r--r-- 1 root root 6578 Feb 19 22:24 version.py - admin@g15-leaf11:/opt/srlinux/python/virtual-env/lib/python3.11/dist-packages/srlinux/mgmt/cli/plugins/reports$ + admin@g15-leaf11:/opt/srlinux/python/virtual-env/lib/python3.11/dist-packages/srlinux/mgmt/cli/plugins/reports$ ``` /// - You should be able to guess some commands from the file names, like `show bgp summary`, `show interface`, or `show system application`. All the SR linux show commands are implemented in this directory. + You should be able to guess some commands from the file names, like `show bgp summary`, `show interface`, or `show system application`. All the SR linux show commands are implemented in this directory. /// -5. Explore the `show version` file to see one of the simplest CLI show commands of the system. Can you find the file? +5. Explore the `show version` file to see one of the simplest CLI show commands of the system. Can you find the file? In parallel, open a second terminal session side-by-side, and login to `leaf11` `sr-cli` shell, so that you can execute the CLI command and see the output while looking at the Python file: /// details | Solution: Native `show version` CLI plugins list - The `show version` file is the version.py. + The `show version` file is the version.py. /// tab | Output - show version ``` bash @@ -759,7 +759,7 @@ In parallel, open a second terminal session side-by-side, and login to `leaf11` /// - In the beginning of `version.py` you find: + In the beginning of `version.py` you find: - the import statements (line 1 to 9) @@ -773,30 +773,30 @@ In parallel, open a second terminal session side-by-side, and login to `leaf11` - Few notes regarding the code: + Few notes regarding the code: - * the CLI command is appended to the CLI command tree using `cli.show_mode.add_command()` to append the CLI command under the `show` branch. (line 32) + * the CLI command is appended to the CLI command tree using `cli.show_mode.add_command()` to append the CLI command under the `show` branch. (line 32) - * the syntax definition is done directly in the `add_command()` method. This is the same as first creating a syntax object and then using it as a parameter. (line 33) + * the syntax definition is done directly in the `add_command()` method. This is the same as first creating a syntax object and then using it as a parameter. (line 33) - * there's a callback `method_print()` which is executed when the `show version` command is entered by a CLI user. (line 33) + * there's a callback `method_print()` which is executed when the `show version` command is entered by a CLI user. (line 33) - * there is a schema object that is passed to the `add_command()` method using the `_get_schema()`. This is specific to show commands. (line 34) + * there is a schema object that is passed to the `add_command()` method using the `_get_schema()`. This is specific to show commands. (line 34) - * the `_get_schema()` method builds a schema consisting of one node called `basic system info` that has multiple fields (`hostname`,`chassis type`, etc). (line 42 to 61) + * the `_get_schema()` method builds a schema consisting of one node called `basic system info` that has multiple fields (`hostname`,`chassis type`, etc). (line 42 to 61) - * the schema object is a placeholder for the data to be displayed by the command. + * the schema object is a placeholder for the data to be displayed by the command. - When the callback function is executed it: + When the callback function is executed it: - * retrieves relevant data in the state datastore with `_fetch_state()`. (line 37) + * retrieves relevant data in the state datastore with `_fetch_state()`. (line 37) - * populates the retrieved data into the schema object with `_populate_data()`. (line 38) + * populates the retrieved data into the schema object with `_populate_data()`. (line 38) - * specifies how the retrieved data should be formatted on the screen with `_set_formatters()`. (line 39) + * specifies how the retrieved data should be formatted on the screen with `_set_formatters()`. (line 39) - * instruct SR Linux to display the retrieved data by calling the `print_data()` method of the output object. (line 40) + * instruct SR Linux to display the retrieved data by calling the `print_data()` method of the output object. (line 40) @@ -877,16 +877,16 @@ In parallel, open a second terminal session side-by-side, and login to `leaf11` /// - Few notes regarding the code: + Few notes regarding the code: - * Lines 64 to 67 set 4 different xpaths into the state datastore + * Lines 64 to 67 set 4 different xpaths into the state datastore * The following lines retrieve the values associated with the 4 xpaths and store them in local data objects (_hostname_data, _chassis_data, _software_version and _control_data) - * You can get the same information using the CLI `info from state` command. The xpath strings using the notation with `/` must be translated into the YANG model hierarchy. For example, `/system/name/host-name` is translated into the YANG elements `system name host-name`. + * You can get the same information using the CLI `info from state` command. The xpath strings using the notation with `/` must be translated into the YANG model hierarchy. For example, `/system/name/host-name` is translated into the YANG elements `system name host-name`. -3. Run the `info from state` commands in your CLI session. +3. Run the `info from state` commands in your CLI session. /// tab | `info from state` @@ -992,7 +992,7 @@ In parallel, open a second terminal session side-by-side, and login to `leaf11` -4. The `_populate_data()` method parses the info returned from the state datastore to extract the relevant information and then assigns a value to each of the fields of the schema. +4. The `_populate_data()` method parses the info returned from the state datastore to extract the relevant information and then assigns a value to each of the fields of the schema. The `_set_formatters()` method specifies how the schema should be displayed. It uses the formatter function `TagValueFormatter()` to display each field in the schema as a tag/value pair, one per row. It also specifies that there should be a border above and a border below. @@ -1077,13 +1077,13 @@ The `_set_formatters()` method specifies how the schema should be displayed. It /// -5. You may compare the output of the `show version` command with the differente fields of the schema. -You can see that the different fields from the schema are displayed line by line. The system has automatically adjusted the width of the columns to the widest field and there is a border above and below all the fiels. Note that you can change the number of columns for your CLI session and SR linux automatically calculates how wide the borders need to be. +5. You may compare the output of the `show version` command with the differente fields of the schema. +You can see that the different fields from the schema are displayed line by line. The system has automatically adjusted the width of the columns to the widest field and there is a border above and below all the fiels. Note that you can change the number of columns for your CLI session and SR linux automatically calculates how wide the borders need to be. When implementing a show command, the focus is on the schema definition rather that on the output formatting. Once the schema values are filled in, SR Linux can automatically format the output. - > **Note 1:** It is possible to use the `as json` modifier for the show commands to display the output in JSON notation instead of displaying as text. If you compare with the python code, you can see that it's the schema definition that is being displayed. + > **Note 1:** It is possible to use the `as json` modifier for the show commands to display the output in JSON notation instead of displaying as text. If you compare with the python code, you can see that it's the schema definition that is being displayed. > **Note 2:** The SR Linux containes several classes and utility functions. The formatters and format utilities allows to customize the outputs look-and-feel. E.g. you have the `show version | as table` that displays the output in a table format. You can achieve the same by using the `ColumnFormatter()` instead of the `TagValueFormatter()` in your code. @@ -1159,7 +1159,7 @@ When implementing a show command, the focus is on the schema definition rather t /// tab | ColumnFormatter - ```py title="Using ColumnFormatter instead of TagValueFormatter" + ```py title="Using ColumnFormatter instead of TagValueFormatter" from srlinux.data import TagValueFormatter, Border, Data, ColumnFormatter def _set_formatters(self, data): data.set_formatter('/basic system info', Border(ColumnFormatter(), Border.Above | Border.Below)) @@ -1180,17 +1180,17 @@ When implementing a show command, the focus is on the schema definition rather t ### Create modified `show version` custom CLI -You now understand the SR Linux plugin architecture and you have explored the native CLI plugins. So you decide to create a modified version of the `show version` plugin. +You now understand the SR Linux plugin architecture and you have explored the native CLI plugins. So you decide to create a modified version of the `show version` plugin. + +In this section you'll create a new plugin using an existing native `show version` plugin as reference and apply custom modifications. +Using an existing native command, duplicate and modify it to adapt to your purpose is a relatively easy way to create a new plugin. -In this section you'll create a new plugin using an existing native `show version` plugin as reference and apply custom modifications. -Using an existing native command, duplicate and modify it to adapt to your purpose is a relatively easy way to create a new plugin. +At the start of a CLI session, SR linux scans the following directories to check for new CLI plugins: -At the start of a CLI session, SR linux scans the following directories to check for new CLI plugins: +* `/home//cli/plugins`: a plugin in this directory is usable only for this user -* `/home//cli/plugins`: a plugin in this directory is usable only for this user +* `/etc/opt/srlinux/cli/plugins`: a plugin in this directory is usable for all users -* `/etc/opt/srlinux/cli/plugins`: a plugin in this directory is usable for all users - In this exercise you'll use the `show version` command file to create a new custom CLI show command. @@ -1204,18 +1204,18 @@ In this exercise you'll use the `show version` command file to create a new cust /// ///warning - Don't forget to check and adjust the folder permissions with `chmod` if needed. + Don't forget to check and adjust the folder permissions with `chmod` if needed. /// /// note - If you prefer to use VSCode, we suggest you to add the server home folder to you workspace (`~/` or `/home/nokia/`). - The `~/clab-srexperts/leaf11/config/cli/plugins` is bound to the `leaf11's` `/etc/opt/srlinux/cli/plugins` folder. - As such, you may edit the `~/clab-srexperts/leaf11/config/cli/plugins/version_srx.py` directly from VSCode. + If you prefer to use VSCode, we suggest you to add the server home folder to you workspace (`~/` or `/home/nokia/`). + The `~/clab-srexperts/leaf11/config/cli/plugins` is bound to the `leaf11's` `/etc/opt/srlinux/cli/plugins` folder. + As such, you may edit the `~/clab-srexperts/leaf11/config/cli/plugins/version_srx.py` directly from VSCode. /// -2. Edit the version_srx.py and change the `load()` method Syntax string and help text. +2. Edit the version_srx.py and change the `load()` method Syntax string and help text. /// tab | version_srx.py syntax @@ -1231,7 +1231,7 @@ In this exercise you'll use the `show version` command file to create a new cust 3. You can now test the new CLI command. To load the new CLI command the CLI session must be restarted. You can logout/login or open a new `sr_cli` session. -Then you can use the new CLI command. +Then you can use the new CLI command. /// tab | version_srx.py cmd @@ -1244,16 +1244,16 @@ Then you can use the new CLI command. ``` bash --{ + running }--[ ]-- A:g15-leaf11# show - / interface platform tunnel-interface - acl lag system version - arpnd network-instance tunnel version_srexperts + / interface platform tunnel-interface + acl lag system version + arpnd network-instance tunnel version_srexperts --{ + running }--[ ]-- A:g15-leaf11# show version - version - version_srexperts + version + version_srexperts @@ -1296,18 +1296,18 @@ Then you can use the new CLI command. > **Tip:** You can use `show ` and the `show version_srexperts ?` to verify the syntax and options available. -What has changed in the output compared to the native plugin output? +What has changed in the output compared to the native plugin output? /// details | Answer type: success -The output of the new CLI command is the same as the `show version` as we didn't change anything. - -**Let's do it now!** +The output of the new CLI command is the same as the `show version` as we didn't change anything. + +**Let's do it now!** /// -#### Add extra fields to your command +#### Add extra fields to your command -You task is to add an extra field to the output to display the current time as shown below. +You task is to add an extra field to the output to display the current time as shown below. @@ -1341,18 +1341,18 @@ A:g15-leaf11# /// details | Tip type: tip -There are multiple ways to achieve the solution, you can you use the python datetime module or retrieve this value from system information current-datetime state datastore. -These are the steps using the python datetime module: +There are multiple ways to achieve the solution, you can you use the python datetime module or retrieve this value from system information current-datetime state datastore. +These are the steps using the python datetime module: 1. Add an extra filed `Current time` to the schema. 2. Import the `datetime` module 3. Update the `_populate_data()` method. 4. Reload the plugin. -And these are the steps using system information current-datetime state datastore: +And these are the steps using system information current-datetime state datastore: 1. Add an extra filed `Current time` to the schema. -2. Retrieve the current-datetime at `_fetch_state()` method +2. Retrieve the current-datetime at `_fetch_state()` method 3. Update the `_populate_data()` method. 4. Reload the plugin. @@ -1403,7 +1403,7 @@ These are the steps using the python datetime module: ``` /// - /// tab | `_populate_data` `current_time` + /// tab | `_populate_data` `current_time` ``` py hl_lines="5" def _populate_data(self, state, arguments): result = Data(arguments.schema) @@ -1415,14 +1415,14 @@ These are the steps using the python datetime module: ``` /// - > **Note:** Although the extra fields in the schema is defined as `Current Time`, its actual name in the schema structure becomes `current_time`. The name is converted to lower case and the space character is replaced by an underscore to avoid Python miss interpretations. The same occurs for the `'-' (dash)` character in the field name, it is replaced by the underscore. + > **Note:** Although the extra fields in the schema is defined as `Current Time`, its actual name in the schema structure becomes `current_time`. The name is converted to lower case and the space character is replaced by an underscore to avoid Python miss interpretations. The same occurs for the `'-' (dash)` character in the field name, it is replaced by the underscore. And these are the steps using system information current-datetime state datastore: 1. Add an extra filed `Current time` to the schema. -2. Retrieve the `current-datetime` at `_fetch_state()` method +2. Retrieve the `current-datetime` at `_fetch_state()` method 3. Update the `_populate_data()` method. 4. Reload the plugin. @@ -1454,10 +1454,10 @@ And these are the steps using system information current-datetime state datastor ``` /// - /// tab | import datetime + /// tab | look up system time ``` py def _fetch_state(self, state): - + current_time_path = build_path('/system/information/current-datetime') try: self._current_time_data = state.server_data_store.get_data(current_time_path, recursive=False) @@ -1466,7 +1466,7 @@ And these are the steps using system information current-datetime state datastor ``` /// - /// tab | _populate_data current_time + /// tab | _populate_data current_time ``` py hl_lines="5" def _populate_data(self, state, arguments): @@ -1475,11 +1475,11 @@ And these are the steps using system information current-datetime state datastor /// -You can now test the changes. Logout/login or open a new `sr_cli` session and execute the command again. -Then you can use the new CLI command. +You can now test the changes. Logout/login or open a new `sr_cli` session and execute the command again. +Then you can use the new CLI command. -/// tab | version_srx.py +/// tab | version_srx.py ``` bash show version_srexperts ``` @@ -1521,7 +1521,7 @@ The current time is now displayed along with the output. This also shows that th #### Change the output format -You next task is to change the CLI command to display the output in a table format as shown below. +You next task is to change the CLI command to display the output in a table format as shown below. /// tab | version_srx.py column format @@ -1545,8 +1545,8 @@ You may refer to [SR Linux Classes and utility functions](https://documentation. /// details | Tip type: tip - -You just need to perform two small changes: + +You just need to perform two small changes: 1. You need to import the `ColumnFormatter` module from `srlinux.data`. 2. You need to edit the `_set_formaters()` method at the end of the `version_srx.py` @@ -1574,21 +1574,21 @@ def _set_formatters(self, data): -And with these changes you create a modified version of a native plugin as a custom plugin. -Are you ready now to create you own plugin from scratch? +And with these changes you create a modified version of a native plugin as a custom plugin. +Are you ready now to create you own plugin from scratch? -### Create `show traffic` custom CLI +### Create `show traffic` custom CLI -In this section you will create a new CLI command from scratch and step-by-step. +In this section you will create a new CLI command from scratch and step-by-step. -The request is to create a `show traffic` plugin that displays an overview of the chassis traffic. -The output shall include: +The request is to create a `show traffic` plugin that displays an overview of the chassis traffic. +The output shall include: - a table with the input/output rates and utilization percentages per port (only for those admin-enabled). - the aggregate input and output for the chassis -The intended output is shown below: +The intended output is shown below: ```title="show traffic" --{ + running }--[ ]-- @@ -1608,14 +1608,14 @@ Total rate-out: 267.57 Kbps ``` -/// admonition +/// admonition type: question -Is there another way to get this without a CLI plugin? +Is there another way to get this without a CLI plugin? /// /// details | Answer type: tip - + You can use the command below but it doesn't give you the percentage or the total values and its not flexible. /// tab | `from state / interface * traffic-rate` @@ -1702,35 +1702,35 @@ A:g15-leaf11# /// -To create the new plugin you will follow these steps: - -1. Create the `show_traffic.py` file -2. Define the import statements, the Plugin class and load method -3. Define the CLI command syntax -4. Define the schema -5. Callback - - Fetching state - - Populating data - - Adding formatters - - Printing output +To create the new plugin you will follow these steps: + +1. Create the `show_traffic.py` file +2. Define the import statements, the Plugin class and load method +3. Define the CLI command syntax +4. Define the schema +5. Callback + - Fetching state + - Populating data + - Adding formatters + - Printing output 6. Test your new plugin ///note -The SR Linux CLI needs to be restarted to load new code changes made on CLI plugins. To avoid log-out and log-in often during your development, switch to SR Linux bash shell and run `sr_cli show traffic`. This implicitly executes a new SR Linux CLI instance before executing `show traffic`. +The SR Linux CLI needs to be restarted to load new code changes made on CLI plugins. To avoid log-out and log-in often during your development, switch to SR Linux bash shell and run `sr_cli show traffic`. This implicitly executes a new SR Linux CLI instance before executing `show traffic`. /// #### Create the `show_traffic.py` file -Recall that at the start of a CLI session, SR linux scans the following directories to check for new CLI plugins: +Recall that at the start of a CLI session, SR linux scans the following directories to check for new CLI plugins: -* `/home//cli/plugins`: a plugin in this directory is usable only foth this user +* `/home//cli/plugins`: a plugin in this directory is usable only foth this user -* `/etc/opt/srlinux/cli/plugins`: a plugin in this directory is usable for all users +* `/etc/opt/srlinux/cli/plugins`: a plugin in this directory is usable for all users -Your first step is to deploy the `show_traffic.py` plugin under one of these folders. We suggest you to use VSCode to create the file. If you need guidance, have a look to the tip below. Then proceed to the following sections for guidance to deploy the plugin. +Your first step is to deploy the `show_traffic.py` plugin under one of these folders. We suggest you to use VSCode to create the file. If you need guidance, have a look to the tip below. Then proceed to the following sections for guidance to deploy the plugin. -/// details | Tip: Create the plugin file +/// details | Tip: Create the plugin file type: tip -Create the plugin file using one of the following options: +Create the plugin file using one of the following options: - A) Using VSCode, create the file `show_traffic.py` under the server `~/clab-srexperts/leaf11/config/cli/plugins` folder. There's a bind between this directory and the leaf11's plugins folder, so if you create the file under this folder it will be automatically mapped to `leaf11`. After the file is created verify that it is present under leaf11's `/etc/opt/srlinux/cli/plugins/` folder. @@ -1748,7 +1748,7 @@ total 32 drwxrwxrwx+ 2 srlinux srlinux 4096 Apr 15 10:23 . drwxrwxrwx+ 3 srlinux srlinux 4096 Mar 31 15:58 .. -rw-r--r-- 1 root root 4603 Apr 15 10:19 show_traffic.py -admin@g15-leaf11:~$ +admin@g15-leaf11:~$ ``` /// @@ -1761,22 +1761,22 @@ touch show_traffic.py ``` /// -> **Note:** You can copy/paste code directly to `vi`, howhever, to keep your indentation you need to enable paste mode (Esc + `:set paste`) then move to insertation mode and paste your code. +> **Note:** You can copy/paste code directly to `vi`, howhever, to keep your indentation you need to enable paste mode (Esc + `:set paste`) then move to insertation mode and paste your code. /// -#### Define the import statements, the Plugin class and load() method +#### Define the import statements, the Plugin class and load() method -You need to import packages that are going to be required in the plugin. -The plugin needs to have a class called Plugin that inherits from the CliPlugin with a `load` public method. The SR Linux CLI engine scans the user directories and loads all the plugins that match this signature. +You need to import packages that are going to be required in the plugin. +The plugin needs to have a class called Plugin that inherits from the CliPlugin with a `load` public method. The SR Linux CLI engine scans the user directories and loads all the plugins that match this signature. The `load` method of the Plugin class is the entry point for the CLI plugin. It is where you add your new CLI command to one of the CLI modes - `show`, `global` or `tools`. -Since we want to create a `show traffic` command, we are going to "mount" our command to the show hierarchy. +Since we want to create a `show traffic` command, we are going to "mount" our command to the show hierarchy. -The `add_command` method of the CLI mode receives the command definition arguments such as: +The `add_command` method of the CLI mode receives the command definition arguments such as: -- syntax - how the command is structured syntactically -- schema - what schema defines the data that the command operates on -- callback - what function to call when the command is executed +- syntax - how the command is structured syntactically +- schema - what schema defines the data that the command operates on +- callback - what function to call when the command is executed ///details | Hint type: tip @@ -1786,7 +1786,7 @@ Copy the structure from the `show version` plugin or the github [uptime-cli-plug /// details | Start code: `import`, class `Plugin` and `load()` method type: success -``` py +``` py from srlinux.data import Border, Data, TagValueFormatter, ColumnFormatter from srlinux.location import build_path from srlinux.mgmt.cli import CliPlugin @@ -1810,15 +1810,15 @@ class Plugin(CliPlugin): ``` /// -#### Define the CLI command syntax -The command's syntax defines the command representation - its name, help strings and the arguments it accepts. -To define a command syntax, we need to create an object of the Syntax class; this is what the `_syntax()` method does. +#### Define the CLI command syntax +The command's syntax defines the command representation - its name, help strings and the arguments it accepts. +To define a command syntax, we need to create an object of the Syntax class; this is what the `_syntax()` method does. For our `show traffic` command we just define the command name and the help text in different flavors in the `_syntax()` object. /// details | possible solution: CLI syntax type: success -``` py +``` py def _syntax(self): return Syntax( name="traffic", @@ -1828,20 +1828,20 @@ For our `show traffic` command we just define the command name and the help text ``` /// -#### Define the schema -You might be wondering, what is a schema and why do we need it for such a simple thing as a CLI command? -For a given show command the schema describes the data that the command intends to print out. As per our intent, the `show traffic` command should print out two things: +#### Define the schema +You might be wondering, what is a schema and why do we need it for such a simple thing as a CLI command? +For a given show command the schema describes the data that the command intends to print out. As per our intent, the `show traffic` command should print out two things: - a table with the input/output rates and utilization percentages per admin-enabled port. - the aggregate input/output rate for the chassis. -But, still, why do we need a schema to print values? Can't we just use print the values? -The answer is that a schema makes it possible to have multiple output formats without implementing the logic for each of them. In SR Linux we can display the output using distinct output modifiers such as: default tag/value, table, json, yaml or xml. +But, still, why do we need a schema to print values? Can't we just use print the values? +The answer is that a schema makes it possible to have multiple output formats without implementing the logic for each of them. In SR Linux we can display the output using distinct output modifiers such as: default tag/value, table, json, yaml or xml. Without having a schema-modeled data structure, we would have to implement the logic for each of the output formats ourselves. -/// admonition +/// admonition type: question -- You already know how the schema looks like for a fixed list of `key:value` pairs like in `show version` plugin. But how it would look like for a list table with a dynamic number of rows? +- You already know how the schema looks like for a fixed list of `key:value` pairs like in `show version` plugin. But how it would look like for a list table with a dynamic number of rows? /// ///details | Hint type: tip @@ -1849,14 +1849,14 @@ Check how it is done on a native plugin such as `show interface brief`. [Recal /// ///details | Hint type: tip -You might add multiple children to the schema. +You might add multiple children to the schema. For example, you could create one to hold the ports data, and other to hold the chassis aggregate rate data. This would allow you to set different formatters and different data structures to each. /// /// details | possible solution: schema type: success -``` py +``` py def _schema(self): root = FixedSchemaRoot() root.add_child( @@ -1878,16 +1878,16 @@ For example, you could create one to hold the ports data, and other to hold the /// #### _print() Callback - Fetching state, Populating data, adding formatters and printing output -We described the syntax of the `show traffic` command and defined the schema for the data it operates on. The final task is to create the callback function - the one that gets called when the command is executed and does all the useful work. -We provide the callback function as the second argument to the add_command method and it is up to us how we call it. Most often the show commands will have the callback function named _print, as show commands print out some data to the output. +We described the syntax of the `show traffic` command and defined the schema for the data it operates on. The final task is to create the callback function - the one that gets called when the command is executed and does all the useful work. +We provide the callback function as the second argument to the add_command method and it is up to us how we call it. Most often the show commands will have the callback function named _print, as show commands print out some data to the output. -///tip +///tip From example native scripts such as `show version`, start by writing the high level `_print()` method and leave the called methods unimplemented for now. /// /// details | possible solution: Callback skeleton code type: success -``` py +``` py def _print(self, state, arguments, output, **_kwargs): data = self._fetch_state(state) result = self._populate_data(data) @@ -1896,10 +1896,10 @@ def _print(self, state, arguments, output, **_kwargs): def _fetch_state(self, state): pass - + def _populate_data(self, fetched_data): pass - + def _set_formatters(self, data): pass ``` @@ -1912,7 +1912,7 @@ Complete the `_fetch_state()` method. This is where you collect the data from `s - Which interfaces represent the ports? - Is there a YANG path that contains the traffic-rate information? - Which YANG path provide information about if a port is administratively enabled? - - Which other piece of information you need to be able to calculate the utilization % of each port? + - Which other piece of information you need to be able to calculate the utilization % of each port? /// @@ -1972,7 +1972,7 @@ percent = (traffic_rate_in_bps/port_speed_bps)*100 /// #### Adding formatters -What left is to set the formatters on the resulting `Data` object so that is printed according to your preference. +What left is to set the formatters on the resulting `Data` object so that is printed according to your preference. Complete `_set_formatters()` method. If you followed a similar schema to the one provided at beginning of the exercise, then your `Data` object has 2 children: @@ -1982,7 +1982,7 @@ If you followed a similar schema to the one provided at beginning of the exercis You can use different formatters for each. -/// admonition +/// admonition type: question - What would be the appropriate formatter for each child? /// @@ -2091,7 +2091,7 @@ class Plugin(CliPlugin): syntax=self._syntax(), callback=self._print, schema=self._schema()) - + def _syntax(self): return Syntax( name="traffic", @@ -2126,7 +2126,7 @@ class Plugin(CliPlugin): def _fetch_state(self, state): path = build_path('/interface[name={mgmt0,ethernet-*}]') return state.server_data_store.get_data(path, recursive=True) - + def _populate_data(self, fetched_data): result = Data(self._schema()) total_in_bps = 0 @@ -2163,7 +2163,7 @@ class Plugin(CliPlugin): total.total_rate_out=bps2text(total_out_bps) return result - + def _set_formatters(self, data): data.set_formatter('/port', ColumnFormatter(widths={'Port': 19,'speed':6,'util-in':10,'util-out':10})) data.set_formatter('/chassis', Border(TagValueFormatter(), Border.Below)) @@ -2172,10 +2172,10 @@ class Plugin(CliPlugin): ## Summary and review -Congratulations! If you have got this far you have completed this activity and achieved the following: +Congratulations! If you have got this far you have completed this activity and achieved the following: -- Explored the native plugins folders, files and code. -- Created a modified custom plugin based on the `show version` native plugin. +- Explored the native plugins folders, files and code. +- Created a modified custom plugin based on the `show version` native plugin. - Created the `show traffic` CLI plugin that prints the interface and system traffic rate and added it to the CLI as if it was a built-in command. The CLI Plugin infrastructure allows you to create commands that make operational sense for your network, whenever you want them and without any vendor involvement. It provides the full visibility into the system and makes it easy to get the data with all the output formats SR Linux supports - text, table, json, yaml, xml, etc. diff --git a/docs/nos/srlinux/intermediate/58-programming-snmp-mibs.md b/docs/nos/srlinux/intermediate/58-programming-snmp-mibs.md index 109651f..8d7ef4e 100644 --- a/docs/nos/srlinux/intermediate/58-programming-snmp-mibs.md +++ b/docs/nos/srlinux/intermediate/58-programming-snmp-mibs.md @@ -18,12 +18,12 @@ tags: | **Difficulty** | Intermediate | | **Tools used** | [SNMP](https://documentation.nokia.com/srlinux/24-10/books/system-mgmt/snmp.html){:target='_blank'}, [MicroPython](https://micropython.org/){:target='_blank'} | | **Topology Nodes** | :material-router: spine11, :material-router: leaf11 | -| **References** | [SR Linux's built-in MIBs and traps](https://documentation.nokia.com/srlinux/24-10/books/system-mgmt/snmp.html){:target='_blank'}
[SNMP Framework blogpost](https://learn.srlinux.dev/snmp/snmp_framework/){:target='_blank'}
[MicroPython](https://docs.micropython.org/en/latest/){:target='_blank'}
[YANG Browser](https://yang.srlinux.dev/v24.10.4){:target="_blank"}
| +| **References** | [SR Linux's built-in MIBs and traps](https://documentation.nokia.com/srlinux/24-10/books/system-mgmt/snmp.html){:target='_blank'}
[SNMP Framework blogpost](https://learn.srlinux.dev/snmp/snmp_framework/){:target='_blank'}
[MicroPython](https://docs.micropython.org/en/latest/){:target='_blank'}
[YANG Browser](https://yang.srlinux.dev/v24.10.3){:target="_blank"}
| -Many of the activities in this hackathon focus on programmability and automation in a model-driven network. There are still some systems that require the use of more traditional (dare we say, legacy?) protocols such as SNMP. Thankfully, SR Linux combines the best of both worlds with a highly configurable and flexible SNMP framework that lets you define your own MIBs and traps, using the same mechanisms that power its built-in SNMP capabilities. +Many of the activities in this hackathon focus on programmability and automation in a model-driven network. There are still some systems that require the use of more traditional (dare we say, legacy?) protocols such as SNMP. Thankfully, SR Linux combines the best of both worlds with a highly configurable and flexible SNMP framework that lets you define your own MIBs and traps, using the same mechanisms that power its built-in SNMP capabilities. -This SNMP framework is explained in detail in the following article on [customizing SNMP MIBs for Gets and Traps in SR Linux](https://learn.srlinux.dev/snmp/snmp_framework/){:target='_blank'}. +This SNMP framework is explained in detail in the following article on [customizing SNMP MIBs for Gets and Traps in SR Linux](https://learn.srlinux.dev/snmp/snmp_framework/){:target='_blank'}. In this activity, we will briefly review the most important aspects and then move straight into an example, followed by a task where you will implement an SNMP Trap yourself. @@ -76,7 +76,7 @@ flowchart LR ``` ### Management information base (MIB) -A management information base (MIB) is a formal specifications document with definitions of management information used to remotely monitor, configure, and control a managed device or network system. The agent’s management information consists of a set of network objects that can be managed with SNMP. +A management information base (MIB) is a formal specifications document with definitions of management information used to remotely monitor, configure, and control a managed device or network system. The agent’s management information consists of a set of network objects that can be managed with SNMP. Object identifiers are unique object names that are organized in a hierarchical tree structure. The main branches are defined by the Internet Engineering Task Force (IETF). When requested, the Internet Assigned Numbers Authority (IANA) assigns a unique branch for use by a private organization or company. The branch assigned to Nokia (TiMetra) is 1.3.6.1.4.1.6527. @@ -115,7 +115,7 @@ You can create custom MIB definitions following these steps: The user-defined MIB definitions and files with the associated scripts are stored in `/etc/opt/srlinux/snmp` directory, while the built-in MIB definitions are stored in `/opt/srlinux/snmp` directory. /// -Built-in MIB examples (like `if_mib.yaml`) show how interface data maps to SNMP tables using standard OIDs and types such as counters, strings, and timeticks. Your custom MIBs follow this same structure. +Built-in MIB examples (like `if_mib.yaml`) show how interface data maps to SNMP tables using standard OIDs and types such as counters, strings, and timeticks. Your custom MIBs follow this same structure. ##### Python Script @@ -195,7 +195,7 @@ A:srl# /tree xpath from state / system grpc-server /system/grpc-server[name=*]/rate-limit: ``` -Or by using the [YANG Browser](https://yang.srlinux.dev/v24.10.4){:target="_blank"}. +Or by using the [YANG Browser](https://yang.srlinux.dev/v24.10.3){:target="_blank"}. /// ```{.yaml .code-scroll-lg} @@ -240,7 +240,7 @@ tables: syntax: timeticks ``` /// details | OID definition -OIDs are typically hierarchically structured. Since this is an example, we are using an arbitrary OID within Nokia assigned enterprise branch `1.3.6.1.4.1.6527`. The suffix `115.114.108.105.110.117.120` actually decodes to `srlinux` in ASCII. +OIDs are typically hierarchically structured. Since this is an example, we are using an arbitrary OID within Nokia assigned enterprise branch `1.3.6.1.4.1.6527`. The suffix `115.114.108.105.110.117.120` actually decodes to `srlinux` in ASCII. /// The table definition file has the following important top level fields: @@ -482,7 +482,7 @@ traps: oid: 1.3.6.1.4.1.6527.115.114.108.105.110.117.120.1.1 syntax: octet string ``` -The trap definition YAML file has exactly the same top level elements as the table definition file but instead of `tables` the file contains `traps` top-level list. +The trap definition YAML file has exactly the same top level elements as the table definition file but instead of `tables` the file contains `traps` top-level list. Besides the common `name`, `enabled` and `oid` fields, the `traps` object has the following fields: @@ -798,9 +798,9 @@ There you have it: user-defined SNMP traps added to SR Linux at **runtime**, no ## Tasks -**You should read these tasks from top-to-bottom before beginning the activity**. +**You should read these tasks from top-to-bottom before beginning the activity**. -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. You are now equipped with all the knowledge to create your own custom SNMP MIBs or Traps in SR Linux. To test your newly acquired knowledge, you will create a new custom SNMP Trap. In this task you will enhance your network's observability by creating an SNMP Trap for the ACL `matched-packets` statistic. @@ -823,6 +823,38 @@ Check out the [documentation page](https://documentation.nokia.com/srlinux/24-10 /// /// details | Solution type: success +/// tab | Commands +```srl +enter candidate +system { + snmp { + access-group SNMPv2-RO-Community { + security-level no-auth-no-priv + community-entry RO-Community { + community $aes1$AWCRb2THTuMd5G8=$i60dOVPIHcmUuTNwePE+JQ== + } + } + trap-group demo { + admin-state enable + network-instance mgmt + destination collector { + admin-state enable + address 10.128.15.1 + security-level no-auth-no-priv + community-entry demo { + community $aes1$AWAp8kl/wnx0RG8=$0tiHTb7b/9pRdrUHb7b1MA== + } + } + } + network-instance mgmt { + admin-state enable + } + } +} +commit stay +``` +/// +/// tab | Expected configuration ```srl --{ + running }--[ ]-- A:g15-spine11# info system snmp @@ -853,55 +885,97 @@ A:g15-spine11# info system snmp } ``` /// +/// ### Configure an ACL on Spine11 -Configure an Access Control List (ACL) on :material-router: spine11 to capture (match and accept) ICMP packets originating from :material-router: leaf11. If you're unsure how to do this, the procedure is explained here. +Configure an Access Control List (ACL) on :material-router: spine11 to capture (match and accept) ICMP packets originating from :material-router: leaf11. If you're unsure how to do this, the procedure is explained here. 1. Create the ACL and enable statistics tracking (set statistics-per-entry to true to monitor matched packets). -2. Add an entry with matching criteria for ICMP traffic, define the match conditions (e.g. protocol type = ICMP) and specify the desired action. +2. Add an entry with matching criteria for ICMP traffic, define the match conditions (e.g. protocol type = ICMP) and specify the desired action. 3. Apply the ACL to the appropriate interface (this should be the same interface that the ICMP packets were observed on during the packet capture in the previous task). /// details | Solution type: success +/// tab | Commands +```srl +enter candidate +acl { + acl-filter ping_leaf type ipv4 { + description "ACL to capture ICMP request from leaf" + statistics-per-entry true + entry 10 { + match { + ipv4 { + protocol icmp + destination-ip { + prefix 10.46.15.31/32 + } + icmp { + type echo + } + source-ip { + prefix 10.46.15.33/32 + } + } + } + action { + accept { + } + } + } + } + interface ethernet-1/1.0 { + input { + acl-filter ping_leaf type ipv4 { + } + } + } +} +diff +commit stay ``` -A:g15-spine11# enter candidate +/// +/// tab | Expected `diff` output +```srl +--{ +* candidate shared default }--[ ]-- A:g15-spine11# diff - acl { - acl-filter ping_leaf type ipv4 { - description "ACL to capture ICMP request from leaf" - statistics-per-entry true - entry 10 { - match { - ipv4 { - protocol icmp - destination-ip { - prefix 10.46.15.31/32 - } - icmp { - type echo - } - source-ip { - prefix 10.46.15.33/32 - } - } - } - action { - accept { - } - } - } - } - interface ethernet-1/1.0 { - input { - acl-filter ping_leaf type ipv4 { - } - } - } - } + acl { ++ acl-filter ping_leaf type ipv4 { ++ description "ACL to capture ICMP request from leaf" ++ statistics-per-entry true ++ entry 10 { ++ match { ++ ipv4 { ++ protocol icmp ++ destination-ip { ++ prefix 10.46.15.31/32 ++ } ++ icmp { ++ type echo ++ } ++ source-ip { ++ prefix 10.46.15.33/32 ++ } ++ } ++ } ++ action { ++ accept { ++ } ++ } ++ } ++ } + interface ethernet-1/1.0 { + input { ++ acl-filter ping_leaf type ipv4 { ++ } + } + } + } ``` /// +/// ### Check ACL statistics Perform a ping command on :material-router: leaf11. ```bash @@ -941,7 +1015,7 @@ Entry-stats : yes Entries : 1 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Subinterface Input Output -ethernet-1/1.0 yes no +ethernet-1/1.0 yes no -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Entry 10 Match : protocol=icmp, 10.46.15.33/32(*)->10.46.15.31/32(*) @@ -986,7 +1060,7 @@ In this activity we want to expose the `matched-packets` and `last-match` statis Create the file `acl_traps.yaml` in the `etc/opt/srlinux/snmp/scripts` directory on :material-router: spine11. Take a look at the `grpc_traps.yaml` file from the example earlier and use this as a reference to see what is needed in your `.yaml` file. /// Note -Use the [YANG Browser](https://yang.srlinux.dev/v24.10.4){:target="_blank"} to easily figure out the YANG-paths you need. +Use the [YANG Browser](https://yang.srlinux.dev/v24.10.3){:target="_blank"} to easily figure out the YANG-paths you need. /// /// details | Hint 1 @@ -1135,7 +1209,7 @@ def parseACLFilterKeys(xpath: str): Extracts values from [key=value] sections in the XPath string. Should return a list of values like ['ping_leaf', 'ipv4', '10'] """ - name_pattern = re.compile(r"\[([^\[\]=]+)=([^\]]+)\]") # This regex will match "key" and "value" + name_pattern = re.compile(r"\[([^\[\]=]+)=([^\]]+)\]") # This regex will match "key" and "value" results = [] ### Your logic here to extract the values @@ -1317,33 +1391,33 @@ snmptrapd -f -Lo NET-SNMP version 5.9.1 AgentX subagent connected NET-SNMP version 5.9.1 2025-05-15 15:35:50 clab-srexperts-spine11 [UDP: [10.128.15.31]:59592->[10.128.15.1]:162]: -iso.3.6.1.2.1.1.3.0 = Timeticks: (7604300) 21:07:23.00 -iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.6527.99.117.115.116.111.109 -iso.3.6.1.6.3.1.1.4.3.0 = OID: iso.3.6.1.4.1.6527.1.20 -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.1.0 = STRING: "cpm" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.2.0 = STRING: "ipv4" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.3.0 = STRING: "10" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.4.0 = INTEGER: 1716 +iso.3.6.1.2.1.1.3.0 = Timeticks: (7604300) 21:07:23.00 +iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.6527.99.117.115.116.111.109 +iso.3.6.1.6.3.1.1.4.3.0 = OID: iso.3.6.1.4.1.6527.1.20 +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.1.0 = STRING: "cpm" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.2.0 = STRING: "ipv4" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.3.0 = STRING: "10" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.4.0 = INTEGER: 1716 iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.5.0 = Timeticks: (7604300) 21:07:23.00 2025-05-15 15:35:50 clab-srexperts-spine11 [UDP: [10.128.15.31]:59592->[10.128.15.1]:162]: -iso.3.6.1.2.1.1.3.0 = Timeticks: (7604300) 21:07:23.00 -iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.6527.99.117.115.116.111.109 -iso.3.6.1.6.3.1.1.4.3.0 = OID: iso.3.6.1.4.1.6527.1.20 -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.1.0 = STRING: "cpm" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.2.0 = STRING: "ipv4" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.3.0 = STRING: "260" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.4.0 = INTEGER: 1082346 +iso.3.6.1.2.1.1.3.0 = Timeticks: (7604300) 21:07:23.00 +iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.6527.99.117.115.116.111.109 +iso.3.6.1.6.3.1.1.4.3.0 = OID: iso.3.6.1.4.1.6527.1.20 +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.1.0 = STRING: "cpm" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.2.0 = STRING: "ipv4" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.3.0 = STRING: "260" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.4.0 = INTEGER: 1082346 iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.5.0 = Timeticks: (7604300) 21:07:23.00 2025-05-15 15:35:50 clab-srexperts-spine11 [UDP: [10.128.15.31]:59592->[10.128.15.1]:162]: -iso.3.6.1.2.1.1.3.0 = Timeticks: (7604300) 21:07:23.00 -iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.6527.99.117.115.116.111.109 -iso.3.6.1.6.3.1.1.4.3.0 = OID: iso.3.6.1.4.1.6527.1.20 -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.1.0 = STRING: "ping_leaf" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.2.0 = STRING: "ipv4" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.3.0 = STRING: "10" -iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.4.0 = INTEGER: 16 +iso.3.6.1.2.1.1.3.0 = Timeticks: (7604300) 21:07:23.00 +iso.3.6.1.6.3.1.1.4.1.0 = OID: iso.3.6.1.4.1.6527.99.117.115.116.111.109 +iso.3.6.1.6.3.1.1.4.3.0 = OID: iso.3.6.1.4.1.6527.1.20 +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.1.0 = STRING: "ping_leaf" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.2.0 = STRING: "ipv4" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.3.0 = STRING: "10" +iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.4.0 = INTEGER: 16 iso.3.6.1.4.1.6527.99.117.115.116.111.109.1.5.0 = Timeticks: (7604300) 21:07:23.00 ``` diff --git a/docs/nos/sros/beginner/41-ANYsec.md b/docs/nos/sros/beginner/41-ANYsec.md index 7d9502b..b3c997b 100644 --- a/docs/nos/sros/beginner/41-ANYsec.md +++ b/docs/nos/sros/beginner/41-ANYsec.md @@ -49,7 +49,7 @@ For this activity we will use the `PE1` and `PE2` FP5-based routers to configure In this activity you will: 1. Enable the network to support ANYsec and create a simple MPLS service to interconnect two client hosts. -2. Configure the client hosts, test the connectivity and use Wireshark, Edgeshark or TCPDump to observe the ANYsec packet headers. +2. Configure the client hosts, test the connectivity and use Wireshark, Edgeshark or TCPDump to observe the ANYsec packet headers. 3. Create gNMIc scripts to create new ANYsec enabled services, enable or disable ANYsec for a service to demonstrate how easy is to automate ANYsec activation. You'll also create a network failure to observe that ANYsec, as any other MPLS packets, are not impacted. 4. Finally we challenge you to automate ANYsec services using other technologies e.g with Python and pySROS. @@ -59,7 +59,7 @@ In this activity you will: ANYSec is a Nokia network encryption solution available with the new FP5 models introduced in the SR OS 23.10.R1 release. It is a low-latency line-rate encryption mechanism that is scalable, flexible and quantum-safe. -Based on MACSec standards as the foundation, ANYsec has flexibility to offset the authentication and encryption to allow L2, L2.5 and L3 encryption. +Based on MACSec standards as the foundation, ANYsec has flexibility to offset the authentication and encryption to allow L2, L2.5 and L3 encryption. It is currently supported for SR-ISIS, SR-OSPF and SR-OSPFv3. ANYsec encapsulates MKA over IP/UDP and supports tunnel slicing using Flex Algo or multi-instance IGP. @@ -191,13 +191,13 @@ After configuring both PEs, validate the MACsec CA configuration. /// tab | MACsec CA validation ``` bash -/show macsec connectivity-association "CA_VLL-1001" detail +/show macsec connectivity-association "CA_VLL-1001" detail ``` /// /// tab | Output ``` bash [/] -A:admin@g15-pe1# show macsec connectivity-association "CA_VLL-1001" detail +A:admin@g15-pe1# show macsec connectivity-association "CA_VLL-1001" detail =============================================================================== Connectivity Association "CA_VLL-1001" @@ -224,7 +224,7 @@ Encryption Type : aes-128-cmac =============================================================================== [/] -A:admin@g15-pe1# +A:admin@g15-pe1# ``` /// @@ -447,7 +447,7 @@ Dynamic 18432 524287 0 492848 505856 Reserved Label Blocks ------------------------------------------------------------------------------- Reserved Label Start End Total -Block Name Label Label +Block Name Label Label ------------------------------------------------------------------------------- Anysec 32000 35999 4000 ------------------------------------------------------------------------------- @@ -461,7 +461,7 @@ A:admin@g15-pe1# /// /// tab | Output - mka-over-ip ``` bash -[/] +(gl)[/] A:admin@g15-pe1# show anysec mka-over-ip =============================================================================== @@ -472,7 +472,7 @@ Reserved Label Block : Anysec Operational Status : in-service =============================================================================== -[/] +(gl)[/] A:admin@g15-pe1# ``` /// @@ -534,7 +534,7 @@ Decrypted Octets : 0 =============================================================================== (gl)[/] -A:admin@g15-pe1# +A:admin@g15-pe1# ``` /// @@ -639,6 +639,7 @@ After configuring both PEs, validate that the SDP are up at both PEs. /// /// tab | Output - SDP ``` bash +[/] A:admin@g15-pe1# show service sdp ============================================================================ @@ -758,8 +759,8 @@ Use the following parameters respectively: - sap 1/1/c6/1:1001 -If you're not familiarized with the concept of SDP (Service destination points), you may refer to the -[Services Overview Guide - SDP section](https://documentation.nokia.com/sr/25-3/7750-sr/books/services-overview/service-entities.html#ai9erp9sk9). +If you're not familiarized with the concept of SDP (Service destination points), you may refer to the +[Services Overview Guide - SDP section](https://documentation.nokia.com/sr/25-3/7750-sr/books/services-overview/service-entities.html#ai9erp9sk9). /// details | Hint @@ -926,9 +927,9 @@ A:admin@g15-pe1# ### Configure clients -Now that the network and the VLL service is configured we will configure the clients and test the connectivity. The client nodes `client01` and `client02` are connected to their respective `PE` node on interface `eth1`. +Now that the network and the VLL service is configured we will configure the clients and test the connectivity. The client nodes `client01` and `client02` are connected to their respective `PE` node on interface `eth1`. -Configure the IP for each linux client using interface `eth1:1001`, vlan `1001` and subnet `192.168.51.0/24`. +Configure the IP for each linux client using interface `eth1:1001`, vlan `1001` and subnet `192.168.51.0/24`. Then verify the connectivity between the hosts. @@ -959,7 +960,7 @@ PING 192.168.51.2 (192.168.51.2) 56(84) bytes of data. 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 5.870/8.195/10.520/2.325 ms -bash# +bash# ``` /// @@ -982,18 +983,18 @@ EdgeShark is installed in your VM and it exposes a Web UI on port 5001. You can /// tab | EdgeShark link ``` bash -# (Replace `${INSTANCE_ID}` with your `Group ID`). -http://${INSTANCE_ID}.srexperts.net:5001 +# (Replace `${INSTANCE_ID}` with your `Group ID`). +http://${INSTANCE_ID}.srexperts.net:5001 ``` /// /// note -You need SSH port forwarding in case you don't have direct reachability to the server. E.g.: -`ssh -L 5001:localhost:5001 srx-ws1.rd.ohn81.srexperts.net` +You need SSH port forwarding in case you don't have direct reachability to the server. E.g.: +`ssh -L 5001:localhost:5001 ${INSTANCE_ID}.srexperts.net` /// -EdgeShark allows you to visualize all containers in your server, select the interfaces you want to capture, and stream the capture to your laptop. For that you need Wireshark and install the [Edgeshark external capture plugin](https://github.com/siemens/cshargextcap/releases/tag/v0.10.7) in your laptop to allow Edgeshark to open your local Wireshark to display the packets. +EdgeShark allows you to visualize all containers in your server, select the interfaces you want to capture, and stream the capture to your laptop. For that you need Wireshark and install the [Edgeshark external capture plugin](https://github.com/siemens/cshargextcap/releases/tag/v0.10.7) in your laptop to allow Edgeshark to open your local Wireshark to display the packets. EdgeShark allows you to cature multiple interfaces simultaneously. Start a capture at `PE1` `eth1` and `eth2` as shown below and observe the ANYsec headers. @@ -1006,8 +1007,8 @@ Optionally you may consider install [ANYsec Packet Dissectors for Wireshark](#an #### Tshark and Tcpdump -One advantage of TCPdump is that it is available in most Linux systems, however it is limited in decoding protocols. -You can still use it and look to the MPLS labels and verify that the 2nd label is from the ANYsec label range as shown in the output below. +One advantage of TCPdump is that it is available in most Linux systems, however it is limited in decoding protocols. +You can still use it and look to the MPLS labels and verify that the 2nd label is from the ANYsec label range as shown in the output below. Tshark has more decoding capabilities and allows you to select specific interfaces to capture. @@ -1026,14 +1027,14 @@ sudo ip netns exec clab-srexperts-client01 ping -c 1 192.168.51.2 /// tab | Tshark output - Anysec ``` bash hl_lines="51 102" -nokia@rd-srx-ws1-155afda:~$ sudo ip netns exec clab-srexperts-pe1 tshark -l -i eth1 -i eth2 -Y mpls -V +❯ sudo ip netns exec clab-srexperts-pe1 tshark -l -i eth1 -i eth2 -Y mpls -V Capturing on 'eth1' and 'eth2' ** (tshark:2315673) 23:14:21.006908 [Main MESSAGE] -- Capture started. ** (tshark:2315673) 23:14:21.007039 [Main MESSAGE] -- File: "/tmp/wireshark_2_interfaces6QIE62.pcapng" -^Ctshark: +^Ctshark: 0 packets captured -nokia@rd-srx-ws1-155afda:~$ sudo ip netns exec clab-srexperts-pe1 tshark -l -i eth1 -i eth2 -Y mpls -V +❯ sudo ip netns exec clab-srexperts-pe1 tshark -l -i eth1 -i eth2 -Y mpls -V Capturing on 'eth1' and 'eth2' ** (tshark:2316298) 23:14:46.597766 [Main MESSAGE] -- Capture started. @@ -1140,15 +1141,15 @@ Data (134 bytes) Data: 88e52c0000000004000000007d650001f76021f1b67bc5bf25d0ae2bfa3a015477ea45a1… [Length: 134] -^Ctshark: +^Ctshark: 2 packets captured -nokia@rd-srx-ws1-155afda:~$ +❯ ``` /// /// tab | Tcpdump output - Anysec ``` bash hl_lines="4 15" -nokia@rd-srx-ws1-155afda:~$ sudo ip netns exec clab-srexperts-pe1 tcpdump -nni eth1 -nnvvv mpls +❯ sudo ip netns exec clab-srexperts-pe1 tcpdump -nni eth1 -nnvvv mpls tcpdump: listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes ^C21:02:50.342036 MPLS (label 21022, tc 0, ttl 255) (label 32101, tc 0, [S], ttl 255) @@ -1176,12 +1177,12 @@ tcpdump: listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 2 packets captured 2 packets received by filter 0 packets dropped by kernel -nokia@rd-srx-ws1-155afda:~$ +❯ ``` /// /// tab | Tcpdump output - ICMP clear-text ``` bash hl_lines="4 13" -nokia@rd-srx-ws1-155afda:~$ sudo ip netns exec clab-srexperts-pe1 tcpdump -nni eth2 -nnvvv mpls +❯ sudo ip netns exec clab-srexperts-pe1 tcpdump -nni eth2 -nnvvv mpls tcpdump: listening on eth2, link-type EN10MB (Ethernet), snapshot length 262144 bytes ^C21:39:52.121897 MPLS (label 21021, tc 0, ttl 254) (label 524279, tc 0, [S], ttl 255) @@ -1205,7 +1206,7 @@ tcpdump: listening on eth2, link-type EN10MB (Ethernet), snapshot length 262144 2 packets captured 2 packets received by filter 0 packets dropped by kernel -nokia@rd-srx-ws1-155afda:~$ +❯ ``` /// @@ -1236,14 +1237,14 @@ Follow the instructions provided. In summary you need an up to date Wireshark ve ### Automate ANYsec services with gNMIc -We have gone over the steps required for setting up a service between two peers that is encrypted with ANYsec. Regrettably, this involved a significant amount of manual configuration that is quite sensitive to parameters and values being aligned. Any situation where you might consider selling this to your customers via a portal where they can create, enable or disable ANYsec services at the push of a button wouldn't work if the configuration needs to be done manually. +We have gone over the steps required for setting up a service between two peers that is encrypted with ANYsec. Regrettably, this involved a significant amount of manual configuration that is quite sensitive to parameters and values being aligned. Any situation where you might consider selling this to your customers via a portal where they can create, enable or disable ANYsec services at the push of a button wouldn't work if the configuration needs to be done manually. -Fortunately, we are focused on automation here. In this task we will use `gNMIc` calls to automate the process of creating and destroying the service. +Fortunately, we are focused on automation here. In this task we will use `gNMIc` calls to automate the process of creating and destroying the service. In a real deployment, a self-service portal can be offered to your customers to align service configuration with their wishes would make these calls, though for now we will do them manually. You may use the [MD-CLI explorer tool](https://documentation.nokia.com/aces/ixr/mdcli-explorer/index.html), to find the YANG paths to use. -Your new task is to build `gNMIc` calls that can do the following: +Your new task is to build `gNMIc` calls that can do the following: 1. Retrieve the VLL configuration present on the system in JSON format 2. Create a new VLL service between two PE nodes @@ -1280,8 +1281,8 @@ gnmic -a clab-srexperts-pe2 -u admin -p $EVENT_PASSWORD --insecure get \ #### Create a new VLL service between two PE nodes Your customer requested you to add a new VLL service. You may use the existing CA and ANYsec configurations, and you only need to configure the new VLL. -Use the JSON files from previous "Get configuration information from the system" task as reference and create the configuration files for both `client01` and `client02` as well as the `gNMIc` RPC `Set` call. -Use the following parameters for the new service: +Use the JSON files from previous "Get configuration information from the system" task as reference and create the configuration files for both `client01` and `client02` as well as the `gNMIc` RPC `Set` call. +Use the following parameters for the new service: - service-name: anysec-vll-1002 - service-id: 1002 @@ -1294,8 +1295,8 @@ Use the following parameters for the new service: The example solution for creating a service makes use of the `Set` RPC. -/// tab | pe1 json -``` bash title="pe1-saved-data.json +/// tab | JSON payload for PE1 +```bash title="pe1-saved-data.json" { "admin-state": "enable", "customer": "1", @@ -1320,8 +1321,8 @@ The example solution for creating a service makes use of the `Set` RPC. ``` /// -/// tab | pe2 json -``` bash title="pe2-saved-data.json" +/// tab | JSON payload for PE2 +```bash title="pe2-saved-data.json" { "admin-state": "enable", "customer": "1", @@ -1360,7 +1361,7 @@ gnmic -a clab-srexperts-pe2 -u admin -p $EVENT_PASSWORD --insecure set \ /// tab | expected output ``` bash -$ gnmic -a clab-srexperts-pe1 -u admin -p $EVENT_PASSWORD --insecure set --update-path '/configure/service/epipe[service-name="anysec-vll-1002"]' --update-file pe1-saved-data.json +$ gnmic -a clab-srexperts-pe1 -u admin -p $EVENT_PASSWORD --insecure set --update-path '/configure/service/epipe[service-name="anysec-vll-1002"]' --update-file pe1-saved-data.json { "source": "clab-srexperts-pe1", "timestamp": 1747000595813352651, @@ -1381,14 +1382,14 @@ $ You have completed this task as you now have a `gNMIc` call to add service configuration to model-driven SR OS. -In a real deployment, for distinct customers you may need to deploy distinct CAs, distinct ANYsec configs and PSKs. -With ANYsec you mays achieve granularity per service and you can also configure slicing with traffic-engineering using e.g. Flex-Algo. +In a real deployment, for distinct customers you may need to deploy distinct CAs, distinct ANYsec configs and PSKs. +With ANYsec you can achieve granularity per service and you can also configure slicing with traffic-engineering using e.g. Flex-Algo. #### Test the new service -Your next task is to configure the clients and test the new service with the commands below. +Your next task is to configure the clients and test the new service with the commands below. /// tab | Client1 configuration @@ -1411,10 +1412,10 @@ ip -d link show eth1.1002 You may validate from the PE's CLI, using the clients and the packet inspection techniques seen previously, to make sure your calls have the expected result. -**Challenge:** Create gNMIC set to disable the link between the PE1 and P1 while you capture traffic and obverse the impact on the traffic. +**Challenge:** Create gNMIC set to disable the link between the PE1 and P1 while you capture traffic and obverse the impact on the traffic. /// details | Solution -Solution example to disable/enable the link between PE1 and P1. Note that you must disable the link on both sides. +Solution example to disable/enable the link between PE1 and P1. Note that you must disable the link on both sides. /// tab | gNMIC disable link PE1-P1 ``` bash gnmic -a clab-srexperts-pe1:57400 -u admin -p $EVENT_PASSWORD --insecure set --update-path '/configure/port[port-id=1/1/c1/1]/admin-state' --update-value disable @@ -1481,7 +1482,7 @@ gnmic -a clab-srexperts-pe2 -u admin -p $EVENT_PASSWORD --insecure getset \ #### Remove the VLL service from the PE nodes -Lets suppose that your customer no longer needs the service and wants to remove it. +Lets suppose that your customer no longer needs the service and wants to remove it. With the automation portal tool a customer can always clean up their own service configurations on your PE nodes if they so wish. Use `gNMIc` to connect to a remote system from the CLI with the [`Set`](https://gnmic.openconfig.net/cmd/set/) RPC to delete the previously created VLL `anysec-vll-1002`. /// details | Solution diff --git a/docs/nos/sros/beginner/9-custom-generic-log.md b/docs/nos/sros/beginner/9-custom-generic-log.md index 9801477..3f27b78 100644 --- a/docs/nos/sros/beginner/9-custom-generic-log.md +++ b/docs/nos/sros/beginner/9-custom-generic-log.md @@ -108,14 +108,14 @@ In this task we will ensure the event handling system is ready to respond to an This same `ehs_basic.py` file has been made available within :material-router:PE2 via container binds. ??? note - In the Hackathon environment the `/home/nokia/clab-srexperts/pe2/tftpboot/` directory on your groups Hackathon VM is made available using TFTP to the node `PE2`. Any file you put in that folder will be accessible from within SR OS using TFTP. This could be used as an alternative to `scp` or manually copying over file contents for containerlab environnments. + In the Hackathon environment the `/home/nokia/clab-srexperts/pe2/tftpboot/` directory on your groups Hackathon VM is made available using TFTP to the node `PE2`. Any file you put in that folder will be accessible from within SR OS using TFTP. This could be used as an alternative to `scp` or manually copying over file contents for containerlab environments. Any modifications you make to that file in your group's hackathon VM will be visible to the router, this is the preferred method of development as it allows you to modify the file under the Linux filesystem while being able to test on the containerlab node. !!! info "Connect to :material-router:PE2 from your group's hackathon VM" - ssh admin@clab-srexperts-pe2 + ```ssh admin@clab-srexperts-pe2``` In the box below you see that the full configuration for setting up the EHS on the node has already been prepared for you. However, the second step (creating a directory to store the `python-script` execution results) must be performed manually by you before continuing with the tasks. @@ -178,7 +178,6 @@ In the box below you see that the full configuration for setting up the EHS on t entry 10 { script-policy { name "ehs_basic" - owner "admin" } } } @@ -203,7 +202,7 @@ In the box below you see that the full configuration for setting up the EHS on t } ``` -Before proceeding, execute the command to create a results directory on :material-router: PE2 before you continue: +Before proceeding, execute the command to create a results directory on :material-router: PE2: ```bash /file make-directory cf3:/results_ehs_basic/ diff --git a/docs/nos/sros/beginner/nos-sros-activity-06.md b/docs/nos/sros/beginner/nos-sros-activity-06.md index b177d9b..7c0ebac 100644 --- a/docs/nos/sros/beginner/nos-sros-activity-06.md +++ b/docs/nos/sros/beginner/nos-sros-activity-06.md @@ -115,7 +115,7 @@ uv venv /// /// tab | expected output -``` bash +``` bash {.no-copy} Using CPython 3.11.11 Creating virtual environment at: .venv Activate with: source .venv/bin/activate @@ -136,11 +136,9 @@ You can now install pySROS. A virtual environment can be created using the builtin `venv` Python module. Create the virtual environment using the following command. -/// tab | cmd ``` bash python -m venv .venv ``` -/// It is important to make sure that you are using this newly created virtual environment. To do this use the Linux `source` command. @@ -179,7 +177,7 @@ uv pip install --upgrade pysros /// /// tab | expected output -``` bash +``` bash {.no-copy} Resolved 9 packages in 793ms Built ncclient==0.6.19 Prepared 9 packages in 2.96s @@ -217,7 +215,7 @@ python -m ensurepip ``` /// /// tab | possible outcome on Debian/Ubuntu -``` bash +``` bash {.no-copy} ensurepip is disabled in Debian/Ubuntu for the system python. Python modules for the system python are usually handled by dpkg and apt-get. @@ -245,7 +243,7 @@ pip install --upgrade pysros ``` /// /// tab | expected output -``` bash +``` bash {.no-copy} Collecting pysros Using cached pysros-25.3.1-py3-none-any.whl (85 kB) Collecting ncclient~=0.6.12 @@ -286,7 +284,7 @@ git clone https://github.com/nokia/pysros ``` /// /// tab | expected output -``` bash +``` bash {.no-copy} Cloning into 'pysros'... remote: Enumerating objects: 1000, done. remote: Counting objects: 100% (121/121), done. @@ -305,7 +303,7 @@ python -m ensurepip ``` /// /// tab | possible outcome on Debian/Ubuntu -``` bash +``` bash {.no-copy} ensurepip is disabled in Debian/Ubuntu for the system python. Python modules for the system python are usually handled by dpkg and apt-get. @@ -334,8 +332,8 @@ pip install . ``` /// /// tab | expected output -``` bash -Processing /home/nokia/jgctest/pysros +``` bash {.no-copy} +Processing /home/nokia/pysros Collecting ncclient~=0.6.12 Using cached ncclient-0.6.19.tar.gz (112 kB) Collecting lxml~=5.3.0 @@ -546,7 +544,7 @@ To be able to reproduce the output shown in the table above we require at least #### Finding the raw data -One place you might look is the [SR OS YANG explorer](https://yang.labctl.net/yang/SROS/25.3.R1/t) as it allows you to search the YANG model with a convenient web GUI. Another possible location is the MD-CLI. Last but not least, Nokia publishes the YANG models [online](https://github.com/nokia/7x50_YangModels/tree/master/latest_sros_25.3) any time a new version released. Use any of these resources to identify a path that you will be able to use to find each of the data points above for a given BGP neighbor, recognizing that those paths will be reusable when applied to a different BGP neighbor. Remember that `pwc` can provide you with reusable information. +One place you might look is the [SR OS YANG explorer](https://yang.labctl.net/yang/SROS/25.3.R1/t) as it allows you to search the YANG model with a convenient web GUI. Another possible location is the MD-CLI. Last but not least, Nokia publishes the YANG models [online](https://github.com/nokia/7x50_YangModels/tree/master/latest_sros_25.3) any time a new version is released. Use any of these resources to identify a path that you will be able to use to find each of the data points above for a given BGP neighbor, recognizing that those paths will be reusable when applied to a different BGP neighbor. Remember that `pwc` can provide you with reusable information. /// details | Solution: finding the context /// tab | Using the MD-CLI Path Finder @@ -657,7 +655,7 @@ These are the values shown for that neighbor in the table. peer-as 65000 ``` !!! tip Empty peer-as - This last one may have thrown you for a loop. The peer-as attribute in the statistics context applies only to dynamic-peers which this is neighbor is not. To find out the actual `peer-as` value we can instead look for the value set in the configuration. Note that this could be further obfuscated by a possible `type internal` configuration or the like that would make explicit configuration of the `peer-as` unnecessary. + This last one may have thrown you for a loop. The peer-as attribute in the statistics context applies only to dynamic-peers which this neighbor is not. To find out the actual `peer-as` value we can instead look for the value set in the configuration. Note that this could be further obfuscated by a possible `type internal` configuration or the like that would make explicit configuration of the `peer-as` unnecessary. @@ -670,7 +668,23 @@ Most of the information needed to build the table is now at your fingertips via To begin, make sure you have a working programmatic way of connecting to a model-driven SR OS machine. Use the pySROS [`connect`](https://documentation.nokia.com/html/3HE19211AAAFTQZZA01/pysros.html#pysros.management.connect) method by importing it from `pysros.management` and use the appropriate parameters to connect to `PE1` from your development environment. To complete this subtask, use the pySROS [`get`](https://documentation.nokia.com/sr/25-3/pysros/pysros.html#pysros.management.Datastore.get) method on the `running` datastore along with what you have learned to look up the configured system name to make sure you are on the router you expected to be on. /// details | Expected result -```bash hl_lines="7" + +/// tab | Start the Python interpreter shell +```bash title="In your development environment of choice or Hackathon instance" +python +``` +/// + +/// tab | Connect to a node using pySROS +```python +from pysros.management import connect +connection = connect(host="clab-srexperts-pe1", hostkey_verify=False, username="admin") +connection.running.get('/configure/system/name') +``` +/// + +/// tab | Expected output +```python hl_lines="7" $ python Python 3.12.3 (main, Feb 4 2025, 14:48:35) [GCC 13.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. @@ -682,6 +696,8 @@ Leaf('g23-pe1') ``` /// +/// + #### Gathering information from the paths you identified Next, use the `get` method to get the paths that you identified you would be needing later on. As a general rule of thumb, consider that remotely executed pySROS scripts prefer few `get` calls with [filters](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros-management-datastore-get-example-content-node-filters) applied while on-box execution prefers more precise and frequent `get` calls. @@ -691,68 +707,103 @@ Develop a solution that retrieves the paths required for building the table iden !!! note One of the BGP neighbors of `PE1` in the topology _is_ a dynamic neighbor so it does have a `peer-as` attribute under `statistics`. Is your solution able to capture that neighbor's information in addition to the information of the statically configured neighbors? -??? note "Solution: gathering information" - ```python - >>> neighbor_information = connection.running.get('/state/router[router-name="Base"]/bgp/neighbor') - >>> result_info = {} - >>> for neighbor,neighbor_data in neighbor_information.items(): - ... info = { - ... "recvMsg": neighbor_data["statistics"]["received"]["messages"], - ... "sentMsg": neighbor_data["statistics"]["sent"]["messages"], - ... "lastEstabTime": neighbor_data["statistics"]["last-established-time"], - ... } - ... prefix_dict = {} - ... if "negotiated-family" in neighbor_data["statistics"]: - ... for address_family in neighbor_data["statistics"]["negotiated-family"]: - ... prefix_data = neighbor_data["statistics"]["family-prefix"][address_family.lower()] - ... prefix_dict[address_family] = ( - ... prefix_data["received"], prefix_data["active"], prefix_data["sent"] - ... ) - ... info["addrFamInfo"] = prefix_dict - ... else: - ... info["addrFamInfo"] = neighbor_data["statistics"]["session-state"] - ... if neighbor_data["statistics"]["dynamically-configured"]: - ... info["peerAS"] = neighbor_data["statistics"]["peer-as"] - ... info["dynConfig"] = True - ... else: - ... group_associated_with_neighbor = connection.running.get('/configure/router[router-name="Base"]/bgp/neighbor[ip-address=%s]/group' % neighbor) - ... peer_as_from_bgp_group = connection.running.get('/nokia-conf:configure/router[router-name="Base"]/bgp/group[group-name="%s"]/peer-as' % group_associated_with_neighbor) - ... info["peerAS"] = peer_as_from_bgp_group - ... info["dynConfig"] = False - ... result_info[neighbor] = info - ... - >>> result_info - {'10.64.51.2': {'recvMsg': Leaf(7260), 'sentMsg': Leaf(7260), 'lastEstabTime': Leaf('2025-05-13T09:00:19.7Z'), 'addrFamInfo': {'IPv4': (Leaf(0), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, '10.64.54.0': {'recvMsg': Leaf(7251), 'sentMsg': Leaf(7253), 'lastEstabTime': Leaf('2025-05-13T09:04:00.9Z'), 'addrFamInfo': {'IPv4': (Leaf(0), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, 'fd00:fc00:0:51::2': {'recvMsg': Leaf(7262), 'sentMsg': Leaf(7260), 'lastEstabTime': Leaf('2025-05-13T09:00:14.9Z'), 'addrFamInfo': {'IPv6': (Leaf(3), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, 'fd00:fde8::23:11': {'recvMsg': Leaf(1499), 'sentMsg': Leaf(1238), 'lastEstabTime': Leaf('2025-05-15T11:23:59.4Z'), 'addrFamInfo': {'EVPN': (Leaf(24), Leaf(2), Leaf(8)), 'IPv4': (Leaf(50), Leaf(21), Leaf(5)), 'IPv6': (Leaf(50), Leaf(16), Leaf(4)), 'VPN-IPv4': (Leaf(22), Leaf(14), Leaf(6)), 'VPN-IPv6': (Leaf(10), Leaf(5), Leaf(3))}, 'peerAS': Leaf(65000), 'dynConfig': False}, 'fd00:fde8::23:12': {'recvMsg': Leaf(1490), 'sentMsg': Leaf(1238), 'lastEstabTime': Leaf('2025-05-15T11:23:59.4Z'), 'addrFamInfo': {'EVPN': (Leaf(36), Leaf(0), Leaf(8)), 'IPv4': (Leaf(50), Leaf(1), Leaf(5)), 'IPv6': (Leaf(50), Leaf(0), Leaf(4)), 'VPN-IPv4': (Leaf(24), Leaf(2), Leaf(6)), 'VPN-IPv6': (Leaf(12), Leaf(2), Leaf(3))}, 'peerAS': Leaf(65000), 'dynConfig': False}, 'fd00:fde8::23:13': {'recvMsg': Leaf(8086), 'sentMsg': Leaf(7271), 'lastEstabTime': Leaf('2025-05-13T09:00:17.8Z'), 'addrFamInfo': {'EVPN': (Leaf(84), Leaf(2), Leaf(8))}, 'peerAS': Leaf(65000), 'dynConfig': False}, 'fd00:fde8:0:54::': {'recvMsg': Leaf(7254), 'sentMsg': Leaf(7253), 'lastEstabTime': Leaf('2025-05-13T09:04:00.9Z'), 'addrFamInfo': {'IPv6': (Leaf(3), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, 'fe80::18b2:10ff:feff:31%leaf21': {'recvMsg': Leaf(7264), 'sentMsg': Leaf(7311), 'lastEstabTime': Leaf('2025-05-13T09:00:13.9Z'), 'addrFamInfo': {'IPv4': (Leaf(2), Leaf(2), Leaf(12)), 'IPv6': (Leaf(2), Leaf(2), Leaf(8))}, 'peerAS': Leaf(4200002001), 'dynConfig': True}} - ``` - - !!! note "Pretty Printing" - pySROS has the [printTree](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros.pprint.printTree) utility that can help you display data retrieved from the system datastores and dictionaries in general in a more convenient form: - ```python - >>> from pysros.pprint import printTree - >>> printTree(result_info) - +-- 10.64.51.2: - | +-- recvMsg: 7260 - | +-- sentMsg: 7260 - | +-- lastEstabTime: 2025-05-13T09:00:19.7Z - | +-- addrFamInfo: - | | `-- IPv4: (Leaf(0), Leaf(0), Leaf(0)) - | +-- peerAS: 64599 - | `-- dynConfig: False - +-- 10.64.54.0: - | +-- recvMsg: 7251 - | +-- sentMsg: 7253 - | +-- lastEstabTime: 2025-05-13T09:04:00.9Z - | +-- addrFamInfo: - | | `-- IPv4: (Leaf(0), Leaf(0), Leaf(0)) - | +-- peerAS: 64599 - | `-- dynConfig: False - +-- fd00:fc00:0:51::2: - | +-- recvMsg: 7262 - | +-- sentMsg: 7260 - | +-- lastEstabTime: 2025-05-13T09:00:14.9Z - ... (truncated) - ``` +/// details | Solution: gathering information +/// tab | Solution - code +```python +neighbor_information = connection.running.get('/state/router[router-name="Base"]/bgp/neighbor') +result_info = {} +for neighbor,neighbor_data in neighbor_information.items(): + info = { + "recvMsg": neighbor_data["statistics"]["received"]["messages"], + "sentMsg": neighbor_data["statistics"]["sent"]["messages"], + "lastEstabTime": neighbor_data["statistics"]["last-established-time"], + } + prefix_dict = {} + if "negotiated-family" in neighbor_data["statistics"]: + for address_family in neighbor_data["statistics"]["negotiated-family"]: + prefix_data = neighbor_data["statistics"]["family-prefix"][address_family.lower()] + prefix_dict[address_family] = ( + prefix_data["received"], prefix_data["active"], prefix_data["sent"] + ) + info["addrFamInfo"] = prefix_dict + else: + info["addrFamInfo"] = neighbor_data["statistics"]["session-state"] + if neighbor_data["statistics"]["dynamically-configured"]: + info["peerAS"] = neighbor_data["statistics"]["peer-as"] + info["dynConfig"] = True + else: + group_associated_with_neighbor = connection.running.get('/configure/router[router-name="Base"]/bgp/neighbor[ip-address=%s]/group' % neighbor) + peer_as_from_bgp_group = connection.running.get('/nokia-conf:configure/router[router-name="Base"]/bgp/group[group-name="%s"]/peer-as' % group_associated_with_neighbor) + info["peerAS"] = peer_as_from_bgp_group + info["dynConfig"] = False + result_info[neighbor] = info + +result_info +``` +/// +/// tab | Solution - output +```python {.no-copy} +>>> neighbor_information = connection.running.get('/state/router[router-name="Base"]/bgp/neighbor') +>>> result_info = {} +>>> for neighbor,neighbor_data in neighbor_information.items(): +... info = { +... "recvMsg": neighbor_data["statistics"]["received"]["messages"], +... "sentMsg": neighbor_data["statistics"]["sent"]["messages"], +... "lastEstabTime": neighbor_data["statistics"]["last-established-time"], +... } +... prefix_dict = {} +... if "negotiated-family" in neighbor_data["statistics"]: +... for address_family in neighbor_data["statistics"]["negotiated-family"]: +... prefix_data = neighbor_data["statistics"]["family-prefix"][address_family.lower()] +... prefix_dict[address_family] = ( +... prefix_data["received"], prefix_data["active"], prefix_data["sent"] +... ) +... info["addrFamInfo"] = prefix_dict +... else: +... info["addrFamInfo"] = neighbor_data["statistics"]["session-state"] +... if neighbor_data["statistics"]["dynamically-configured"]: +... info["peerAS"] = neighbor_data["statistics"]["peer-as"] +... info["dynConfig"] = True +... else: +... group_associated_with_neighbor = connection.running.get('/configure/router[router-name="Base"]/bgp/neighbor[ip-address=%s]/group' % neighbor) +... peer_as_from_bgp_group = connection.running.get('/nokia-conf:configure/router[router-name="Base"]/bgp/group[group-name="%s"]/peer-as' % group_associated_with_neighbor) +... info["peerAS"] = peer_as_from_bgp_group +... info["dynConfig"] = False +... result_info[neighbor] = info +... +>>> result_info +{'10.64.51.2': {'recvMsg': Leaf(7260), 'sentMsg': Leaf(7260), 'lastEstabTime': Leaf('2025-05-13T09:00:19.7Z'), 'addrFamInfo': {'IPv4': (Leaf(0), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, '10.64.54.0': {'recvMsg': Leaf(7251), 'sentMsg': Leaf(7253), 'lastEstabTime': Leaf('2025-05-13T09:04:00.9Z'), 'addrFamInfo': {'IPv4': (Leaf(0), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, 'fd00:fc00:0:51::2': {'recvMsg': Leaf(7262), 'sentMsg': Leaf(7260), 'lastEstabTime': Leaf('2025-05-13T09:00:14.9Z'), 'addrFamInfo': {'IPv6': (Leaf(3), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, 'fd00:fde8::23:11': {'recvMsg': Leaf(1499), 'sentMsg': Leaf(1238), 'lastEstabTime': Leaf('2025-05-15T11:23:59.4Z'), 'addrFamInfo': {'EVPN': (Leaf(24), Leaf(2), Leaf(8)), 'IPv4': (Leaf(50), Leaf(21), Leaf(5)), 'IPv6': (Leaf(50), Leaf(16), Leaf(4)), 'VPN-IPv4': (Leaf(22), Leaf(14), Leaf(6)), 'VPN-IPv6': (Leaf(10), Leaf(5), Leaf(3))}, 'peerAS': Leaf(65000), 'dynConfig': False}, 'fd00:fde8::23:12': {'recvMsg': Leaf(1490), 'sentMsg': Leaf(1238), 'lastEstabTime': Leaf('2025-05-15T11:23:59.4Z'), 'addrFamInfo': {'EVPN': (Leaf(36), Leaf(0), Leaf(8)), 'IPv4': (Leaf(50), Leaf(1), Leaf(5)), 'IPv6': (Leaf(50), Leaf(0), Leaf(4)), 'VPN-IPv4': (Leaf(24), Leaf(2), Leaf(6)), 'VPN-IPv6': (Leaf(12), Leaf(2), Leaf(3))}, 'peerAS': Leaf(65000), 'dynConfig': False}, 'fd00:fde8::23:13': {'recvMsg': Leaf(8086), 'sentMsg': Leaf(7271), 'lastEstabTime': Leaf('2025-05-13T09:00:17.8Z'), 'addrFamInfo': {'EVPN': (Leaf(84), Leaf(2), Leaf(8))}, 'peerAS': Leaf(65000), 'dynConfig': False}, 'fd00:fde8:0:54::': {'recvMsg': Leaf(7254), 'sentMsg': Leaf(7253), 'lastEstabTime': Leaf('2025-05-13T09:04:00.9Z'), 'addrFamInfo': {'IPv6': (Leaf(3), Leaf(0), Leaf(0))}, 'peerAS': Leaf(64599), 'dynConfig': False}, 'fe80::18b2:10ff:feff:31%leaf21': {'recvMsg': Leaf(7264), 'sentMsg': Leaf(7311), 'lastEstabTime': Leaf('2025-05-13T09:00:13.9Z'), 'addrFamInfo': {'IPv4': (Leaf(2), Leaf(2), Leaf(12)), 'IPv6': (Leaf(2), Leaf(2), Leaf(8))}, 'peerAS': Leaf(4200002001), 'dynConfig': True}} +``` +/// +!!! note "Pretty Printing" + pySROS has the [printTree](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros.pprint.printTree) utility that can help you display data retrieved from the system datastores and dictionaries in general in a more convenient form: + ```python {.no-copy} + >>> from pysros.pprint import printTree + >>> printTree(result_info) + +-- 10.64.51.2: + | +-- recvMsg: 7260 + | +-- sentMsg: 7260 + | +-- lastEstabTime: 2025-05-13T09:00:19.7Z + | +-- addrFamInfo: + | | `-- IPv4: (Leaf(0), Leaf(0), Leaf(0)) + | +-- peerAS: 64599 + | `-- dynConfig: False + +-- 10.64.54.0: + | +-- recvMsg: 7251 + | +-- sentMsg: 7253 + | +-- lastEstabTime: 2025-05-13T09:04:00.9Z + | +-- addrFamInfo: + | | `-- IPv4: (Leaf(0), Leaf(0), Leaf(0)) + | +-- peerAS: 64599 + | `-- dynConfig: False + +-- fd00:fc00:0:51::2: + | +-- recvMsg: 7262 + | +-- sentMsg: 7260 + | +-- lastEstabTime: 2025-05-13T09:00:14.9Z + ... (truncated) + ``` +/// #### Displaying the information in an SR OS-style table Clearly, the output from the previous subtask isn't very appealing or usable. Look through the pySROS documentation for the available [methods](https://documentation.nokia.com/sr/25-3/pysros/pysros.html#module-pysros.pprint) for displaying data or implement your own. Use it to display the information gathered in the previous task in a format inspired by the table shown in the standard `show router bgp summary` command. @@ -762,7 +813,7 @@ Clearly, the output from the previous subtask isn't very appealing or usable. Lo /// details | Solution: Printing a table /// tab | Expected outcome -```python +```python {.no-copy} >>> printTable(table,rows) =============================================================================== BGP Summary @@ -808,94 +859,99 @@ fe80::18b2:10ff:feff:31-"leaf21"(D) ``` /// /// tab | Implementation +Continue with the existing Python shell you've been using so far. /// tab | Creating the columns Column widths are created to align with the pySROS Table object and how it splits rows. ```python ->>> from pysros.pprint import Padding ->>> width = 79 # standard width ->>> cols = [ -... (79, "Neighbor"), -... (50, "Description"), -... Padding(79), #wrap to a new line -... Padding(8), -... (12, " AS"), -... (7, "PktRcvd"), -... (4, "InQ"), -... (9, "Up/Down"), -... (39, "State|Rcv/Act/Sent (Addr Family)"), -... Padding(21), -... (7, "PktSent"), -... (5, "OutQ"), -... ] ->>> +from pysros.pprint import Padding +width = 79 # standard width +cols = [ + (79, "Neighbor"), + (50, "Description"), + Padding(79), #wrap to a new line + Padding(8), + (12, " AS"), + (7, "PktRcvd"), + (4, "InQ"), + (9, "Up/Down"), + (39, "State|Rcv/Act/Sent (Addr Family)"), + Padding(21), + (7, "PktSent"), + (5, "OutQ"), +] ``` /// /// tab | Populating table rows ```python ->>> import re ->>> from datetime import datetime, timezone ->>> from pysros.pprint import Table ->>> def format_neighbor(neighbor, dyn_config): -... if "%" in neighbor: -... ip_addr, intf = neighbor.split("%") -... return ip_addr + "-\"" + intf + "\"" + ("(D)" if dyn_config else "") -... return neighbor + ("(D)" if dyn_config else "") -... -... ->>> def calculate_format_timestamp(last_estab_time): -... match = re.match("^(\\d+)-(\\d+)-(\\d+)T(\\d+):(\\d+):(\\d+).\\dZ$", last_estab_time) -... year,month,day,hour,minute,second = match.groups() -... establish_time = datetime(int(year),int(month),int(day),int(hour),int(minute),int(second), tzinfo = timezone.utc) -... time_since_last_established = datetime.now(timezone.utc) - establish_time -... hours = time_since_last_established.seconds // 3600 -... minutes = (time_since_last_established.seconds % 3600) // 60 -... return "%02dd%02dh%02dm" % (time_since_last_established.days,hours,minutes) -... -... ->>> def addr_fam_tuple(fam_tuples): -... if not isinstance(fam_tuples, dict): -... # in this case, the state is "Connect" and the peer may not be up -... return (" "+str(fam_tuples),) -... result = [] -... for family, pfx_info in fam_tuples.items(): -... result.append(" %s/%s/%s (%s)" % (pfx_info[0], pfx_info[1], pfx_info[2], family)) -... return result -... -... ->>> rows = [] ->>> for nbr, info in result_info.items(): -... fam_tuples = addr_fam_tuple(info["addrFamInfo"]) -... output = format_neighbor(nbr, info["dynConfig"]) + "\n" -... # output += description # not present -... output += "%21s" % info["peerAS"] -... output += "%8s"%info["recvMsg"] -... output += " 0 " -... output += calculate_format_timestamp(str(info["lastEstabTime"])) -... output += fam_tuples[0] -... output += "\n" -... output += "%29s"%info["sentMsg"] -... output += " 0 " -... if len(fam_tuples) > 1: -... output += "%9s%s" % ("",fam_tuples[1]) -... for fam_tuple in fam_tuples[2:]: -... output += "\n%44s%s" % ("",fam_tuple) -... rows.append(output) -... ->>> +import re +from datetime import datetime, timezone +from pysros.pprint import Table +def format_neighbor(neighbor, dyn_config): + if "%" in neighbor: + ip_addr, intf = neighbor.split("%") + return ip_addr + "-\"" + intf + "\"" + ("(D)" if dyn_config else "") + return neighbor + ("(D)" if dyn_config else "") + + +def calculate_format_timestamp(last_estab_time): + match = re.match("^(\\d+)-(\\d+)-(\\d+)T(\\d+):(\\d+):(\\d+).\\dZ$", last_estab_time) + year,month,day,hour,minute,second = match.groups() + establish_time = datetime(int(year),int(month),int(day),int(hour),int(minute),int(second), tzinfo = timezone.utc) + time_since_last_established = datetime.now(timezone.utc) - establish_time + hours = time_since_last_established.seconds // 3600 + minutes = (time_since_last_established.seconds % 3600) // 60 + return "%02dd%02dh%02dm" % (time_since_last_established.days,hours,minutes) + + +def addr_fam_tuple(fam_tuples): + if not isinstance(fam_tuples, dict): + # in this case, the state is "Connect" and the peer may not be up + return (" "+str(fam_tuples),) + result = [] + for family, pfx_info in fam_tuples.items(): + result.append(" %s/%s/%s (%s)" % (pfx_info[0], pfx_info[1], pfx_info[2], family)) + return result + + +rows = [] +for nbr, info in result_info.items(): + fam_tuples = addr_fam_tuple(info["addrFamInfo"]) + output = format_neighbor(nbr, info["dynConfig"]) + "\n" + # output += description # not present + output += "%21s" % info["peerAS"] + output += "%8s"%info["recvMsg"] + output += " 0 " + output += calculate_format_timestamp(str(info["lastEstabTime"])) + output += fam_tuples[0] + output += "\n" + output += "%29s"%info["sentMsg"] + output += " 0 " + if len(fam_tuples) > 1: + output += "%9s%s" % ("",fam_tuples[1]) + for fam_tuple in fam_tuples[2:]: + output += "\n%44s%s" % ("",fam_tuple) + rows.append(output) + ``` /// /// tab | Writing a printTable function ```python ->>> table = Table("BGP Summary", columns=cols, width=width) ->>> def printTable(table, rows): -... table.printHeader("BGP Summary") -... print("Legend : D - Dynamic Neighbor") -... table.printDoubleLine() -... table.printColumnHeaders() -... for row in rows: -... print(row) -... table.printSingleLine() -... +table = Table("BGP Summary", columns=cols, width=width) +def printTable(table, rows): + table.printHeader("BGP Summary") + print("Legend : D - Dynamic Neighbor") + table.printDoubleLine() + table.printColumnHeaders() + for row in rows: + print(row) + table.printSingleLine() + +# and call your function +printTable(table, rows) +``` +/// +/// tab | Example function call output +```python {.no-copy} >>> printTable(table, rows) =============================================================================== BGP Summary @@ -1098,11 +1154,10 @@ if __name__ == "__main__": Copy that file to `PE1` using SCP or another method to prepare for the next task. -```bash +```bash {.no-copy} $ scp bgp_summary.py admin@clab-srexperts-pe1:/cf3:/bgp_summary.py Warning: Permanently added 'clab-srexperts-pe1' (ECDSA) to the list of known hosts. - -bgp_summary.py 100% 4735 2.8MB/s 00:00 +bgp_summary.py 100% 4735 2.8MB/s 00:00 ``` ### Override the existing show command with a command-alias diff --git a/docs/nos/sros/beginner/nos-sros-show-latest-commit-activity-14.md b/docs/nos/sros/beginner/nos-sros-show-latest-commit-activity-14.md index 79b2e34..07fae8f 100644 --- a/docs/nos/sros/beginner/nos-sros-show-latest-commit-activity-14.md +++ b/docs/nos/sros/beginner/nos-sros-show-latest-commit-activity-14.md @@ -396,7 +396,7 @@ connection = connect(host = "clab-srexperts-pe1", username = "admin", hostkey_ve !!! note Executing `connect()` might take some time when it connects for the first time, as it needs to transfer information from the node to establish the connection. On posterior connections, this function will execute much faster, as the information will be kept cached. - + !!! warning The option `hostkey_verify = False` disables verification of the host key when establishing the SSH connection. This option should be enabled if used in a production environment. /// @@ -682,7 +682,7 @@ scp show-commits.py admin@clab-srexperts-pe1:cf3:/ ❯ scp show-commits.py admin@clab-srexperts-pe1:cf3:/ Warning: Permanently added 'clab-srexperts-pe1' (ECDSA) to the list of known hosts. -show-commits.py 100% 2411 784.5KB/s 00:00 +show-commits.py 100% 2411 784.5KB/s 00:00 ``` /// /// @@ -1312,7 +1312,7 @@ With the work you have put in, you should now have a basic understanding of the - Creating a Python script and setting it up as a custom `show` command in SR OS. -If you also ventured into the optional, more advanced tasks, you should also have become familiar with: +If you also ventured into the optional, more advanced tasks, you should also have become familiar with: - Using the data obtained through pySROS to extend your custom command with additional information. diff --git a/docs/nos/sros/intermediate/nos-sros-activity-05.md b/docs/nos/sros/intermediate/nos-sros-activity-05.md index 0766665..de152ab 100644 --- a/docs/nos/sros/intermediate/nos-sros-activity-05.md +++ b/docs/nos/sros/intermediate/nos-sros-activity-05.md @@ -67,15 +67,15 @@ The [SR OS system management guide](https://documentation.nokia.com/sr/25-3/7x50 ### MD-CLI alias command -SR OS MD-CLI command aliases provide a way for an operator to customize the user-experience of an SR OS node by renaming commands, creating shortcut aliases to existing commands or integrating custom developed commands directly into the MD-CLI with context sensitive help, auto-completion and the other user interface features operators love about SR OS. +SR OS MD-CLI command aliases provide a way for an operator to customize the user-experience of an SR OS node by renaming commands, creating shortcut aliases to existing commands or integrating custom developed commands directly into the MD-CLI with context sensitive help, auto-completion and the other user interface features operators love about SR OS. The [MD-CLI command reference guide](https://documentation.nokia.com/sr/25-3/7750-sr/books/md-cli-command-reference/environment_0.html#d67300) and the [SR OS system management guide](https://documentation.nokia.com/sr/25-3/7x50-shared/system-management/python.html#ai9exj5x8z) provide more information. ## Tasks -**You should read these tasks from top-to-bottom before beginning the activity**. +**You should read these tasks from top-to-bottom before beginning the activity**. -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. All supporting files can be found in the `activities/nos/sros/activity-05` directory of the repository. @@ -94,7 +94,7 @@ Create the virtual environment using the `uv` command. /// tab | cmd ``` bash uv venv -``` +``` /// /// tab | expected output @@ -122,7 +122,7 @@ A virtual environment can be created using the builtin `venv` Python module. Cr /// tab | cmd ``` bash python -m venv .venv -``` +``` /// It is important to make sure that you are using this newly created virtual environment. To do this use the Linux `source` command. @@ -158,7 +158,7 @@ Next install the pySROS package from PyPI into your virtual environment. /// tab | cmd ``` bash uv pip install --upgrade pysros -``` +``` /// /// tab | expected output @@ -197,7 +197,7 @@ Now ensure that you have the `pip` package manager installed by running the comm /// tab | cmd ``` bash python -m ensurepip -``` +``` /// /// tab | possible outcome on Debian/Ubuntu ``` bash @@ -225,7 +225,7 @@ Next install the pySROS package from PyPI into your virtual environment. /// tab | cmd ``` bash pip install --upgrade pysros -``` +``` /// /// tab | expected output ``` bash @@ -266,7 +266,7 @@ Use `git` to clone the source code repository from GitHub (where the pySROS sour /// tab | cmd ``` bash git clone https://github.com/nokia/pysros -``` +``` /// /// tab | expected output ``` bash @@ -285,7 +285,7 @@ Now ensure that you have the `pip` package manager installed by running the comm /// tab | cmd ``` bash python -m ensurepip -``` +``` /// /// tab | possible outcome on Debian/Ubuntu ``` bash @@ -314,7 +314,7 @@ Next install the pySROS package from the source code you downloaded. ``` bash cd pysros pip install . -``` +``` /// /// tab | expected output ``` bash @@ -323,21 +323,21 @@ Collecting ncclient~=0.6.12 Using cached ncclient-0.6.19.tar.gz (112 kB) Collecting lxml~=5.3.0 Downloading lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl (5.2 MB) - |████████████████████████████████| 5.2 MB 19.2 MB/s + |████████████████████████████████| 5.2 MB 19.2 MB/s Collecting paramiko>=1.15.0 Downloading paramiko-3.5.1-py3-none-any.whl (227 kB) - |████████████████████████████████| 227 kB 89.9 MB/s + |████████████████████████████████| 227 kB 89.9 MB/s Collecting pynacl>=1.5 Using cached PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (856 kB) Collecting cryptography>=3.3 Downloading cryptography-44.0.2-cp39-abi3-manylinux_2_28_x86_64.whl (4.2 MB) - |████████████████████████████████| 4.2 MB 60.4 MB/s + |████████████████████████████████| 4.2 MB 60.4 MB/s Collecting bcrypt>=3.2 Downloading bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl (284 kB) - |████████████████████████████████| 284 kB 61.7 MB/s + |████████████████████████████████| 284 kB 61.7 MB/s Collecting cffi>=1.12 Downloading cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446 kB) - |████████████████████████████████| 446 kB 86.2 MB/s + |████████████████████████████████| 446 kB 86.2 MB/s Collecting pycparser Using cached pycparser-2.22-py3-none-any.whl (117 kB) Using legacy 'setup.py install' for pysros, since package 'wheel' is not installed. @@ -363,7 +363,7 @@ Run the following command to verify the end-to-end traffic integrity of the `RED /// tab | cmd ``` bash python verify.py -``` +``` /// /// tab | expected output ``` bash @@ -371,10 +371,10 @@ Enter router password: ===================================================================================== Verification table ===================================================================================== -Host GREEN config RED config GREEN traffic RED traffic +Host GREEN config RED config GREEN traffic RED traffic ------------------------------------------------------------------------------------- -clab-srexperts-pe1 False False False False -clab-srexperts-pe2 True True False False +clab-srexperts-pe1 False False False False +clab-srexperts-pe2 True True False False ===================================================================================== ``` /// @@ -404,10 +404,10 @@ Having obtained a pySROS formatted data structure containing the configuration, /// details | Hint type: tip -pySROS utilizes NETCONF as the underlying protocol. +pySROS utilizes NETCONF as the underlying protocol. + +NETCONF requires the operator to supply a top level path and (currently) pySROS requires the same. -NETCONF requires the operator to supply a top level path and (currently) pySROS requires the same. - You have been provided with the full JSON IETF formatted configuration back to the YANG modeled root. This includes the top level path, therefore, you will need to strip this off and supply it as the `path` parameter of the pySROS `set` method. /// @@ -420,7 +420,7 @@ Run the following command to verify the end-to-end traffic integrity of the `RED /// tab | cmd ``` bash python verify.py -``` +``` /// /// tab | expected output ``` bash @@ -428,15 +428,15 @@ Enter router password: ===================================================================================== Verification table ===================================================================================== -Host GREEN config RED config GREEN traffic RED traffic +Host GREEN config RED config GREEN traffic RED traffic ------------------------------------------------------------------------------------- -clab-srexperts-pe1 True False True False -clab-srexperts-pe2 True True True False +clab-srexperts-pe1 True False True False +clab-srexperts-pe2 True True True False ===================================================================================== ``` /// -If your application works correctly, you will have been able to configure :material-router: PE1 on the command line, using your program, and the configuration for the `GREEN` VPRN should be shown present on :material-router: PE1. +If your application works correctly, you will have been able to configure :material-router: PE1 on the command line, using your program, and the configuration for the `GREEN` VPRN should be shown present on :material-router: PE1. Both :material-router: PE1 and :material-router: PE2 should be able to ping each other over the `GREEN` VPRN showing that traffic is flowing correctly. @@ -525,7 +525,7 @@ You may wish to consider the `input()` Python method to solve this part of the a ### Configure SR OS to reference your application -Configure this Python application info the SR OS configuration using the `/configure python python-script`. Make sure you identify it as a `python3` script. +Configure this Python application into the SR OS configuration using the `/configure python python-script`. Make sure you identify it as a `python3` script. ### Create a SR OS command-alias pointing to your configured Python application @@ -542,7 +542,7 @@ If you get stuck and need to return the lab to it's original starting position, ``` bash python setup-activity.py teardown --configure-all python setup-activity.py setup -``` +``` /// /// tab | expected output 1 ``` bash diff --git a/docs/nos/sros/intermediate/nos-sros-activity-08.md b/docs/nos/sros/intermediate/nos-sros-activity-08.md index deb39d3..43ae3e9 100644 --- a/docs/nos/sros/intermediate/nos-sros-activity-08.md +++ b/docs/nos/sros/intermediate/nos-sros-activity-08.md @@ -211,16 +211,31 @@ For `PE2` the NETCONF port is mapped to the your group's hackathon VM's port 504 Once the connection object has been created, try to `get` the system's `oper-name` attribute from the running datastore to confirm we connected to the correct node. -/// details | Solution - Connecting and executing a basic `get` -```bash +/// details | Solution - connecting and executing a basic `get` +/// tab | Start the Python interpreter shell +```bash title="In your development environment of choice or your group's Hackathon VM." +python +``` +/// +/// tab | Connect and get something using pySROS +```python +from pysros.management import connect +connection = connect(host="23.srexperts.net", username="admin", hostkey_verify=False, password=#PROVIDED#, port=50422) +connection.running.get('/configure/system/name') +``` +/// +/// tab | Expected outcome +```bash {.no-copy} (env) wsl-ubuntu: python Python 3.10.12 (main, Jan 17 2025, 14:35:34) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from pysros.management import connect >>> connection = connect(host="23.srexperts.net", username="admin", hostkey_verify=False, password=#PROVIDED#, port=50422) >>> connection.running.get('/state/system/oper-name') -Leaf('g8-pe2') +Leaf('g23-pe2') ``` +/// + /// admonition | Host key verification type: warning As you can see from the example output or as you might have noticed, the `hostkey_verify` keyword parameter for the `connect` call is set to `False`. This makes us vulnerable to man-in-the-middle attacks. The alternative to disabling the verification is explicitly connecting to each node on the desired port to save the associated key, however for lab environments that are cleaned up and recreated regularly this is not efficient. In addition, the danger of this vulnerability is lessened greatly in such lab environments. In any live network environment `hostkey_verify` should be set to `True`. @@ -230,6 +245,14 @@ As you can see from the example output or as you might have noticed, the `hostke ///tip | Pretty Output You can use the [`printTree` function](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros.pprint.TreePrinter){:target="_blank"} to print data retrieved in a more readable format +/// tab | Code +```python +from pysros.pprint import printTree +data=connection.running.get('/state/port[port-id="1/1/c4/1"]/statistics') +printTree(data) +``` +/// +/// tab | Execution ```python >>> from pysros.pprint import printTree >>> data=connection.running.get('/state/port[port-id="1/1/c4/1"]/statistics') @@ -270,7 +293,7 @@ You can use the [`printTree` function](https://network.developer.nokia.com/stati `-- queue-id: 8 ``` /// - +/// #### Get LLDP information using your interactive interpreter @@ -367,10 +390,9 @@ To complete this sub-task, implement logic in Python that retrieves `remote-port /// /// tab | Solution ```python ->>> from pysros.pprint import printTree ->>> lldp_state=connection.running.get('/state/port',\ -... filter={"ethernet": {"lldp": {"dest-mac": { "remote-system": { "system-name": { }, "remote-port-id": { } } } } } } ) ->>> +from pysros.pprint import printTree +lldp_state=connection.running.get('/state/port',filter={"ethernet": {"lldp": {"dest-mac": { "remote-system": { "system-name": { }, "remote-port-id": { } } } } } } ) +printTree(lldp_state) ``` /// @@ -585,8 +607,8 @@ Having built up the code, we can now copy it onto our model-driven SR OS `PE2` n If you are developing on your own platform, the port mapped to `PE2`'s port 22 is `50022`. If you are working on your group's hackathon VM you can go directly to `clab-srexperts-pe2`. -??? note "[vrnetlab](https://github.com/hellt/vrnetlab/tree/master/sros) SR OS tftpboot" - If you use SR OS in containerlab, a file location is created and is reachable from within SR OS as a TFTP location, `tftp://172.31.255.29/`. In the Hackathon topology and environment, for node `PE2`, that location is `/home/nokia/clab-srexperts/pe2/tftpboot/`. The result of this is that any file you put in that folder will be accessible from within SR OS using TFTP. This could be used as an alternative to `scp` or manually copying over the file contents for containerlab environnments. +??? note "[vrnetlab](https://github.com/srl-labs/vrnetlab/tree/master/nokia/sros) SR OS tftpboot" + If you use SR OS in containerlab, a file location is created and is reachable from within SR OS as a TFTP location, `tftp://172.31.255.29/`. In the Hackathon topology and environment, for node `PE2`, that location is `/home/nokia/clab-srexperts/pe2/tftpboot/`. The result of this is that any file you put in that folder will be accessible from within SR OS using TFTP. This could be used as an alternative to `scp` or manually copying over the file contents for containerlab environments. /// details | Running your script with `pyexec` ``` @@ -669,9 +691,9 @@ With the `log` configuration and the code ready, the `script` object to be refer Finally, create the policy referenced by the event-handler from the previous step. To do this, add configuration to `/configure system script-control` that references the created `python-script` object. Once complete, `commit` your changes into the running datastore to make sure they are usable in the next section. /// details | Solution - Script and EHS configuration +Commands required to make the necessary configuration updates: ``` -*(pr)[/] -A:admin@g23-pe2# compare +edit-config private configure { log { event-handling { @@ -723,6 +745,8 @@ A:admin@g23-pe2# compare } } } +commit +quit-config ``` /// @@ -747,6 +771,16 @@ With everything in place, try bringing down and restoring an LLDP session to tri /// Details | Bring down and recover LLDP neighborships /// tab | For a single port ``` +edit-config private +/configure port 1/1/c1/1 ethernet lldp dest-mac nearest-bridge receive false transmit false +commit +/configure port 1/1/c1/1 ethernet lldp dest-mac nearest-bridge receive true transmit true +commit +quit-config +``` +/// +/// tab | For a single port - example +``` (pr)[/] A:admin@g23-pe2# # Bring down the LLDP session on port 1/1/c1/1 @@ -768,6 +802,16 @@ A:admin@g23-pe2# commit /// /// tab | For all ports ``` +edit-config private +delete /configure apply-groups "lldp" +commit +/configure apply-groups "lldp" +commit +quit-config +``` +/// +/// tab | For all ports (example) +``` (pr)[/] A:admin@g23-pe2# # Bring down the LLDP session on all ports by removing all LLDP configuration @@ -792,7 +836,7 @@ A:admin@g23-pe2# /// /// -Does your solution behave as expected? Before proceeding, make sure the `apply-group` or / and LLDP configuration is in the same state as it was originally in order not to interfere with any other usecases. +Does your solution behave as expected? Before proceeding, make sure the `apply-group` or / and LLDP configuration is in the same state as it was originally in order not to interfere with any other activities. Testing your script on `PE2` is well and good, however the real use case only becomes apparent once you make changes on neighboring nodes and let your automation pick up on the events. diff --git a/docs/nos/sros/intermediate/nos-sros-activity-21.md b/docs/nos/sros/intermediate/nos-sros-activity-21.md index 615ea30..1ef24d9 100644 --- a/docs/nos/sros/intermediate/nos-sros-activity-21.md +++ b/docs/nos/sros/intermediate/nos-sros-activity-21.md @@ -183,7 +183,20 @@ If you are using your own platform outside the hackathon environment you can mak Once the connection object has been created, try to `get` the system's `oper-name` attribute from the running datastore to confirm we reached the correct node. /// details | Connecting and executing a basic get -```bash +/// tab | Start the Python interpreter shell +```bash title="In your development environment of choice or your group's Hackathon VM." +python +``` +/// +/// tab | Connect and get something using pySROS +```python +from pysros.management import connect +connection = connect(host="clab-srexperts-pe1", hostkey_verify=False, username="admin") +connection.running.get('/configure/system/name') +``` +/// +/// tab | Expected outcome +```bash {.no-copy} (env) wsl-ubuntu: python Python 3.10.12 (main, Jan 17 2025, 14:35:34) [GCC 11.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. @@ -193,6 +206,7 @@ Type "help", "copyright", "credits" or "license" for more information. Leaf('g21-pe1') ``` /// +/// /// admonition | Host key verification type: warning @@ -220,13 +234,22 @@ You may find the use of For VPRN services the same is not true, as the service name could be anything and a regular [`get`](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros.management.Datastore.get) call is required. This can be optimized using [selection node filters](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros-management-datastore-get-example-selection-node-filters) to retrieve less data in total. /// details | Finding the bgp neighbor configuration with pySROS +Using your existing Python shell, run the code below: +/// tab | Code +```python +connection.running.get_list_keys('/nokia-conf:configure/router[router-name="Base"]/bgp/neighbor') +connection.running.get('/nokia-conf:configure/service/vprn', filter= {"bgp": { "neighbor": { "ip-address": {}} } }) ``` +/// +/// tab | Expected result +```python {.no-copy} >>> connection.running.get_list_keys('/nokia-conf:configure/router[router-name="Base"]/bgp/neighbor') ['10.64.51.2', '10.64.54.0', 'fd00:fc00:0:51::2', 'fd00:fde8::23:11', 'fd00:fde8::23:12', 'fd00:fde8::23:13', 'fd00:fde8:0:54::'] >>> connection.running.get('/nokia-conf:configure/service/vprn', filter= {"bgp": { "neighbor": { "ip-address": {}} } }) {'dci': Container({'service-name': Leaf('dci'), 'bgp': Container({'neighbor': {'12.3.3.3': Container({'ip-address': Leaf('12.3.3.3')})}})})} ``` /// +/// ### Create prefix-list configuration Prefix lists to be used in SR OS are configured in the `configure filter match-list` context. Find the correct translation of this path for use in your Python interpreter such that the interpreter is able to create `ip-prefix-list` and `ipv6-prefix-list` objects. Use that path and an appropriate dictionary to create 2 match-lists (one for ipv4, another for ipv6) that include all BGP neighbors you found in the previous step. @@ -234,7 +257,35 @@ Prefix lists to be used in SR OS are configured in the `configure filter match-l One possible method for determining the expected structure and hierarchy of data that needs to be put in a [`set`](https://network.developer.nokia.com/static/sr/learn/pysros/latest/pysros.html#pysros.management.Datastore.set) call is by configuring the desired state on SR OS and using `get`. The output retrieved from the system will contain the configuration converted into the correct Python object, allowing you to go from there by building on top of known good information. /// details | Create match lists +Using your existing Python shell, run the code below: +/// tab | Code ```python +import ipaddress +ipv4_peers, ipv6_peers = set(), set() +peers = connection.running.get_list_keys('/nokia-conf:configure/router[router-name="Base"]/bgp/neighbor') +svc_peers = connection.running.get('/nokia-conf:configure/service/vprn', filter= {"bgp": { "neighbor": { "ip-address": {}} } }) +for k,v in svc_peers.items(): + if "neighbor" not in v["bgp"].keys(): + continue + for address in v["bgp"]["neighbor"].keys(): + peers.append(address) + +for peer in peers: + if ipaddress.ip_address(peer).version == 4: + ipv4_peers.add(peer) + else: + ipv6_peers.add(peer) + +path = '/nokia-conf:configure/filter/match-list/ip-prefix-list[prefix-list-name="pysros-match-list"]' +payload = { "prefix": { "%s/32"%peer: {"ip-prefix": f"%s/32"%peer} for peer in ipv4_peers } } +connection.candidate.set(path, payload, commit=False) +path = '/nokia-conf:configure/filter/match-list/ipv6-prefix-list[prefix-list-name="pysros-match-list"]' +payload = { "prefix": { "%s/128"%peer: {"ipv6-prefix": "%s/128"%peer} for peer in ipv6_peers } } +connection.candidate.set(path, payload, commit=True) +``` +/// +/// tab | Expected execution result +```python {.no-copy} >>> import ipaddress >>> ipv4_peers, ipv6_peers = set(), set() >>> peers = connection.running.get_list_keys('/nokia-conf:configure/router[router-name="Base"]/bgp/neighbor') @@ -263,7 +314,7 @@ One possible method for determining the expected structure and hierarchy of data >>> connection.candidate.set(path, payload, commit=True) ``` /// - +/// To complete this step, exit your interactive Python shell once you confirm that the configuration exists in the target SR OS node, `PE1`. You can do this using your pySROS connection or simply by logging in to the node. !!! tip "Private candidate" @@ -275,6 +326,37 @@ To complete this step, exit your interactive Python shell once you confirm that By default, the creation you have now created is not used anywhere. In this optional subtask we will use the created match-list to populate an entry in the `cpm-filter` on `PE1`. We will use entries that are set to `accept` with a `default-action accept` so as not to impact the topology routing or lock ourselves out of the system. +/// tab | Commands +``` +edit-config private +configure { + system { + security { + cpm-filter { + default-action accept + ipv6-filter { + admin-state enable + entry 10 { + match { + router-instance "Base" + src-ip { + ipv6-prefix-list "pysros_match_list" + } + } + action { + accept + } + } + } + } + } + } +} +commit +quit-config +``` +/// +/// tab | Compared result with existing configuration ``` *(pr)[/] A:admin@pe1# compare / @@ -302,6 +384,7 @@ A:admin@pe1# compare / } } ``` +/// If you're using this approach you can check the effect and correctness of your prefix list using the following commands: @@ -394,7 +477,7 @@ Having built up the code, we can now copy it onto our model-driven SR OS `PE1` n Once your file is prepared and reachable, run it with `pyexec` on `PE1` to make sure it still works as expected. /// details | Running your script with `pyexec` -``` +```hl_lines="7" [/] A:admin@g21-pe1# edit-config private INFO: CLI #2070: Entering private configuration mode @@ -432,6 +515,40 @@ A next step, now that we are able to use our code from within SR OS, is to make Use the [documentation](https://documentation.nokia.com/sr/25-3/7x50-shared/md-cli-user/navigate.html#concept_hkg_hb3_bqb) for command aliases to create an alias called `align-prefix-lists` that is mounted under the `tools` context and calls a `python-script` object that calls your script file. You'll also have to create this `python-script` object. Test and make sure that the alias works the same as the `pyexec` approach by removing some prefixes from the previously created prefix-lists or by creating new BGP peer entries. /// details | Solution - creating an alias +/// tab | Commands +``` +edit-config private +configure { + python { + python-script "align-prefix-lists" { + admin-state enable + urls ["cf3:/match_lists.py"] + version python3 + } + } + system { + management-interface { + cli { + md-cli { + environment { + command-alias { + alias "align-prefix-lists" { + admin-state enable + python-script "align-prefix-lists" + mount-point "/tools" { } + } + } + } + } + } + } + } +} +commit +quit-config +``` +/// +/// tab | Example changes and usage ``` *[pr:/configure] A:admin@g21-pe1# compare / @@ -476,6 +593,7 @@ A:admin@g21-pe1# /tools align-prefix-lists dump perform ``` /// +/// ### Make it automated @@ -515,63 +633,119 @@ Create the `script-policy` and review your changes, make sure anything that need - the `event-handler`, as it doesn't boast much in the way of configuration but all information is linked to it. Use `/show log event-handling information` to see if you can find an issue. - the `script-policy`, as we had already verified in the previous task that the `python-script` works by way of the alias. Use `/show system script-control script-policy "match_lists"` to identify issues. -??? note "Solution - required configuration changes" - ``` - *[pr:/configure] - A:admin@g21-pe1# compare / - configure { - log { - event-handling { - handler "match_lists" { - admin-state enable - entry 10 { - script-policy { - name "match_lists" - } +/// details | Solution - required configuration changes +/// tab | Commands +``` +edit-config private +configure { + log { + event-handling { + handler "match_lists" { + admin-state enable + entry 10 { + script-policy { + name "match_lists" } } } - event-trigger { - system event mdCommitSucceeded { - admin-state enable - description "event-trigger for activity #21" - entry 10 { - filter "10" - handler "match_lists" - } + } + event-trigger { + system event mdCommitSucceeded { + admin-state enable + description "event-trigger for activity #21" + entry 10 { + filter "10" + handler "match_lists" } } - filter "10" { - default-action forward - } } - system { - script-control { - script-policy "match_lists" owner "TiMOS CLI" { - admin-state enable - results "/null" - python-script { - name "align-prefix-lists" - } + filter "10" { + default-action forward + } + } + system { + script-control { + script-policy "match_lists" owner "TiMOS CLI" { + admin-state enable + results "/null" + python-script { + name "align-prefix-lists" } } } } - ``` - + } +commit +quit-config +``` +/// +/// tab | Compare output +``` +*(pr)[/] +A:admin@g21-pe1# compare / + configure { + log { + event-handling { ++ handler "match_lists" { ++ admin-state enable ++ entry 10 { ++ script-policy { ++ name "match_lists" ++ } ++ } ++ } + } + event-trigger { ++ system event mdCommitSucceeded { ++ admin-state enable ++ description "event-trigger for activity #21" ++ entry 10 { ++ filter "10" ++ handler "match_lists" ++ } ++ } + } ++ filter "10" { ++ default-action forward ++ } + } + system { ++ script-control { ++ script-policy "match_lists" owner "TiMOS CLI" { ++ admin-state enable ++ results "/null" ++ python-script { ++ name "align-prefix-lists" ++ } ++ } ++ } + } + } +``` +/// +/// #### Test the functionality Commit your changes and make sure the different elements are operationally up. Add BGP peer `192.168.0.1` to the service `dci` configuration. Was your match-list configuration updated? /// details | Testing your implementation +/// tab | Add a BGP peer to the configuration +``` +edit-config private +/configure service vprn dci bgp group neighbor +/configure service vprn dci bgp neighbor 192.168.0.1 group "neighbor" +commit ``` +/// +/// tab | Expected result +``` hl_lines="16" [/] A:admin@g21-pe1# edit-config private INFO: CLI #2070: Entering private configuration mode INFO: CLI #2061: Uncommitted changes are discarded on configuration mode exit (pr)[/] -A:admin@g21-pe1# configure service vprn dci bgp group neighbor +A:admin@g21-pe1# /configure service vprn dci bgp group neighbor *(pr)[/configure service vprn "dci" bgp group "neighbor"] A:admin@g21-pe1# /configure service vprn dci bgp neighbor 192.168.0.1 group "neighbor" @@ -592,6 +766,7 @@ A:admin@g21-pe1# compare baseline running / } ``` /// +/// Remove the previously added BGP peer from your configuration and commit the changes. Does your configuration look as you had expected? diff --git a/docs/nos/sros/intermediate/nos-sros-activity-23.md b/docs/nos/sros/intermediate/nos-sros-activity-23.md index 9b2f326..35e762b 100644 --- a/docs/nos/sros/intermediate/nos-sros-activity-23.md +++ b/docs/nos/sros/intermediate/nos-sros-activity-23.md @@ -138,7 +138,7 @@ show service active-subscribers /// tab | Expected output ``` [/] -A:admin@g##-pe4# show service active-subscribers +A:admin@g23-pe4# show service active-subscribers =============================================================================== Active Subscribers @@ -216,25 +216,34 @@ To do this, log in to any of the emulated client devices using SSH. They are ava /// details | Logging in to a virtual subscriber /// tab | From inside the Hackathon VM ```bash -$ ssh -l user clab-srexperts-sub3 +ssh -l admin clab-srexperts-sub3 +``` +

+```{.text .no-select .no-copy} Warning: Permanently added 'clab-srexperts-sub3' (ED25519) to the list of known hosts. [*]─[sub3]─[~] └──> ``` +
/// /// tab | From outside the Hackathon VM ```bash -$ ssh -l user 23.srexperts.net -p 50063 +ssh -l admin 23.srexperts.net -p 50063 +``` +
+```{.text .no-select .no-copy} The authenticity of host '[23.srexperts.net]:50063 ([23.srexperts.net]:50063)' can't be established. ED25519 key fingerprint is SHA256:OkKDNbCUoVhEP3Up6TSjpsB9skvBrpsvMobr025B4i8. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '[23.srexperts.net]:50063' (ED25519) to the list of known hosts. -user@23.srexperts.net's password: #PROVIDED# +admin@23.srexperts.net's password: #PROVIDED# -bash# +[*]─[sub3]─[~] +└──> ``` +
/// /// @@ -329,7 +338,7 @@ If additional information from the Radius server is required, the server's logs `docker exec -it clab-srexperts-radius tail -f /var/log/radius/radius.log` -As an example, consider that this file may include additional information from the Radius server about why it is declining certain requests. +from your group's hackathon VM instance. As an example, consider that this file may include additional information from the Radius server about why it is declining certain requests. ### Add an attribute into Radius Accounting Requests using configuration @@ -470,8 +479,7 @@ A:admin@g23-pe4# /clear service id 401 ipoe session all All three subscribers should reappear in the system after this operation. /// details | Modify DHCP script to cache options for Radius accounting -/// tab | Modified version of script found under `/home/nokia/SReXperts/activities/nos/sros/activity-23/dhcp.py` -```python +```python title="Modified version of script found under /home/nokia/SReXperts/activities/nos/sros/activity-23/dhcp.py" from alc import dhcpv4 from alc import cache from binascii import unhexlify @@ -533,7 +541,6 @@ if __name__ == "__main__": # REQUEST is attr 53 value 1 dhcp4_request() ``` -/// /// tab | Cache for UE MAC 00:d0:f6:01:01:01 - before ``` [/] @@ -580,6 +587,21 @@ The file `/home/nokia/SReXperts/activities/nos/sros/activity-23/radius-accountin For this step, you will have to modify the `python-policy` that is currently in use for your subscribers to apply the pre-provisioned Python script `radius-accounting-request` to Radius Accounting-Request packages headed towards the Radius server. The script doesn't do anything yet, that will be addressed later. /// details | Add the radius-accounting-request `python-script` to the `python-policy` +/// tab | Commands +``` +configure global +python { + python-policy "python-policy" { + radius accounting-request direction egress { + script "radius-accounting-request" + } + } +} +compare / +commit +``` +/// +/// tab | Compare output ``` *[gl:/configure] A:admin@g23-pe4# compare / @@ -594,6 +616,7 @@ A:admin@g23-pe4# compare / } ``` /// +/// Next up, you will modify the `radius-accounting-request.py` file so that it copies cached DHCP options into Radius Accounting Requests. Add your DHCP options to Radius Vendor-Specific Attribute (VSA) 26.6527.102, `Alc-ToServer-Dhcp-Options`. Check the [Radius reference guide](https://documentation.nokia.com/sr/25-3/7750-sr/titles/radius.html) for formatting details. Use the debugging and test methods shown above to verify your changes behave as expected. diff --git a/docs/nos/sros/intermediate/nos-sros-activity-56.md b/docs/nos/sros/intermediate/nos-sros-activity-56.md index 5ff5aef..dd923f2 100644 --- a/docs/nos/sros/intermediate/nos-sros-activity-56.md +++ b/docs/nos/sros/intermediate/nos-sros-activity-56.md @@ -133,12 +133,12 @@ Look inside the files to understand where each piece of information is stored an ### Run the existing playbook and look at the output -Run the existing playbook using the `ansible-playbook` command. Use a CLI flag to point to the inventory file and check the output. What do you notice? +Run the existing playbook from your group's hackathon VM instance using the `ansible-playbook` command. Use a CLI flag to point to the inventory file and check the output. What do you notice? /// Details | Output /// tab | Command ```bash -$ ansible-playbook playbook.yml -i inventory.yml +ansible-playbook playbook.yml -i inventory.yml ``` /// /// tab | Expected Output diff --git a/docs/nos/sros/intermediate/nos-sros-activity-63.md b/docs/nos/sros/intermediate/nos-sros-activity-63.md index 16e103e..9edc74a 100644 --- a/docs/nos/sros/intermediate/nos-sros-activity-63.md +++ b/docs/nos/sros/intermediate/nos-sros-activity-63.md @@ -223,7 +223,7 @@ You could also start the `crond` process on the emulated subscribers using `sudo /// details | Subscriber renewal as seen from client `sub1` /// tab | Command ```bash -bash# while :; do sudo ifdown eth1.100; sudo ifup eth1.100; sleep 15; done +while :; do sudo ifdown eth1.100; sudo ifup eth1.100; sleep 15; done ``` /// /// tab | Expected output @@ -280,7 +280,7 @@ configure { Above, the different contexts and configuration modes have been highlighted. To add configuration to the debug context we will have to open an `exclusive` configuration session on it and add the required statements. Add configuration to the debug context to ensure that all Radius traffic related to authentication from the Radius server with IP address `10.64.13.0` in the Base router is marked as debug information. /// details | Expected result -``` +```text {.no-copy} [ex:/debug] A:admin@g23-pe4# info router "Base" { @@ -302,10 +302,15 @@ If additional information from the Radius server is required, the server's logs `docker exec -it clab-srexperts-radius tail -f /var/log/radius/radius.log` -As an example, consider that this file may include additional information from the Radius server about why it is declining certain requests. Before proceeding to the next section, find out for the three subscribers in our topology which values the Radius server is returning in the Radius Access Accept for attributes `Alc-PySROS-Script-Policy` and `Alc-PySROS-Script-Params`. +from your group's hackathon VM instance. As an example, consider that this file may include additional information from the Radius server about why it is declining certain requests. Before proceeding to the next section, find out for the three subscribers in our topology which values the Radius server is returning in the Radius Access Accept for attributes `Alc-PySROS-Script-Policy` and `Alc-PySROS-Script-Params`. /// details | Gather information being sent down by Radius -/// tab | Trigger a renewal for each subscriber host +/// tab | Command to trigger a subscriber renewal +```bash +sudo ifdown eth1.100; sudo ifup eth1.100 +``` +/// +/// tab | Example execution For sub1: ```bash @@ -542,10 +547,32 @@ To complete this task, look into the configuration for the script policies and c /// details | Changes required /// tab | Explanation -The status we find in the configuration is that each script-policy has been administratively disabled. In addition, the results locations has been set to `/null` to ensure there can be no clogging up of the system with log files that aren't being looked at. For debugging and development purposes, we will write the output generated by our script-policy whenever it runs to a directory on `cf3:`. +The status we find in the configuration is that each script-policy has been administratively disabled. In addition, the results locations has been set to `/null` to ensure there can be no clogging up of the system with log files that aren't being looked at. For debugging and development purposes, we will write the output generated by our `script-policy` whenever it runs to a directory on `cf3:`. /// /// tab | Commands ``` +configure global + system { + script-control { + script-policy "sub1-script-policy" owner "TiMOS CLI" { + admin-state enable + results "cf3:/sub1_results/" + } + script-policy "sub2-3-script-policy" owner "TiMOS CLI" { + admin-state enable + results "cf3:/sub2_3_results/" + } + } + } +compare / +commit +/file make-directory sub1_results/ +/file make-directory sub2_3_results/ + +``` +/// +/// tab | Compare output +``` *[gl:/configure] A:admin@g23-pe4# compare / configure { @@ -793,11 +820,19 @@ if __name__ == "__main__": The configuration of the subscribers expects that `sub2`'s second interface on VLAN 2000 has layer-2 connectivity to VLAN 3000 on the second interface of `sub-3` in subnet `192.168.190.0/24`. Confirm they can reach each other using `ping`. + +/// tab | Command to test connectivity through dynamic service (on node `sub2`) +```bash +ping -c 1 192.168.190.3 +``` +/// +/// tab | Example output ```bash bash# ping -c 1 192.168.190.3 PING 192.168.190.3 (192.168.190.3) 56(84) bytes of data. 64 bytes from 192.168.190.3: icmp_seq=1 ttl=64 time=1.36 ms ``` +/// ### Optional - sending custom log events @@ -820,8 +855,7 @@ quit-config /// /// tab | Stopping `crond` on `sub` instances ```bash -bash# sudo kill -8 "$(pgrep crond.*)" - +sudo kill -8 "$(pgrep crond.*)" ``` /// /// diff --git a/docs/nsp/advanced/57-nsp-netbox.md b/docs/nsp/advanced/57-nsp-netbox.md index 3b15b42..367dafa 100644 --- a/docs/nsp/advanced/57-nsp-netbox.md +++ b/docs/nsp/advanced/57-nsp-netbox.md @@ -5,75 +5,78 @@ tags: - Python --- -# Deploying NSP Intents using Netbox +# Integrating NSP w/ NetBox | | | | --- | --- | -| **Activity name** | Deploying NSP Intents with NetBox | +| **Activity name** | Integrating NSP w/ NetBox | | **Activity ID** | 57 | | **Short Description** | Use NetBox for infrastructure management on top of NSP to create/update infrastructure intents. | | **Difficulty** | Advanced | -| **Tools used** | [Postman](https://www.postman.com/downloads/) | +| **Tools used** | [Postman](https://www.postman.com/downloads/), [Postman (portable)](https://portapps.io/app/postman-portable/) | | **Topology Nodes** | :material-router: PE1, :material-router: PE2, :material-router: PE3, :material-router: PE4, :material-router: P1, :material-router: P2 | -| **References** | [Nokia Developer Portal](https://network.developer.nokia.com) (Sign up for a free account)
[NSP Postman collections](https://network.developer.nokia.com/static/private/downloads/postmanCollections/24_11_NSP_Postman_Collections.zip)
[Netbox Shell Documentation](https://netboxlabs.com/docs/netbox/en/stable/administration/netbox-shell/) | +| **References** | [Nokia Developer Portal](https://network.developer.nokia.com) (Sign up for a free account)
[NSP Postman collections](https://network.developer.nokia.com/static/private/downloads/postmanCollections/24_11_NSP_Postman_Collections.zip)
[NetBox Shell Documentation](https://netboxlabs.com/docs/netbox/en/stable/administration/netbox-shell/) | ## Objective -Netbox is a Source of Truth platform for recording the target state of your network infrastructure, both physical and logical. NSP is an intent-driven automation platform we'll be using to control the IP network domain, based on the information defined in Netbox. In this activity, you'll create a custom Netbox script to translate Netbox's version of the network state into NSP intents to control device configuration. +Keeping your network inventory and your operational systems in sync is a recurring challenge. You may already maintain device and service records in a central source-of-truth such as NetBox, while your devices are managed and configured through NSP. Without integration, you risk having two versions of the truth: one in your inventory database and another in the live network. + +In this activity, you'll create a custom NetBox script that translates NetBox's version of the network state into NSP intents and pushes them into the live network. This ensures that updates made in your inventory system directly drive configuration changes on the devices. + +This approach helps you: + +* Reduce manual re-entry of configuration data across systems +* Ensure that the inventory view always corresponds to actual device state +* Move toward event-driven operations, where network inventory changes automatically trigger configuration updates + +This is the rough flow chart of the solution we're going to construct, the NetBox custom script is where most of the effort will be focused. -This is the rough flow chart of the solution we're going to construct, the Netbox custom script is where most of the effort will be focused. ``` mermaid flowchart LR - nb(Netbox) --> |Event-Rule| sc(Netbox
Custom Script) - sc -->|Restconf API| nsp(NSP) + nb(NetBox) --> |Event-Rule| sc(NetBox
Custom Script) + sc -->|RESTCONF API| nsp(NSP) nsp --> |gNMI/NETCONF| net(Network) - style sc fill:pink + style sc fill:red ``` -## Prerequisites +## Technology Explanation -- NSP RESTCONF APIs using POSTMAN -- Practical programming experience using python +### NSP Intents +Nokia Network Services Platform (NSP) is a comprehensive network management and automation platform that uses intent-based networking principles to simplify operations. Rather than requiring operators to specify low-level device configurations, NSP allows them to declare high-level business intents that describe desired network behaviors, automatically translating these intents into device configurations and policies while continuously monitoring compliance. -## NetBox +### NetBox DCIM +NetBox is a Source of Truth platform (SoT) for managing network infrastructure state. Its DCIM module documents network devices, racks, cables and interfaces. The platform models physical hardware through devices and network connectivity through `Interfaces`, tracking both physical connections and configurations enabling automation use-cases. -### DCIM -The Data Center Infrastructure Management (DCIM) module in Netbox provides tools for documenting network infrastructure, including devices, racks, and cables. It centers around the Device model for hardware and the Interface model for network ports, allowing operators to track both physical connections and interface configurations in a centralized system. +### NetBox IPAM +The IP Address Management (IPAM) module in NetBox provides tools for managing IP addresses, prefixes, VLANs, and VRFs. A key feature is the `IPAddress` model which represents individual IP addresses and their assignments. IPAddress objects can be directly associated with Interface objects from the DCIM module, creating a clear link between physical ports and their IP addressing. The IPAM module supports both IPv4 and IPv6 addressing, CIDR notation, and can enforce rules around address assignment and utilization. -DCIM's power lies in how it relates these components - Interfaces can be connected to other Interfaces via Cables, Devices can be mounted in Racks at specific positions, and everything can be organized by Site and Location. This creates a complete model of the physical network that serves as a source of truth for automation. The module also includes features for tracking power connections, console ports, and front/rear panel layouts of devices. -For network automation use-cases, the Device and Interface models are particularly valuable as they can be integrated with other systems (like NSP) to drive configuration changes based on the documented physical state in Netbox. +## Tasks + +**You should read these tasks from top-to-bottom before beginning the activity.** -### IPAM -The IP Address Management (IPAM) module in Netbox provides tools for managing IP addresses, prefixes, VLANs, and VRFs. A key feature is the IPAddress model which represents individual IP addresses and their assignments. IPAddress objects can be directly associated with Interface objects from the DCIM module, creating a clear link between physical ports and their IP addressing. This relationship is crucial for network automation as it allows operators to track both the physical connectivity and logical addressing of network devices in one system. The IPAM module supports both IPv4 and IPv6 addressing, CIDR notation, and can enforce rules around address assignment and utilization. When integrated with the Interface model, it provides a complete view of both physical and logical network configurations that can be used as a source of truth for automation platforms. +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -## Accessing Netbox +### Accessing NetBox !!! note - Login to the Netbox UI via the web interface:
+ Login to the NetBox UI via the web interface:
**URL**: http://**GROUP_NUMBER**.srexperts.net:8000
**Username**: admin
- **Password**: same password as the instance SSH or SROS and SRL nodes
- - -## Tasks - -**You should read these tasks from top-to-bottom before beginning the activity.** - -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. + **Password**: same password as the instance SSH or SR OS and SR Linux nodes
-### Explore Netbox -We've already done some work to load the Hackathon topology into Netbox - this includes specifying Manufactures and Device Types, creating Racks, installing Devices into racks with hostnames, Interfaces and connecting devices to one another. +### Explore NetBox +We've already done some work to load the Hackathon topology into NetBox - this includes specifying `Manufacturers` and `Device Types`, creating `Racks`, installing `Devices` into racks, creating `Interfaces` and connecting devices to one another. -#### Explore Core Netbox Components +#### Explore Core NetBox Components * Browse the **Devices** section to see all network equipment * Examine the **Racks** view to understand physical infrastructure layout, use the **Elevations** menu option to view a visual representation of the rack front/rear. * Click into individual devices to view their basic information, browse the **Interfaces** tab to list interfaces and inspect their basic parameters. #### Run the IP Allocation Custom Script -You'll may notice that devices don't have IPs assigned to interface within Netbox. Because each lab environment has unique IP space, we have to dynamically add IP addresses to each Netbox instance. The next instructions will show you an example of how a custom script is run interactively and what they can do. +You may notice that devices don't have IPs assigned to interfaces within NetBox. Because each Hackathon instance VM has unique IP space, we must dynamically add IP addresses to each NetBox instance. The next instructions will show you an example of how a custom script is run interactively and what they can do. -???+ note "Run Netbox IP Assignment Script" +???+ note "Run NetBox IP Assignment Script" * Navigate to `Customization > Scripts > Create IP interfaces on core nodes` * In the `Instance id` field, put in your group number such as `10`. Be sure this is correct, your NSP intents won't work unless this is correct. * Click the `Run Script` button. @@ -100,20 +103,34 @@ Once authenticated, the generated bearer-token will be used for follow-up API ca Be aware, that the token is only valid for a certain period of time. Either one must refresh it once in a while, or reauthenticate when the token has expired. -If you use an older version of POSTMAN, you will find the script in a tab called **Tests**. +If you use an older version of Postman, you will find the script in a tab called **Tests**. /// note -The POSTMAN collection hosted on the developer portal made available by the NSP product-team stores the auth-token under `Globals`. +The Postman collection hosted on the developer portal made available by the NSP product-team stores the auth-token under `Globals`. The script used in this activity stores the token in the environment instead, which allows toggling between different environments without the need to reconnect. /// #### List all network ports -List all network ports using RESTCONF `GET` -`24.11 Network Functions > Network Infrastructure Management > Network Inventory > Get vs Find Restconf API samples> GET getAllPorts` +List all network ports using RESTCONF, browse to the following Postman endpoint: + +- `24.11 Network Functions` + - `Network Infrastructure Management` + - `Network Inventory` + - `Get vs Find Restconf API samples` + - `GET getAllPorts` + ![GetAllPorts Restconf API call](./images/57-netbox/postman-getAllPortsCall.png) #### Search NSP Inventory -Execute the `Filter ethernet ports` Postman example found in `24.11 Network Functions > Network Infrastructure Management > Network Inventory > Get vs Find Restconf API samples> POST Filter ethernet ports`. Because this is using the `nsp-inventory:find` RPC using RESTCONF `POST`, we can pass JSON in the `Body` tab to filter for specific ports. Inspect the **Body** tab and adjust the xpath filter. +Execute the `Filter ethernet ports` Postman example found in: + +- `24.11 Network Functions` + - `Network Infrastructure Management` + - `Network Inventory` + - `Get vs Find Restconf API samples` + - `POST Filter ethernet ports`. + +Because this is using the `nsp-inventory:find` RPC using RESTCONF `POST`, we can pass JSON in the **Body** tab to filter for specific ports. Inspect the **Body** tab and adjust the xpath filter. ``` { @@ -134,7 +151,7 @@ Inspect the results - note the `equipment-extension-port:extension` stanza in th We'll come back to this later. ### Create NSP ICM Templates -We'll now set up some configuration templates we'll later reference in our Netbox script. +We'll now set up some configuration templates we'll later reference in our NetBox script. Head over to the NSP UI and browse to `Device Management > Configuration Intent Types`. #### Check ICM Intent Types @@ -142,62 +159,63 @@ Ensure our required intent-types have been imported into `Device Management`, th * `port-connector_gsros_` - For basic configuration on the physical port (Admin state etc.) * `icm-equipment-port-ethernet` - For Ethernet configuration on the physical port (MTU, LLDP etc.) -* `icm-router-network-interface` - For IP Interfaces added to the "Base" router (IPv4, IPv6 addresses etc.) +* `icm-router-network-interface` - For IP Interfaces added to the SR OS `Base` router (IPv4, IPv6 addresses etc.) ![NSP Intent Types](./images/57-netbox/nsp-intent-types.png) #### Create ICM Templates -We'll now create ICM Templates, these are the blueprints we'll use to create Intent deployments in our Netbox script. +We'll now create ICM Templates, these are the blueprints we'll use to create Intent deployments in our NetBox script. * Using the drop-down next to `Device Management` browse to `Configuration Templates`. -* Create a template called `Group 10 - NSP Activity 57 - Port Connector` using intent-type `port-connector_gsros_`. Click Release. -* Repeat for the other two intent-types: `icm-equipment-port-ethernet` and `icm-router-network-interface` using similar names swapping the "Port Connector" part. +* Create a template called `Group - NSP Activity 57 - Port Connector` using intent-type `port-connector_gsros_`, substitute in your group number. Click Release. +* Repeat for the other two intent-types: `icm-equipment-port-ethernet` and `icm-router-network-interface` using similar names and substituting "Port Connector" for "Port Ethernet" or "Network Interface". This is a name to identify the template which we'll use later when we create intent instances. ![NSP Intent Template](./images/57-netbox/nsp-intent-template.png) #### Create ICM Configuration Deployments Create 3 ICM Configuration Deployments using your templates. -Choose an unused port and do some basic port configuration: +Choose an unused port and do some basic port configuration, unused ports can be determined from the topology diagram provided in the hackathon briefing. | Template | Target | Config | | --- | --- | --- | | Connector Port | NE: `PE1`
Port: `1/1/c10` | Breakout: `c1-100g` | | Ethernet Port | NE: `PE1`
Port: `1/1/c10/1` | *keep defaults* | -| Network Interface | Interface Name: `port_1/1/c10/1` | Port Binding: `port`
Port `1/1/c10/1`
IPv4 Primary Address: `1.6.20.25`
IPv4 Primary Prefix Length: `31` | +| Network Interface | Interface Name: `port_1/1/c10/1` | Port Binding: `port`
Port `1/1/c10/1`
IPv4 Primary Address: `10.6.20.25`
IPv4 Primary Prefix Length: `31` | /// note -We'll use this naming scheme in the deployment script. This is the basic process we'll use via the API for the Netbox script. +We'll use this naming scheme in the deployment script. This is the basic process we'll use via the API for the NetBox script. /// ![NSP ICM Deployments](./images/57-netbox/nsp-icm-deployments.png) -* Re-execute the `Filter Ethernet ports` postman call from the previous step - can you see the `deployments` key? See the details of the deployment listed. This is how you should detect if an existing ICM Deployment already exists for a port. +* Re-execute the `Filter Ethernet ports` Postman call from the previous step - can you see the `deployments` key? See the details of the deployment listed. This is how you should detect if an existing ICM Deployment already exists for a port. -### Create Netbox Event Rule +### Create NetBox Event Rule +NetBox event rules allow for a script to be run when a NetBox object changes, such as being created, updated or deleted. The script receives the object details as an argument. #### View the Dump Data Script -Back in the Netbox UI, browse to `Customization > Scripts` and click on the `Dump Data` script. At the top there are tabs to show the script source and to show the `Jobs` - these are the instances of the script being executed. You can click the ID number of each job execution to view the script output. +Back in the NetBox UI, browse to `Customization > Scripts` and click on the `Dump Data` script. At the top there are tabs to show the script source and to show the `Jobs` - these are the instances of the script being executed. You can click the ID number of each job execution to view the script output. ![NSP Dump Script](./images/57-netbox/nb-dump-script.png) #### Create Dump Data Event Rule -Netbox can create a rule that responds to changes for particular objects and trigger web hooks or script executions. We're going to create a testing rule that runs an existing script called **DumpData** - all this script does is print out the `data` parameter that's passed to the `run()` method of the script when the Event Rule is triggered. +NetBox can create a rule that responds to changes for particular objects and trigger web hooks or script executions. We're going to create a testing rule that runs an existing script called **DumpData** - all this script does is print out the `data` parameter that's passed to the `run()` method of the script when the Event Rule is triggered. * Create an Event Rule under `Operations > Event Rules` with **Action Type** of `Script` set to the existing **DumpData** script. * Note the `Action data` field where you can provide arbitrary JSON that gets included with the `data` parameter, we'll use this later. * You can test this rule by making a change to a device's interface and inspecting the job log: `Operations > Jobs > `. This output is a useful reference when creating your custom script. -![Netbox Event Rule](./images/57-netbox/nb-event-rule.png) +![NetBox Event Rule](./images/57-netbox/nb-event-rule.png) -### Write Netbox Script -Our goal is to have a python script that gets uploaded to Netbox and run whenever an interface object in Netbox is created or changed. Your challenge is to flesh out the skeleton script with all the required functionality to query NSP inventory, determine what action is needed and make calls to the NSP API to create ICM Deployments. You'll want to use Postman as your API reference to find the endpoints you need and what needs to be passed in them. +### Write NetBox Script +Our goal is to have a python script that gets uploaded to NetBox and run whenever an interface object in NetBox is created or changed. Your challenge is to flesh out the skeleton script with all the required functionality to query NSP inventory, determine what action is needed and make calls to the NSP API to create ICM Deployments. You'll want to use Postman as your API reference to find the endpoints you need and what needs to be passed in them. -Netbox scripts should be written in your own development environment or IDE - VSCode is a great starting point. +NetBox scripts should be written in your own development environment or IDE - VSCode is a great starting point. -#### Netbox Script Skeleton -We've provided this skeleton script as a starting point - it provides the basic structure and allows you to run the script interactively (on the terminal) or after being uploaded to Netbox. +#### NetBox Script Skeleton +We've provided this skeleton script as a starting point - it provides the basic structure and allows you to run the script interactively (on the terminal) or after being uploaded to NetBox. For running on the terminal, please ensure you've installed the `requests` pip package. ``` @@ -205,7 +223,7 @@ pip install requests ``` !!! tip - This skeleton script has some custom magic that means it can (mostly) be run outside the Netbox execution environment. This means participants can run the script on their local machine or on the jump host to test the NSP calls. Any calls that use the Netbox models will fail, comment those out and set static values during testing. + This skeleton script has some custom magic that means it can (mostly) be run outside the NetBox execution environment. This means participants can run the script on their local machine or on the jump host to test the NSP calls. Any calls that use the NetBox models will fail, comment those out and set static values during testing. ??? note "skeleton.py" ```python @@ -228,29 +246,29 @@ pip install requests #### Your Turn There are some hints below about how you could structure your script, try your best without referring to this if you can. -??? tip - #### Script format - * The netbox `data` parameter doesn't indicate the action type (create, update, delete) so some logic is required to determine the required action. - * Write a method that can interface with the NSP Inventory API (`Filter ethernet ports`) explored earlier and search for Port/Ethernet/Interface deployments. - * Write a method that can create/update/delete an NSP ICM Deployment given service data parameters and the ICM template name. You'll need to explore the NSP ICM Postman collection to find the best API call to make. - * You'll need to create separate Port, Ethernet and Interface Deployments when the script runs. - * Assemble the final logic in the run() method, pulling the required information from Netbox object queries (interface details like state, MTU, IP address etc.) and pass it to the ICM deployment target_data param. - -You can test your script by running it interactively and pass in the sample_data.json file. As mentioned above, netbox object queries won't work - you'll need to stub those out for static values during testing. Example output from a script execution is shown below: + +#### Script format +* The netbox `data` parameter doesn't indicate the action type (create, update, delete) so some logic is required to determine the required action. +* Write a method that can interface with the NSP Inventory API (`Filter ethernet ports`) explored earlier and search for Port/Ethernet/Interface deployments. +* Write a method that can create/update/delete an NSP ICM Deployment given service data parameters and the ICM template name. You'll need to explore the NSP ICM Postman collection to find the best API call to make. +* You'll need to create separate Port, Ethernet and Interface Deployments when the script runs. +* Assemble the final logic in the run() method, pulling the required information from NetBox object queries (interface details like state, MTU, IP address etc.) and pass it to the ICM deployment `target_data` param. + +You can test your script by running it interactively and pass in the `sample_data.json` file. As mentioned above, netbox object queries won't work - you'll need to stub those out for static values during testing. Example output from a script execution is shown below: ```bash > python3 ./skeleton.py sample_data.json > Authenticated with NSP! Status Code:200 > Querying NSP for Port Deployments... > 1 Port deployment found -> Netbox interface exists, we need to update the NSP ICM Deployment +> NetBox interface exists, we need to update the NSP ICM Deployment > Updating NSP ICM Deployment... > SUCCESS:204 - updated NSP ICM Deployment for Port 1/1/c10. ``` -#### Useful Netbox script snippets -The [Netbox Shell Documentation](https://netboxlabs.com/docs/netbox/en/stable/administration/netbox-shell/) is a good reference for how to query and filter models in Custom scripts. You can also access the API docs directly in Netbox (a good way to see keys on each model) at `/api/`. +#### Useful NetBox script snippets +The [NetBox Shell Documentation](https://netboxlabs.com/docs/netbox/en/stable/administration/netbox-shell/) is a good reference for how to query and filter models in Custom scripts. You can also access the API docs directly in NetBox (a good way to see keys on each model) at `http://GROUP_NUMBER.srexperts.net:8000/api/`. -* Lookup a device's `system` address using the Netbox API. +* Lookup a device's `system` address using the NetBox API. ```python title="Get System Address" i = [i for i in list(IPAddress.objects.filter( @@ -259,7 +277,7 @@ i = [i for i in ][0] ``` -* Retrieve a Netbox interface from the id parameter in the `data` param: +* Retrieve a NetBox interface from the id parameter in the `data` param: ```python title="Get Interface by ID" nb_interface = list(Interface.objects.filter(id=data.get('id'))) ``` @@ -269,18 +287,20 @@ nb_interface = list(Interface.objects.filter(id=data.get('id'))) ip_addresses = list(IPAddress.objects.filter(interface_id=data.get('id'))) ``` -### Deploy to Netbox -Once you have a basic script that can create/update/delete NSP ICM intent deployments based on the sample data, we can setup the Event Rule in Netbox. +### Deploy to NetBox +Once you have a basic script that can create/update/delete NSP ICM intent deployments based on the sample data, we can setup the Event Rule in NetBox. #### Upload Script -First we need to upload your script to Netbox: -* Browse to `Customization > Scripts > Add` and upload your script source. -Now to hook the script up to an event rule. You can either reuse the Event Rule we created earlier, or create a second one which might be better for debugging - when an interface is changed, you'll have a Netbox `Job` output that the script was executed with from the other Event Rule. +First, we need to upload your script to NetBox: + +* Browse to `Customization > Scripts > Add` and upload your script source. +* Associate the script to an `Event Rule`. You can either reuse the Event Rule we created earlier or create a second one which might be better for debugging. +* When an interface is changed, a NetBox `Job` will be created with script execution output, as executed by the Event Rule. #### Create Event Rule -* Browse to `Operations > Event Rules` in Netbox +* Browse to `Operations > Event Rules` in NetBox * Create an event rule that will trigger your script. -* Note the `Action Data` section - provide the following JSON snippet customized with your NSP's login details and host IP. +* Note the `Action data` section - provide the following JSON snippet customized with your NSP's login details and host IP. ```json {"nsp_host":"nsp.srexperts.net","nsp_password":"","nsp_username":">"} @@ -289,17 +309,20 @@ Now to hook the script up to an event rule. You can either reuse the Event Rule ![Final Event Rule](./images/57-netbox/nb-event-rule-final.png) #### Test -Now you can test! Choose a device interface, make a change and test your script. Some example changes: - -* Change the Netbox interface state to "disabled" to ensure a Port Connector ICM deployment disables the interface. -* Change the MTU of a Netbox interface to ensure the Ethernet ICM deployment changes the ethernet MTU. -* Add an IP address to an existing interface and ensure a Network Interface ICM is created. -* Delete an interface that already has ICM Deployments, ensure that all three Deployments are removed from NSP. +Now you can test! Choose a device interface, make a change and test your script. /// note -To access the Netbox interface navigate to `Devices > DEVICE COMPONENTS > Interfaces`. +To browse and edit device interfaces in NetBox, navigate to `Devices > Device Components > Interfaces`. /// +Some example changes: + +* Change the NetBox interface state to "disabled" to ensure a Port Connector ICM deployment disables the interface. +* Change the MTU of a NetBox interface to ensure the Ethernet ICM deployment changes the ethernet MTU. +* Add an IP address to an existing interface and ensure a Network Interface ICM deployment is created. +* Delete an interface that already has ICM deployments, ensure that all three deployments are removed from NSP. + + ### Solution Here is an example solution that can create and update NSP ICM Intents: @@ -307,3 +330,12 @@ Here is an example solution that can create and update NSP ICM Intents: ```python --8<-- "./docs/nsp/advanced/resources/57-netbox/example-solution.py" ``` + +### Summary +If you've made it this far and have even a basic solution, congratulations! + +* You have learnt the basics of the NSP ICM RESTCONF API +* You understand how to create NetBox Event Rules to automate configuration changes +* You can integrate NetBox with NSP ICM to automatically deploy network changes + +We have illustrated the power of integrating network management systems to create automated actions that can speed up network operations, avoiding manual work. There is lots of potential with Nokia NSP to extend these ideas into a limitless number of potential use-cases. \ No newline at end of file diff --git a/docs/nsp/advanced/72-nsp-tldp-to-evpn-migration.md b/docs/nsp/advanced/72-nsp-tldp-to-evpn-migration.md index 3dc2067..3a829c7 100644 --- a/docs/nsp/advanced/72-nsp-tldp-to-evpn-migration.md +++ b/docs/nsp/advanced/72-nsp-tldp-to-evpn-migration.md @@ -6,11 +6,11 @@ tags: - EPIPE --- -# T-LDP to EVPN Migration +# Service Migration from TLDP to EVPN | | | | --- | --- | -| **Activity name** | T-LDP to EVPN Migration | +| **Activity name** |Service Migration from TLDP to EVPN | | **Activity ID** | 72 | | **Short Description** | Converting EPIPE services from Targeted LDP (T-LDP) to Ethernet VPN (EVPN) | | **Difficulty** | Advanced | @@ -18,13 +18,13 @@ tags: | **Topology Nodes** | :material-router: PE1, :material-router: PE2 | | **References** | [NSP Documentation](https://documentation.nokia.com/nsp/24-11/libfiles/landing.html)
[NSP Developer Portal](https://network.developer.nokia.com/learn/24_11/)
[NSP Service Management](https://documentation.nokia.com/nsp/24-11/NSP_Service_Management_Guide/iptitle.html)
[SROS Documentation](https://documentation.nokia.com/sr/24-10/index.html)
[SROS L2 Service and EVPN Advance Configuration Guide](https://documentation.nokia.com/sr/24-10/7750-sr/titles/layer-2-services-evpn.html) | -In this activity, we explore the evolution of L2VPN services—from traditional EPIPE over TLDP to a more scalable, modern alternative: EPIPE over EVPN. +## Objective -We'll begin by revisiting how EPIPE services over TLDP work within the Nokia IP/MPLS ecosystem, then introduce EVPN (Ethernet VPN)—a standards-based -solution gaining widespread adoption for its superior scalability, operational simplification, and flexibility. +Migrating EPIPE services from TLDP to EVPN is not a question of “if” but “how” — especially when you are dealing with thousands of services. Doing this manually is slow, error-prone, and simply not scalable. -But we won’t stop at theory. You'll get your hands dirty in a guided migration exercise, where we use Nokia NSP (Network Services Platform) to -automate the transition of a traditional TLDP-based EPIPE to an EVPN-based EPIPE service. +In this activity, you will explore how NSP can be used to automate the migration of TLDP-based EPIPEs to EVPN-based EPIPEs. Rather than handling every service by hand, you will implement a workflow in NSP that takes care of the complexity and can be extended to meet your operational needs. + +The purpose is not only to complete a migration, but to gain hands-on experience with network automation — experience you can build on to design variations, extend the workflow, and apply the same principles to other large-scale transitions in your network. ## Tasks @@ -1073,9 +1073,7 @@ Let’s dive deeper and **customize the workflow**. #### Challenge: Change the Transport Tunnel from `sr-isis` to `segment routing traffic engineering` -By default, the migration preserves the transport tunnel type defined in the legacy service. In our case, that's **`sr-isis`**—a topology-based label distribution model. -However, **SR-ISIS does not support Traffic Engineering (TE)**, which limits your ability to influence path selection beyond the IGP's shortest path. -To enable **TE capabilities**, we want to update the EVPN service to use **Segment Routing Traffic Engineering (SR-TE)** instead—giving us fine-grained control over how traffic flows across the MPLS core. +By default, the migration preserves the transport tunnel type defined in the legacy service. In our case, that's **`sr-isis`**—a topology-based label distribution model. However, **SR-ISIS does not support Traffic Engineering (TE)**, which limits your ability to influence path selection beyond the IGP's shortest path. To enable **TE capabilities**, we want to update the EVPN service to use **Segment Routing Traffic Engineering (SR-TE)** instead—giving us fine-grained control over how traffic flows across the MPLS core. > **Goal**: Modify the workflow to replace `sr-isis` with `sr-te` in the EVPN transport tunnel selection. @@ -1158,8 +1156,7 @@ This activity gave you a template that applies across many domains. You can take Looking ahead, the same foundational principles can even be extended to **AI-assisted automation**. Imagine using **Model Context Protocol (MCP)**—an emerging framework where **AI models interface directly with network controllers** to interpret high-level service intent, recommend optimizations, or even auto-resolve failures in real time. In such architectures, **AI doesn’t replace the network engineer—it acts as a co-pilot**, helping translate dynamic business needs into actionable, verifiable network changes. -What you’ve built here prepares you not just for today’s migrations—but for tomorrow’s autonomous networks. -What you’ve done here—modeling a service, abstracting its lifecycle, transforming it, and validating the outcome—is repeatable, scalable, and increasingly indispensable. +What you’ve built here prepares you not just for today’s migrations—but for tomorrow’s autonomous networks. What you’ve done here—modeling a service, abstracting its lifecycle, transforming it, and validating the outcome—is repeatable, scalable, and increasingly indispensable. You're no longer simply configuring networks. You're now designing their evolution, shaping their logic, and writing the rules that govern their automation. diff --git a/docs/nsp/advanced/73-nsp-golden-cfg-security.md b/docs/nsp/advanced/73-nsp-golden-cfg-security.md index daed46a..9c068df 100644 --- a/docs/nsp/advanced/73-nsp-golden-cfg-security.md +++ b/docs/nsp/advanced/73-nsp-golden-cfg-security.md @@ -5,11 +5,11 @@ tags: - Device Configuration --- -# Golden Security Configuration +# Security Baseline Configuration | | | | --- | --- | -| **Activity name** | Golden Security Configuration | +| **Activity name** | Security Baseline Configuration | | **Activity ID** | 73 | | **Short Description** | Use intent-based networking principles to implement and assure device-level security configuration for SR OS and SRLinux. | | **Difficulty** | Advanced | @@ -18,14 +18,12 @@ tags: | **References** | [Security Configuration](https://documentation.nokia.com/sr/25-3/7x50-shared/system-management/security-system-management.html#d197e3)
[Developer Portal](https://network.developer.nokia.com) | ## Objective -In this activity, you'll design an abstract intent-type for NSP used to apply node-level security configuration to all your networking devices. -The general approach taken is different from NSP's product intent-types. The intent-type defined uses minimal input to apply security configuration -to a device. The mapping logic is adjustable, so the same intent-type can be used across different router families and even different network -operating systems. -The intent-type boilerplate is provided. You will be expected to make modifications by adding attributes or support for another NOS. -To do this, the idea will be to first become acquainted with the base version of the intent-type, to then modify it for SR OS, make -sure everything behaves as expected and finally to make it work in a similar way for SRLinux. +Security baselines are only effective if they are applied consistently across all devices — and kept that way over time. In practice, differences between platforms and configuration drift often result in small gaps that can quickly become security holes. Manually tracking these differences is error-prone, and updating each device configuration one by one is not sustainable. + +In this activity, you will tackle this challenge using intent-based networking (IBN). By defining an abstract intent-type for node-level security, you can express what should be enforced while NSP ensures how this is realized across different router families and network operating systems. The result is a scalable way to maintain conformance and avoid drift, with one high-level intent applied network wide. + +To get started, a boilerplate custom intent-type for SR OS is provided. You will first install and validate this baseline, then make targeted modifications to extend its functionality. As a final step, you will adapt the same intent-type to support SR Linux, demonstrating how one abstraction can be applied across multiple platforms. ## Tasks @@ -33,10 +31,9 @@ sure everything behaves as expected and finally to make it work in a similar way It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -### Task 0: Install VS Code and NSP Intent Manager extension +### Install VS Code and NSP Intent Manager extension -For this activity, having VS Code with the NSP Intent Manager extension installed is essential. -If you cannot install 3rd party software on your laptop, don't worry you can just use your web-browser and connect to code-server. +For this activity, having VS Code with the NSP Intent Manager extension installed is essential. If you cannot install 3rd party software on your laptop, don't worry you can just use your web-browser and connect to code-server. Installation Steps: @@ -44,27 +41,19 @@ Installation Steps: 2. Install the [vsCode extension for Intent Manager](https://marketplace.visualstudio.com/items?itemName=Nokia.nokia-intent-manager). 3. Configure the vsCode extension to authenticate against the SReXperts NSP at `nsp.srexperts.net` using the credentials (username/password) provided to you. -### Task 1: Create your own Golden Security Config intent-type +### Create your own Golden Security Config intent-type -Add a folder to your VS Code workspace to store intent-types. Open the context-menu for this folder, and select -`Create intent-type`. Provide a unique name like `security-config-group02`, provide the author name and choose -the device security template. Please adjust the name with the group, that has been assigned to you during the -hackathon. A new folder called `security-config-group02_v1` will be created. The folder contains the complete -intent-type, while the context menu has the option to `Upload intent-type` to the connected NSP system. +Add a folder to your VS Code workspace to store intent-types. Open the context-menu for this folder and select `Create intent-type`. Provide a unique name like `security-config-group02`, provide the author's name and choose the device security template. Please adjust the name with the group, that has been assigned to you during the hackathon. A new folder called `security-config-group02_v1` will be created. The folder contains the complete intent-type, while the context menu has the option to `Upload intent-type` to the connected NSP system. -Take yourself some time to study the intent-type folder and file structure and content. The intent-type follows -a decomposed design, minimizing the touch-points to adjust the behavior. In consequence, most of the JavaScript -code-base is static, and must not be changed by the intent developer. +Take yourself some time to study the intent-type folder and file structure and content. The intent-type follows a decomposed design, minimizing the touchpoints to adjust the behavior. In consequence, most of the JavaScript codebase is static and must not be changed by the intent developer. -The most important concept here are mappers, that can be found in `intent-type-resources/mappers`. Those are -templates (using Apache FreeMarker) to translate the intent-model into the device model. +The most important concept here are mappers, that can be found in `intent-type-resources/mappers`. Those are templates (using Apache FreeMarker) to translate the intent-model into the device model. Explore what is contained in the mapper! /// details | Solution type: success -The created intent-type only contains a SR OS mapper, while the mappings are provided using an opinionated -JSON format. Following security rules are applied: +The created intent-type only contains a SR OS mapper, while the mappings are provided using an opinionated JSON format. Following security rules are applied: * Disable telnet and telnet6 server functionality * Disable the on-board FTP server @@ -78,27 +67,21 @@ JSON format. Following security rules are applied: * Create a log 90 that stores logs generated by the MAF (and security in general) /// note -Telnet and FTP configurations we can all agree with, the MAF, clearly, is not very secure. -As this is a containerlab topology, we use these settings to ensure persistent access and -in the hopes of avoiding restarting the topology due to an unfortunate configuration change -that blocks access to the system. +Telnet and FTP configurations we can all agree with, the MAF, clearly, is not very secure. As this is a containerlab topology, we use these settings to ensure persistent access and in the hopes of avoiding restarting the topology due to an unfortunate configuration change that blocks access to the system. /// /// -### Task 2: Create/Deploy intents from WebUI +### Create/Deploy intents from WebUI * Create an intent for PE1, but don't deploy it yet to the network * Run an audit to understand, which configuration would be rolled out * Synchronize the intent to the network and check if the device config was updated * Feel free to modify the device configuration via CLI and run audit/sync operations again -### Task 3: Extend the intent-type with something small -In this task, we explore how to add additional configuration to your intent-type to extend the coverage. -The idea with this type of intent is that model-driven node configuration can be easily reused to populate the intent-type. -This is exactly what we will try to do for model-driven SR OS nodes in this task. +### Extend the intent-type with something small +In this task, we explore how to add additional configuration to your intent-type to extend the coverage. The idea with this type of intent is that model-driven node configuration can be easily reused to populate the intent-type. This is exactly what we will try to do for model-driven SR OS nodes in this task. -Change your intent-type in such a way that it creates an additional entry `50` in the management-access-filter that -explicitly accepts SNMP Traps (UDP 162 as both destination and source port). The resulting configuration in SR OS should be +Change your intent-type in such a way that it creates an additional entry `50` in the management-access-filter that explicitly accepts SNMP Traps (UDP 162 as both destination and source port). /// note | SR OS CLI config ``` @@ -165,14 +148,14 @@ Use CLI commands `pwc model-path` and `info json` to get the snippets to be adde /// After making your changes in the intent-type, trigger an `Audit` of the intent from the WebUI. + What result do you expect? Synchronize either `PE1`, make sure that your changes in the intent-type are propagated correctly and verify the result on the node CLI. -### Task 4: Extend the intent-type with something big +### Extend the intent-type with something big -For the previous task, a simple copy-and-paste of what was already in the intent with minor modifications was all that was needed to get the desired result. -Kudos to you if you used a different approach already. In either case, a different approach will be required for this task. +For the previous task, a simple copy-and-paste of what was already in the intent with minor modifications was all that was needed to get the desired result. Kudos to you if you used a different approach already. In either case, a different approach will be required for this task. The modification required in this task isn't based on existing content of the intent-type, rather requiring entirely new sections to be added to the `SR OS.ftl` file. @@ -218,7 +201,7 @@ Using what you've seen so far, audit and synchronize the intents with your chang Enable the `update-fault-tolerance` configuration in the global BGP context to bring the configuration in line with Nokia's recommendation and once again align the router configuration. -### Task 5: Extend the intent-type for SR Linux +### Extend the intent-type for SR Linux Completing this lab requires a magnum opus of sorts. If you've made it this far that means you are well-versed in SR OS as well as the intent principles we are using here. This intent-type is designed to allow simple onboarding of different NOSes. Having SR Linux available in the topology we would be amiss if we do not add coverage for it to our intent-type. As before, open your intent-type. In line with `SR OS.ftl`, it stands to reason that we will need a similar file for SR Linux. That might be `SRL.ftl` or `SRLinux.ftl` or `SR Linux.ftl`. @@ -275,6 +258,16 @@ system { ``` /// -Use what you've learned and populate `SRLinux.ftl` so this configuration will be applied. The first pointer to take into account here is that the equivalent of `info json` for SR Linux is `info | as json`, and this output modifier can be used in general. The second pointer is that the Model Driven Configurator knows which namespaces (or prefixes) to use, and this information is also freely available [online](https://yang.srlinux.dev/). +Use what you've learned and populate `SRLinux.ftl` so this configuration will be applied. The first pointer is that the equivalent of `info json` for SR Linux is `info | as json`, and this output modifier can be used in general. The second pointer is that the Model Driven Configurator knows which namespaces (or prefixes) to use, and this information is also freely available [online](https://yang.srlinux.dev/). + +Once complete, deploy the intent and confirm the changes are applied successfully. + +## Summary + +Congratulations! You have completed this activity. Take a moment to review what you have achieved: + +* Installed and validated a provided boilerplate intent-type for SR OS. +* Modified the intent-type to enforce node-level security attributes. +* Extended the same construct to also support SR Linux. -Once complete, deploy the intent and confirm the changes are applied successfully. \ No newline at end of file +The result: a reusable, intent-driven approach that enforces consistent configuration across your network, prevents drift, and keeps your security posture aligned with evolving standards. Beyond security, the same concepts and patterns are universally applicable to other configuration areas, helping you simplify operations, maintain conformance, and scale day-to-day network management with confidence. \ No newline at end of file diff --git a/docs/nsp/advanced/images/57-netbox/nb-event-rule-final-old.png b/docs/nsp/advanced/images/57-netbox/nb-event-rule-final-old.png new file mode 100644 index 0000000..cb1b7c1 Binary files /dev/null and b/docs/nsp/advanced/images/57-netbox/nb-event-rule-final-old.png differ diff --git a/docs/nsp/advanced/images/57-netbox/nb-event-rule-final.png b/docs/nsp/advanced/images/57-netbox/nb-event-rule-final.png index cb1b7c1..e6535a5 100644 Binary files a/docs/nsp/advanced/images/57-netbox/nb-event-rule-final.png and b/docs/nsp/advanced/images/57-netbox/nb-event-rule-final.png differ diff --git a/docs/nsp/advanced/resources/57-netbox/example-solution.py b/docs/nsp/advanced/resources/57-netbox/example-solution.py index 0cc3d3c..c3581f6 100644 --- a/docs/nsp/advanced/resources/57-netbox/example-solution.py +++ b/docs/nsp/advanced/resources/57-netbox/example-solution.py @@ -286,7 +286,7 @@ def run(self, data, commit=True): network_action = self.determine_intent_action(bool(nb_interface_exists), bool(network_inventory)) # deployment data - port_mode = "network" # TODO: if len(connected_endpoints) > 0, network, else access + port_mode = "network" # TODO: #303 if len(connected_endpoints) > 0, network, else access port_state = "enable" if data.get("enabled") else "disable" port_mtu = data.get("mtu") diff --git a/docs/nsp/beginner/60-nsp-alarm-ack.md b/docs/nsp/beginner/60-nsp-alarm-ack.md index f83c709..611d1f7 100644 --- a/docs/nsp/beginner/60-nsp-alarm-ack.md +++ b/docs/nsp/beginner/60-nsp-alarm-ack.md @@ -6,27 +6,83 @@ tags: - SchemaForm --- -# Acknowledge alarms using workflows - -| | | -|-----------------------------|-----------------------------------------------------------------------------------------------| -| **Activity name** | Acknowledging specific alarms using workflows | -| **Activity ID** | 60 | -| **Short Description** | In this exercise we will use the Workflow Manager to choose and acknowledge a specific alarm | -| **Difficulty** | Beginner | -| **Tools used** | WFM | -| **Topology Nodes** | | -| **References** | | - -The main purpose of this exercise is to get familiar with NSP WFM ad-hoc actions that can be used as a “suggest” functions -to provide input-forms widgets (pickers, suggest) with data retrieved from NSP. In this particular case we will query -the list of active alarms, while the workflow will acknowledge the corresponding alarm. - -If you consider to do the coding part of this activity, you could also explore the code and eventually apply some modifications. -For improved Developer eXperience, consider using Visual Studio Code with the WFM extension available from -[marketplace](https://marketplace.visualstudio.com/items?itemName=Nokia.nokia-wfm). -Steps to install the VS Code extension can be found on our -[Developer Portal](https://network.developer.nokia.com/tutorials/vscode-extensions/workflow-manager-visual-studio-code-extension). +# Acknowledge Alarms + +| | | +| --- | --- | +| **Activity name** |Acknowledge Alarms | +| **Activity ID** | 60 | +| **Short Description** | Get, Filter, and Acknowledge alarms using Workflow Manager | +| **Difficulty** | Beginner | +| **Tools used** | Workflow Manager (WFM) | +| **Topology Nodes** | all SR OS and SRLinux nodes | +| **References** | [Nokia Developer Portal](https://network.developer.nokia.com) (Sign up for a free account) | + +## Objective + +Network operators often face an overwhelming number of network alarms in their daily work. Manually finding, filtering, and acknowledging alarms can be time-consuming, labor-intense, and error-prone. In this activity, you will use WFM to enable operators to: + +- Retrieve and filter alarms from the network (by severity, alarm-type, or device). +- Present those alarms in a structured input form. +- Acknowledge selected alarms automatically via a workflow. + +The outcome is an operator-focused workflow that reduces manual effort and ensures alarms are handled consistently. The technologies used enable DevOps teams to build more advanced automation use-cases like rule-based, programmatic self-healing. + +## Technology Explanation + +### Workflow Manager +WFM enables operators to automate repetitive or error-prone tasks. Instead of performing manual actions separately, WFM lets you chain API calls into a single, reusable process. In this exercise, WFM is used to: + +- Call RESTCONF APIs to fetch alarms. +- Apply filters so operators can focus on the alarms most relevant to them. +- Wrap actions into re-usable building blocks (ad-hoc actions). +- Acknowledge alarms directly from a form-driven workflow. + +By leveraging WFM, organizations can increase efficiency, improve reliability, and accelerate service delivery and assurance by automating complex, multi-step network tasks. This bridges the gap between raw APIs and operator-friendly network automation. + +### REST and RESTCONF + +**REST** is a widely adopted standard for programmatically interacting with NSP using common HTTP methods such as GET, POST, PATCH, and DELETE. + +**RESTCONF** extends this model by providing a consistent framework for exposing network management data and operations. It builds on REST principles while adding: + +* A standardized way to perform **CRUDL** (Create, Read, Update, Delete, List). +* Support for executing **operations** beyond basic data access. +* A data model based on **YANG**, the industry-standard modeling language for network management. + +Within NSP, RESTCONF gives operators a unified, programmable API surface for both data retrieval and operational control—making automation workflows more reliable, scalable, and future-proof. In this activity, RESTCONF APIs serve as the building blocks, while WFM orchestrates them into a repeatable operator workflow. + +### Visual Studio Code + +While workflows can be designed directly in the NSP WebUI, many operators and developers prefer a full-featured editor for more advanced editing, testing, and version control. + +We recommend using [Visual Studio Code with the WFM extension](https://network.developer.nokia.com/tutorials/vscode-extensions/workflow-manager-visual-studio-code-extension), available from [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=Nokia.nokia-wfm). + +With Visual Studio Code, you gain: + +* Syntax highlighting and validation for workflow YAML. +* Seamless integration with source control (e.g., Git). +* Faster iteration and testing through built-in connectivity to NSP. +* An enhanced developer experience for building, debugging, and sharing workflows. + +### YAQL (Yet Another Query Language) + +[YAQL](https://yaql.readthedocs.io/en/latest) is a flexible query language designed to extract and transform data from structured inputs. In the context of WFM, YAQL expressions are used to filter and reshape API responses so that workflows can consume only the relevant data. + +The Yaqluator is an interactive tool integrated into the WFM WebUI. It enables developers to quickly prototype and test YAQL expressions against real API responses before embedding them into workflows. This helps ensure that data is properly filtered and formatted without repeated trial-and-error inside a running workflow. + +### Ad-hoc Actions + +Ad-hoc actions are user-defined wrappers written in YAML around existing system-actions coded in Python. They act like templates, allowing you to preset frequently used input attributes and reuse them across multiple workflows. This avoids repeating the same or similar definitions, while still relying on the underlying system-action for execution. + +In practice, an ad-hoc action: + +* References a base system-action (coded in Python). +* Defines a set of default inputs (base-input) that are automatically applied whenever the action is used. +* Optionally declares parameters (input) that workflows must supply at runtime. +* Optionally defines how the output should be shaped. + +This makes them especially useful for recurring patterns, such as standard notification emails, device configuration operations, or pre-validated API calls. ## Tasks @@ -40,88 +96,115 @@ Open NSP WebUI and open `Workflows` found under the `PROGRAMMING` category. Select `Actions` view. -On the left hand side we have two types of actions: “Ad-Hoc Actions” and "System Actions". +On the left side, we have two types of actions: `Ad-hoc Actions` and `System Actions`. Let’s start by getting a list of all major alarms on the network: -* Navigate to the “Systems Actions” and search for the “nsp.https” action. -* Click on the 3 dots on the right side and choose “Run” -* Search for the restconf based Alarms API in the [Developer Portal](https://network.developer.nokia.com/api-documentation/) -* You can also find a lot of examples in [this postman collection](https://documenter.getpostman.com/view/26248101/2sAY4uCNvf#de0ea146-e51a-455a-84c5-19f438712103) -* Use it to retrieve a list of all major alarms in NSP +* Navigate to the `Systems Actions` and search for the `nsp.https` action. +* Click on the 3 dots on the right side and choose `Run`. +* Explore the RESTCONF Alarms API in [Developer Portal](https://network.developer.nokia.com/api-documentation) including the corresponding [Postman collection](https://documenter.getpostman.com/view/26248101/2sAY4uCNvf#de0ea146-e51a-455a-84c5-19f438712103) to find API endpoints to query and acknowledge alarms. +* Retrieve a list of all major alarms in NSP using RESTCONF by running the `nsp.https` action from WFM WebUI. -/// details | This is url if you get stuck | - type: tip -url: https://restconf-gateway/restconf/operations/nsp-inventory:find -/// +If you got stuck, find the `nsp.https` action input below to retrieve the list of all major alarms. +/// details | Possible Solution + type: success ```yaml -url: +url: https://restconf-gateway/restconf/operations/nsp-inventory:find method: POST body: input: xpath-filter: /nsp-fault:alarms/alarm-list/alarm[perceived-severity = 'major'] include-meta: false ``` +/// -Try to adjust the filter, for example by picking different severity levels like critical, minor, or warning. +Adjust the filter, for example by picking different severity levels like `critical`, `minor`, or `warning`. +Review the JSON response returned. Try to filter by other alarm attributes, such as alarm-type. -### Yaqulator +/// details | Possible Solution + type: success +Update the `xpath-filter` to match your selection criteria. If you are filtering by `alarm-type-id` or `alarm-type-qualifier`, use the output from your initial query to ensure that the values correspond to existing entries. + +```yaml +url: https://restconf-gateway/restconf/operations/nsp-inventory:find +method: POST +body: + input: + xpath-filter: >- + /nsp-fault:alarms/alarm-list/alarm[alarm-type-qualifier = 'PeerConnectionDown'] + include-meta: false +``` +/// -Copy the received response and navigate to the “Yaqulator” in the upper right corner of the Actions page. -The Yaqulator functionality allows developers to quickly prototype YAQL expressions based on the received response. +### Process Alarm API Response -Paste the response on the bottom left side YAML/JSON Context section +Copy the received response and navigate to the `Yaqluator` in the upper right corner of the Actions page. The Yaqluator functionality allows you to quickly prototype YAQL expressions based on the received response. Paste the response on the bottom left side YAML/JSON Context section. -In the upper YAQL Expression section use the following filter expression to get the list of alarm names: +In the upper YAQL Expression section use the following filter expression to get the list of alarm-names: ```yaml $.result.content.get('nsp-inventory:output').data.select($.get('alarm-type-qualifier')) ``` -Do the same exercise to filter for “fdn”, “alarmTypes” & “neId” +Try to filter for other attributes like `alarm-fdn`, `alarm-type-id`, and `ne-id`. + +### Create the Workflow + +Navigate to the [Developer Portal](https://network.developer.nokia.com/api-documentation/) and search for the RESTCONF call that acknowledges an alarm based on a specific Full Distinguished Name (FDN), which uniquely identifies an alarm. + +/// details | Example output + type: success +The NSP Postman collection "Fault Management RESTCONF API" recommends using a PATCH request on `https://{{server}}:8545/restconf/data/nsp-fault:alarms/acknowledgement={{alarmFdn}}` to acknowledge an alarm. +In your workflow, instead of using the external NSP IP (and port 443 or 8545), you can directly access the RESTCONF gateway. With this, the URL becomes `https://restconf-gateway/restconf/data/nsp-fault:alarms/acknowledgement={{alarmFdn}}`. + +/// + +Create a workflow that uses this API to acknowledge an alarm. + +/// warning +Don't forget to use a unique name for your workflows, e.g. by adding your group number! +/// -### Create Ad-Hoc Action +Workflow Manager uses OpenStack Mistral as engine for workflow execution. To write a new workflow, the following resource might be helpful to you: -Next, navigate back to the ad-hoc Actions and create a new action using the button in the upper right corner. -Paste in the below snippet while substituting the action name with a unique name for the Alram list action +* NSP Developer Portal: https://network.developer.nokia.com/learn/25_4/programming/workflows/wfm-workflow-development/ +* OpenStack Mistral: https://docs.openstack.org/mistral/ocata/dsl/dsl_v2.html#workflows + +Here a simple workflow boilerplate, you can start with: ```yaml +--- version: '2.0' -< UNIQUE-ACTION-NAME>: - base: nsp.https - base-input: - url: - method: POST - body: - input: - xpath-filter: /nsp-fault:alarms/alarm-list/alarm[perceived-severity = 'major'] - include-meta: false - resultFilter: $.content.get('nsp-inventory:output').data.select({alarmName=>$.get('alarm-type-qualifier'),fdn=>$.get('alarm-fdn'),alarmType=>$.get('alarm-type-id'), neId=>$.get('ne-id')} ) - auth: <% $.token_auth %> +workflowname: + type: direct + + description: brief description for the workflow + input: - - token_auth - - formValues: {} - output: <% $.content %> + - varname1: "default-value" + - varname2: 100 + - varname3: true + - varname4: [] + + output: + result: "success" + + tasks: + task1: + action: std.noop +... ``` -“Validate” then “Create”, then try it out by choosing “Run” in the 3 dots button on the action you just created. -You should get a response of a list of major alarms while filtering the response for alarmName, fdn, alarmType and neId. +Adjust workflow name, description, inputs and tasks as needed. You may start by just providing a single `alarmFdn` as input. The workflow itself, could be a single task that is running action `nsp.https` with the corresponding inputs, e.g. `method`, `url`, and `body`. -### Create the Workflow +As a next step check the Mistral documentation for the [`with-items`](https://docs.openstack.org/mistral/ocata/dsl/dsl_v2.html#processing-collections) attribute, to process collections. While the update is rather small, your workflow is now able to acknowledge a list of alarms. -To test the newly created action, create a new workflow that acknowledges an alarm selected by a user. -First navigate to [Developer Portal](https://network.developer.nokia.com/api-documentation/) and search for the RESTCONF call that acknowledges an alarm based on a specific FDN. +If you got stuck, the workflow below provides one way of solving this. -/// details | This is url if you get stuck | +/// details | Possible Solution type: success -url: https://restconf-gateway/restconf/data/nsp-fault:alarms/acknowledgement=<% $.alarm.fdn %> -/// - -Then create a workflow that uses this API call to acknowledge an alarm. -Don't forget to use a unique name for the newly created Workflow, as well as adding the appropriate API call in the url section. - ```yaml version: '2.0' @@ -143,19 +226,56 @@ version: '2.0' safe-rerun: true input: method: PATCH - url: + url: https://restconf-gateway/restconf/data/nsp-fault:alarms/acknowledgement=<% $.alarm.fdn %> body: nsp-fault:alarms: [{}] publish: output: <% task().result %> ``` +/// -Validate, Create then Publish the Workflow +This workflow can be difficult to run as it requires a list of objects as input, and each object must include an attribute called `fdn`. To make execution easier, we will create a user-friendly input form that allows selecting from currently active alarms. -### Create Input Form +### Add a Workflow Input Form -Create a user input form by navigating to “Input Form” in the Workflow’s drop down menu -Paste the following JSON based schemaForm while substituting the suggestFunction with your unique AD-Hoc action name: +To provide a user-friendly input form with alarm pickers, you first need to create an ad-hoc action. This action enables the picker component to query the backend for live alarm data. + +#### Create An Ad-hoc Action + +* Go to Ad-hoc Actions. +* Create a new action using the + button (upper right corner). +* Paste in the snippet below and replace `` with a unique name. + +```yaml +version: '2.0' + +: + base: nsp.https + base-input: + url: https://restconf-gateway/restconf/operations/nsp-inventory:find + method: POST + body: + input: + xpath-filter: /nsp-fault:alarms/alarm-list/alarm[perceived-severity = 'major'] + include-meta: false + resultFilter: $.content.get('nsp-inventory:output').data.select({alarmName=>$.get('alarm-type-qualifier'),fdn=>$.get('alarm-fdn'),alarmType=>$.get('alarm-type-id'), neId=>$.get('ne-id')} ) + auth: <% $.token_auth %> + input: + - token_auth + - formValues: {} + output: <% $.content %> +``` + +From the NSP WFM WebUI tryout your new ad-hoc action after creation. + +You should now see a filtered list including `alarmName`, `fdn`, `alarmType`, and `neId`. The `fdn` is required to acknowledge alarms via API. + +#### Add the schema-form definition + +Next, define a user-input form for alarm selection: + +* In your workflow, open the drop-down menu and select `Input Form`. +* Paste the schemaForm definition (JSON) below, replacing `` with the ad-hoc action name you just created. ```json { @@ -171,7 +291,7 @@ Paste the following JSON based schemaForm while substituting the suggestFunction "required": false, "type": "list", "suggest": { - "action": "< UNIQUE-ACTION-NAME>" + "action": "" }, "component": { "input": "picker" @@ -208,6 +328,17 @@ Paste the following JSON based schemaForm while substituting the suggestFunction } ``` -### Execute +### Run your workflow + +Run your workflow by selecting the alarms that require acknowledgment. Then, verify in the NSP WebUI that the selected alarms have been acknowledged successfully. + +## Summary + +Congratulations! You have completed this activity and tackled the real operator problem of too many alarms, and too much manual effort to process them. With WFM, you have: + +* Queried alarms via RESTCONF APIs. +* Applied filters to make alarm lists meaningful. +* Wrapped API calls into reusable `Ad-hoc Actions`. +* Created a workflow with operator-friendly input form that let users acknowledge alarms directly. -Execute your Workflow by choosing the alarms on the list that require acknowledgment. +The result: a repeatable, operator-friendly workflow that saves time, reduces errors, and ensures consistent handling of alarms. \ No newline at end of file diff --git a/docs/nsp/beginner/68-indicator-analytics.md b/docs/nsp/beginner/68-indicator-analytics.md index d46ff72..cd4dcc4 100644 --- a/docs/nsp/beginner/68-indicator-analytics.md +++ b/docs/nsp/beginner/68-indicator-analytics.md @@ -2,8 +2,10 @@ tags: - NSP - MD-CLI + - Analytics - Telemetry - Kafka + - Workflow Manager --- # Indicators Analytics @@ -12,21 +14,43 @@ tags: | --- | --- | | **Activity name** | Indicators Analytics | | **Activity ID** | 68 | -| **Short Description** | Explore NSP UI on creating Threshold Crossing Alarms (TCA) using NSP CN Telemetry | +| **Short Description** | Visualize nodal CPU usage, add thresholds, and trigger workflow-based automation | | **Difficulty** | Beginner | -| **Tools used** | | -| **Topology Nodes** | all SR OS and SRLinux nodes | -| **References** | | +| **Tools used** | NSP | +| **Topology Nodes** | :material-router: PE1, :material-router: leaf11 | +| **References** | [NSP CN Telemetry Concepts](https://network.developer.nokia.com/learn/24_11/network-functions/data-collection-and-analysis/telemetry/telemetry-collection/cn-telemetry) | ## Objective -Explore NSP Data Collection App to create TCA on CPU usage and visualize the threshold crossing in NSP Data Collection Viewer. +As a network operator managing a large-scale infrastructure, one of your biggest challenges is detecting hidden resource pressure early—before it escalates into service impact. For example, CPU overload on a network node might begin with subtle spikes triggered by OAM stress, constant routing updates from a flapping link, or aggressive telemetry polling. Without early detection, these small disturbances can accumulate into routing instability, degraded performance, or even outages. Identifying such issues early is critical, yet raw telemetry alone often makes it difficult to distinguish normal fluctuations from real problems. -## Technology explanation +In this activity, you will use Indicator Analytics to turn raw telemetry into actionable insights. An indicator is a subscription to a customized metric that allows you to define and monitor KPIs using telemetry data, arithmetic operators, and aggregation functions. You will create an indicator for CPU usage monitoring, set a static threshold, and configure Threshold Crossing Alerts to trigger when limits are exceeded. You will then observe these alerts flowing into Kafka, where they can be tied to programmable workflows, and visualize the collected data in the Data Collection Viewer. -### Model-driven XPATH +By the end, you will see how Indicator Analytics enables you to: -When navigating the NE CLI paths, for SR OS `pwc json-instance-path` gives you the working context for defining the telemetry subscription object filter. +* Detect anomalies in near real time. +* Take proactive action before performance degrades. +* Build a foundation for closed-loop network automation through workflows. + +## Technology Explanation + +NSP’s cloud-native telemetry solution leverages gNMI and YANG models to stream real-time metrics from the network. The telemetry data is collected and processed by the Analytics framework, where it can be enriched, aggregated, and evaluated against thresholds. When raising conditions are met, Threshold Crossing Alerts are generated and published into Kafka to drive network automation or consumption by external systems. + +### Model XPATH + +Telemetry subscriptions use path expressions to select specific objects in the YANG tree to be monitored. This allows operators to focus on the exact objects and metrics of interest. The SR OS MD-CLI command `pwc json-instance-path` helps you determine the correct path for a given CLI context. + +### Kafka + +Apache Kafka acts as messaging system for NSP notifications. Once generated, TCAs are published to Kafka topics, enabling scalable event delivery to downstream consumers. Topic names such as `nsp-act-action-event` are used to route the alerts. + +### NE-ID + +The NE-ID is a unique identifier for network elements managed by NSP. It typically matches the system loopback IP-address. + +### Threshold Crossing Alerts (TCA) + +Threshold Crossing Alerts are a mechanism to detect when metrics exceed a defined threshold and optionally trigger actions. ## Tasks @@ -34,95 +58,235 @@ When navigating the NE CLI paths, for SR OS `pwc json-instance-path` gives you t It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -### Navigate into Indicators UI from the Data Collection App +### Create a new Indicator -Once you have logged into NSP, navigate into Indicators from the Data Collection App. +Login to NSP WebUI and navigate to `Data Collection and Analysis Management` and then `Indicators`. -/// details | Indicators UI +/// details | Lauch Indicator Analytics WebUI + type: success ![indicator-nav](./images/68-indicators/indicator-ui.png) /// -### Create an NSP Indicator +To create a new indicator on your `pe1` node, click on `+ INDICATOR` on the top right of your screen. +Use the following information to fill in the required form: + +```yaml +General: + Name: cpu-tca-g1-pe1 (update to match your group) + Collection Interval: 30 secs + Window Duration: 15 min +Configuration: + Telemetry Type: telemetry:/base/system-info/system + Selected Counters: cpu-usage + Object Filter: /nsp-equipment:network/network-element[ne-name='g1-pe1'] (update to match your group) +Thresholds: + Threshold: 15 (update based on what is considered normal) + Direction: Increasing + Actions: + Action: Kafka + Topic Name: nsp-act-action-event + Content: CPU usage crossed +``` + +Click `CREATE` to add and activate the indicator. + +/// details | Help (if getting stuck) + type: success +* The indicator subscription is specific to an individual network element. +* Update `Indicator Name` and `Object Filter` to match your group +* Set the `Threshold Value` based on the current resource consumption of your NE by running `Verify Resources`. Note that this check may take some time to complete. +* Click `SAVE` to confirm and store the `Threshold Settings`. + +/// tab | Create Indicator +![create-indicator](./images/68-indicators/create-indicator.png) +/// +/// tab | Create Threshold +![create-threshold](./images/68-indicators/create-threshold.png) +/// +/// + +### Trigger a Threshold Event + +One way to increase CPU usage is to run **rapid pings** between two nodes. Both the node sending pings and the node responding will experience higher CPU load. You may also use any other method that reliably increases CPU usage. + +/// details | Rapid Ping Hint + type: success +You can generate CPU load directly from the SR OS CLI using the command below to run rapid pings. Make sure to adjust the target IP address as needed. The actual CPU impact depends on the test parameters provided (count, interval, size). + +The example below runs a ping test from pe1 to p1, lasting about 60 seconds and using an interface IP address as the destination. Since interface addresses are identical across all groups, you can simply copy and paste the command on your system to quickly generate additional CPU load through rapid pings. + +``` +[/] +A:admin@g1-pe1# ping 10.64.11.0 router-instance Base count 6000 interval 0.01 size 1400 output-format summary +PING 10.64.11.0 1400 data bytes +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +---- 10.64.11.0 PING Statistics ---- +6000 packets transmitted, 6000 packets received, 0.00% packet loss +round-trip min = 1.56ms, avg = 4.64ms, max = 60.7ms, stddev = 4.10ms +``` +/// + +### Visualize your Indicator + +Now that your telemetry stream and thresholds are active, follow these steps: -1. Name: cpu-tca-[grpId] -2. Collection Interval: `30 secs` -3. Window Duration: `15 mins` -4. Telemetry Type: `telemetry:/base/system-info/system` -5. Selected Counters: `cpu-usage` -6. Object Filter: `/nsp-equipment:network/network-element[ne-id='<>']` -7. Threshold: - 1. Threshold: `2` - 2. Direction: `Increasing` - 3. Actions: - - Topic Name: `nsp-act-action-event` - - Content: `CPU Usage crossed 2` - 4. Click Save +* Open `Data Collection and Analysis Visualizations` +* Select your resource(s) +* `PLOT` your resource(s) /// note +The Indicator Visualization can directly be opened from Indicator Management. Check the context menu (3 dots) of the Indicator entry you've created. -The indicator subscription is specific to an individual network element. -Please select an `ne-id` that belongs to the network elements of your group. +The threshold will be shown as a red line on the graph. /// -/// details | Sample Indicator Definition +/// details | Step-by-Step (if getting stuck) type: success -![indicator-subscription](./images/68-indicators/indicator-subscription.png) +/// tab | 01 Navigation +![VisualizeStep1](./images/68-indicators/visualize1.png) +/// +/// tab | 02 Resource Selection +![VisualizeStep2](./images/68-indicators/visualize2.png) +/// +/// tab | 03 Plot Config +![VisualizeStep3](./images/68-indicators/visualize3.png) +/// +/// tab | 04 Output Graph +![VisualizeStep4](./images/68-indicators/visualize4.png) +/// /// -### Increasing CPU Usage +Once the threshold is crossed, a Kafka message is published. + +/// details | Kafka Message Example +```json +{ + "ietf-restconf:notification": { + "nsp-act:action-event": { + "type": "Threshold-Crossing", + "rule": "ind_threshold_6f4bda9e_3f04_4a46_ae44_79b5fdf6cd07", + "process": "cpu-tca-pe1-grp1_15_increasing", + "source": { + "neName": "fd00:fde8::1:21", + "name": "cpu-tca-pe1-grp1", + "neId": "fd00:fde8::1:21", + "networkDeviceId": "/network-device-mgr:network-devices/network-device[name='fd00:fde8::1:21']/root/nokia-state:state/system/cpu[sample-period='1']", + "eventTime": "2025-08-21T22:08:06Z" + }, + "payload": { + "thresholdName": "cpu-tca-pe1-grp1_15_increasing", + "direction": "RISING", + "threshold": "15", + "value": "20.1500" + }, + "content": "CPU usage crossed", + "timestamp": "2025-08-21T22:08:08.869Z" + }, + "eventTime": "2025-08-21T22:08:08.869Z" + } +} +``` +/// -One possible means of increasing the CPU usage is by performing a rapid-ping to the node or a config push. -This isn't the only way to increase CPU usage. If you have a method that works, feel free to perform it. +By consuming those Kafka notifications, we can implement closed-loop automation using workflows, which will be explored next. -Now that we have increased the CPU usage, lets see how to visualize the Telemetry Collection. +### Create a workflow to consume the Kafka event -### Visualize Telemetry Collection +To visualize the Kafka event, lets create a simple workflow that gets executed when the target Kafka event gets created. First open the Workflow Manager WebUI by clicking on `Workflows` under section `PROGRAMMING` in the Hamburger Menu. Now list the `Workflows` in the drop-down menu. Click on `+ WORKFLOW` to create the new workflow: -In order to visualize the collection, there are a few stages of definition to reach it. +/// details | Help (if getting stuck) + type: success +/// tab | Open Workflow Manager +![wfm1](./images/68-indicators/wfm1.png) +/// +/// tab | Create a new Workflow +![wfm2](./images/68-indicators/wfm2.png) +/// +/// tab | Workflow Definition +```yaml +version: '2.0' + +tca-kafka-: + description: Test WF trigger of TCA Kafka Event + + tags: + - KafkaTrigger + + input: + - token + - payload + + tasks: + task1: + action: std.noop + publish: + result: <% $.payload %> +``` +/// -1. Initiate the Viewer -2. Select the resource to visualize the collection -3. Define additional plotter configs like time range -4. Plotter is initialised +* The tag `KafkaTrigger` in the workflow definition is mandatory to associate it with Kafka events. +* Workflows associated to a Kafka event must have `token` and `payload` as inputs in its definition. +* Replace `Group-Id` with your assigned group. This is required to make the workflow name unique. For example, if you are in group 17, use `tca-kafka-17` +* Before you save the new workflow, you first must click on `VALIDATE & UPDATE FLOW`. Once if is successfully validated, you can click on `CREATE` to save it. +* New workflows are created in status `Draft`. To execute the workflow it must be set to `Published` first. +/// -/// note +### Associate Kafka events to your Workflow -The threshold is displayed as a red line on the Plotter to visualize the configured limit. -Keep in mind that a threshold alert will only be triggered on the first increase after the threshold is set. -If the most recent value was already above the threshold at the time of configuration, this will not trigger an alert. -/// +In the Workflow Manager WebUI navigate to `Kafka Triggers`. + +To create a new association, click on `+ KAFKA TRIGGER` on the top right of your screen. +Use the following information to fill in the required forms: + +```yaml +Workflow: tca-kafka- (unchanged) +Edit Format: FORM (unchanged) +Kafka Topic: nsp-act-action-event +Trigger Name: match-on-cpu-tca-pe1-grp1 (update to match your group) +Trigger Rule: $[?( @.data['ietf-restconf:notification']['nsp-act:action-event'].source.name == 'cpu-tca-pe1-grp1' )] (update to match your group) +Kafka Event: JSON +Enabled: True +Limit per Minute: 10 (unchanged) +``` -/// tab | 01 Telemetry Viewer Navigation -![visualisation-nav](./images/68-indicators/visualisation-nav.png) +/// note +- Trigger Rule syntax is based on [JsonPath](https://github.com/json-path/JsonPath). +- Replace `Group-Id` with your assigned group. This his needed to make the trigger name unique. For example, if you are in group 17, use `match-on-neId-17`. It's also required to reference the workflow you've created in the previous step, like `tca-kafka-17` in case of group 17. +- Replace `NE-ID` with the system loopback IP-address of the target network element to be monitored. /// -/// tab | 02 Resource Selection to Plot -![resource-selection](./images/68-indicators/resource-selection.png) + +### Validate Automated Workflow Execution + +When a trigger rule matches an event, the `Times Matched` and `Times Executed` columns are updated automatically. After execution completes, you can navigate to the Workflow Execution page to view the output. + +/// tab | Check Kafka Trigger +![trigger](./images/68-indicators/trigger.png) /// -/// tab | 03 Define Plotter Config -![plotter-config](./images/68-indicators/plotter-config.png) +/// tab | Execution +![executions1](./images/68-indicators/executions1.png) /// -/// tab | 04 Plotter View -![plotter-view](./images/68-indicators/plotter-view.png) +/// tab | Execution Details +![executions2](./images/68-indicators/executions2.png) /// -### nsp-act-action-event Notification +## Summary -If you are looking to visualize how a Kafka JSON notification would look like, below shows a sample message. +Congratulations! You have completed this activity. Take a moment to review what you have achieved: -/// details | Sample Kafka Notification - type: success -![nsp-act-action-event](./images/68-indicators/nsp-act-action-event.png) -/// +* Configure Threshold Crossing Alerts (TCA) on system metrics. +* Create model-driven telemetry subscriptions using gNMI and YANG paths. +* Apply object filters to target specific network elements. +* Trigger Kafka-based actions on threshold events. +* Visualize telemetry time series to observe performance trends. -## Summary and review +While the configuration may seem straightforward, this activity covered the essential telemetry workflow to collect, sense, and act on real-time network data. These are foundational capabilities for building robust observability pipelines. -Congratulations! If you have got this far you have completed this activity and achieved the following: +--- -- You have learnt how to create Threshold crossing alerts -- You have learnt how to create Telemetry subscriptions -- You have learnt to build object filters -- You have learnt on possible actions that can be taken once a threshold is crossed +## Next steps -This sure is an achievement! Well done! +Here are some suggestions on how to continue: -If you're hungry for more feel free to explore the same activity for an SRL node. +* Run the [Baseline Analytics](../beginner/69-nsp-baseline-analytics.md) activity and understand the differences between Indicators and Baselines. +* Extend monitoring beyond CPU to include interface, memory, or protocol KPIs. +* Explore workflows for closed-loop automation using telemetry triggers. \ No newline at end of file diff --git a/docs/nsp/beginner/69-nsp-baseline-analytics.md b/docs/nsp/beginner/69-nsp-baseline-analytics.md index 3ed4727..70fa765 100644 --- a/docs/nsp/beginner/69-nsp-baseline-analytics.md +++ b/docs/nsp/beginner/69-nsp-baseline-analytics.md @@ -1,8 +1,9 @@ --- tags: - NSP - - Baseline + - MD-CLI - Analytics + - Telemetry --- # Baseline Analytics @@ -11,78 +12,64 @@ tags: | --- | --- | | **Activity name** | Baseline Analytics | | **Activity ID** | 69 | -| **Short Description** | Detect anomalies through training and providing a baseline | +| **Short Description** | Anomaly detection using historical telemetry data and Z-Score analysis | | **Difficulty** | Beginner | -| **Tools used** | | -| **Topology Nodes** | :material-router: PE3 | -| **References** | [NSP baseline](https://documentation.nokia.com/nsp/24-11/NSP_Data_Collection_and_Analysis_Guide/dca_baselines.html) | +| **Tools used** | NSP | +| **Topology Nodes** | :material-router: pe1, :material-router: agg1 | +| **References** | [NSP Baseline Analytics](https://documentation.nokia.com/nsp/24-8/NSP_Data_Collection_and_Analysis_Guide/dca_baselines.html) | -This guided activity walks you through detecting port flaps using telemetry data and statistical anomaly detection techniques. -The workflow collects port telemetry from routers, applies Z-score-based anomaly detection after training a baseline. +## Objective -## Prerequisites +In large networks, operators must keep critical device and service metrics under control — such as link utilization, memory usage, or temperature. The challenge is that these metrics rarely stay constant: -- Basic understanding of NSP -- Understanding on time-series data and statistical algorithm -- Knowing the common models in NSP and filter can be used on these model to query the appropriate router resource. +* Traffic naturally peaks during business hours and drops at night. +* CPU or memory load may vary with planned maintenance windows. +* Temperature follows device, environmental and seasonal patterns. -## Key Learnings +Traditionally, operators define static thresholds (e.g., CPU > 80%, link utilization > 70%). But static thresholds don’t reflect real behavior. They are often too strict (raising false alarms every Monday morning when traffic ramps up) or too loose (missing actual anomalies). -By the end of this activity, you'll be able to create and train a baseline for anamoly detection. +The alternative — manually adjusting thresholds for every device, per metric, per time-of-day or day-of-week — is not scalable. It requires constant human monitoring, is prone to error, and becomes unmanageable at scale when networks contain thousands of nodes. -## Terminology +Baseline Analytics solves this problem. By automatically learning normal patterns from historical telemetry, NSP builds dynamic, seasonal baselines. These baselines adapt to daily or weekly variations and automatically adjust thresholds without manual intervention. Operators are then alerted only when behavior truly deviates from the norm — e.g., if traffic stays unusually high late at night, or if a router’s temperature spikes outside its usual profile. -**Baseline Training and Z-score Detection** +In this activity you will take some initial steps into the world of Baseline Analytics with NSP. -Train on historical port status data to establish a statistical norm. -Use Z-score to flag deviations beyond a defined threshold, indicating a flap event. +## Technology Explanation -**Statistical Terminology** +### Baseline Training with Dynamic Updates +NSP looks at historical telemetry to learn what normal looks like for each metric. For example, it can learn that interface utilization is always high on Monday mornings but drops on weekends. This means thresholds do not need to be manually adjusted. -Understand how statistical algorithm are used for anomaly detection +Baselines are not static. As new telemetry is collected, NSP updates the baseline so that it stays aligned with current trends. This prevents outdated thresholds from generating false alarms. -## High-level Data Flow +### Windowing +Once you create a baseline, statistics for a selected resource (or group of resources) are collected over a defined time window. Data is typically gathered at shorter collection intervals, but all values collected within the window are aggregated into a single data point for the baseline. Each window then has its own expected value based on historical data, making it easier to compare measurements against what is typical for that time period. -1. Define the Collection Interval +### Metric Aggregation - This is how often you collect data. +Different metric types are aggregated differently when building baselines: - Example: - Every 15 minutes, collect metrics like received-octets. +* **Counters** — cumulative values measured over a window (example: octets transmitted) +* **Gauges** — snapshot values that can go up or down (example: CPU load in percent) +* **Samples** — discrete points measured (example: latency measured periodically) -2. Filter the NSP resource using a path-filter +### Seasonality +Metrics often follow recurring time-based patterns. For example: - Select which resources to monitor using a filter path. +* **Daily season** — traffic rises every weekday around 9am and drops overnight +* **Weekly season** — weekends often show lower traffic compared to weekdays - Example: - Filter for ports with traffic, specific interfaces, or NE-IDs. +A season defines the length of the repeating cycle used for training the baseline (e.g., 24 hours). The baseline learns expected values within that cycle, so it can account for recurring variations. -3. Aggregate the data based on counter, gauge or sample +Typically, you configure the longest relevant season (e.g., 1 week if weekday vs. weekend differences matter). Keep in mind that longer seasons require more time to collect enough data before the baseline becomes reliable. - You collect metrics like: +### Z-Score +A Z-Score is a statistical way to measure how far a value is from the expected average, expressed in units of standard deviation. Using Z-Score allows NSP to detect unusual events automatically, without operators having to guess or configure thresholds manually. - * counters (e.g., received-octets), - * gauges (e.g., CPU usage), - * samples (e.g., latency). +* A Z-Score of **0** means the value is exactly as expected. +* A Z-Score of **+3** means the value is three standard deviations above normal (a rare event, often flagged as an anomaly). -4. Seasonality and window allows us to calculate the mean and variance - - You define a season (e.g., 1 week) and split it into windows (e.g., 15-min intervals). - For a 1-week season with 15m windows, there are: - 7 days x 24 hours x 4 windows/hour = 672 windows - Each window has its own baseline value — the expected metric for that time slot based on past values. - -5. Update the Baseline - - After each new measurement, the system updates the expected value for that window using a baseline algorithm . - So, the value you see for Tuesday 08:00–08:15 is based on past Tuesdays at the same time. - -6. Apply one of the anamoly algorithm to detect anamoly based on the mean and variance - - Once we have a baseline (expected mean and variance), we apply an anomaly detection algorithm. - If a new value deviates too far from the expected value (e.g., outside 3×standard deviation), it's flagged as an anomaly. - ---- +### Anomaly Detection +By comparing the current metric value to the expected baseline using the Z-Score, NSP can highlight anomalies. These are shown visually in the WebUI (red dots vs dotted baseline) and can trigger alerts for operator action. ## Tasks @@ -90,217 +77,350 @@ Understand how statistical algorithm are used for anomaly detection It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -### Configure a Baseline Analytics +### Create a new Baseline for PE1 (SR OS) -/// note | Click on Menu to access the hamburger menu -![Step 1 screenshot](images/69-baseline/step1.png) -/// +Login to NSP WebUI and navigate to `Data Collection and Analysis Management` and then `Baselines`. -/// note | Click on Data Collection and Analysis -![Step 2 screenshot](images/69-baseline/step2.png) +/// details | Step-by-Step (if getting stuck) + type: success +/// tab | 01 NSP Home Nav +![home-nav](../beginner/images/69-baseline/step1.png) /// - -/// note | Click on Management -![Step 3 screenshot](images/69-baseline/step3.png) +/// tab | 02 Data Collection Nav +![data-collection-nav](../beginner/images/69-baseline/step2.png) /// - -/// note | Click on Dropdown -![Step 4 screenshot](images/69-baseline/step4.png) +/// tab | 03 Management tab +![management-nav](../beginner/images/69-baseline/step3.png) /// - -/// note | Click on Baseline subsection -![Step 5 screenshot](images/69-baseline/step5.png) +/// tab | 04 Baseline Tab +![plotter-view](../beginner/images/69-baseline/step5.png) /// - -/// note | Click on BASELINE to create the baseline -![Step 6 screenshot](images/69-baseline/step6.png) -/// - -/// note | Give a Name For the Use Case -![Step 7 screenshot](images/69-baseline/step7.png) -/// - -/// note | Define the collectionInterval -![Step 8 screenshot](images/69-baseline/step8.png) /// -/// note | Choose a seasonlity -![Step 9 screenshot](images/69-baseline/step9.png) -/// - -/// note | Click on 5 minutes -![Step 10 screenshot](images/69-baseline/step10.png) -/// - -/// note | Click on Window Duration -![Step 11 screenshot](images/69-baseline/step11.png) -/// +Now, click on `+ BASELINE` on the top right of your screen to create a baseline on your `pe1` node. Use the following information to fill in the required form: -/// note | Click on 1 minute for the window -![Step 12 screenshot](images/69-baseline/step12.png) -/// - -/// note | Click on ​Object Filter to select your resource -![Step 13 screenshot](images/69-baseline/step13.png) -/// - -/// note | Type "/" to select available filters -![Step 14 screenshot](images/69-baseline/step14.png) - -Choose `nsp-equipment:network/network-element` -/// - -/// note | Type "/interface" to find the telemetry type -![Step 15 screenshot](images/69-baseline/step15.png) -/// - -/// note | Click on interfaces/interface to monitor ports -![Step 16 screenshot](images/69-baseline/step16.png) -/// - -/// note | Click on COUNTERS for data aggregation -![Step 17 screenshot](images/69-baseline/step17.png) -/// - -/// note | Click on / Press Space to toggle row selection (checked) -![Step 18 screenshot](images/69-baseline/step18.png) - -Check `transmitted-octets-periodic` -/// - -/// note | Click on / Press Space to toggle row selection (checked) -![Step 19 screenshot](images/69-baseline/step19.png) - -Check `received-octets-periodic` -/// - -/// note | Click on ADD -![Step 20 screenshot](images/69-baseline/step20.png) -/// - -/// note | Click on / Press SPACE to select this row -![Step 21 screenshot](images/69-baseline/step21.png) -/// - -/// note | Click on Counter -![Step 22 screenshot](images/69-baseline/step22.png) -/// - -/// note | Click on / Press SPACE to select this row -![Step 23 screenshot](images/69-baseline/step23.png) -/// - -/// note | Click on Counter -![Step 24 screenshot](images/69-baseline/step24.png) -/// - -/// note | Click on VERIFY RESOURCES -![Step 25 screenshot](images/69-baseline/step25.png) -/// - -/// note | Select the router or resource where you want to apply this baseline -![Step 26 screenshot](images/69-baseline/step26.png) -/// - -/// note | You can select multiple resources -![Step 27 screenshot](images/69-baseline/step27.png) - -/// warning -Make sure to select resources from routers that belong to your group. -Access control is not enforced. -/// -/// - -/// note | Click on CREATE -![Step 28 screenshot](images/69-baseline/step28.png) -/// - -/// note | Click on CLOSE -![Step 29 screenshot](images/69-baseline/step29.png) -/// +```yaml +General: + Collection Interval: 30 secs + Season: 5 mins + Window Duration: 1 min +Filter And Counters: + Object Filter: /nsp-equipment:network/network-element[ne-name='g1-pe1'] (update to match your group) + Telemetry Type: telemetry:/base/system-info/system + Selected Counters: cpu-usage (Gauge) +Detector: + Algorithm: Z-Score Absolute + Comparison: Less than + Threshold: 2 +``` -/// note | Click on the create baseline -![Step 30 screenshot](images/69-baseline/step30.png) -/// +/// details | Help (if getting stuck) + type: success +* Replace `g1-pe1` to match the system-name of the `pe1` node in your system. Like if you are in group 17, it becomes `g17-pe1`. +* The baseline name is auto generated and cannot be set during creation. +* After you filled in the form click on `VERIFY RESOURCES`. It may take a bit of time to list the desired counter. Once you see your resource, click on `STOP VERIFICATION`, select the resource to be monitored, and confirm by clicking on `CREATE`. +* Edit the baseline created: Add a detector with the information provided above. -/// note | Click on 3 dots to edit option -![Step 31 screenshot](images/69-baseline/step31.png) +/// tab | 01 Baseline Definition +![baseline-definition](../beginner/images/69-baseline/step7.png) /// - -/// note | Click on Edit -![Step 32 screenshot](images/69-baseline/step32.png) +/// tab | 02 Algorithm Definition +![alogrithm-definition](../beginner/images/69-baseline/step34.png) /// - -/// note | Click rule to create a rule for detecting anamoly -![Step 33 screenshot](images/69-baseline/step33.png) /// -/// note | Set up the comparator -![Step 34 screenshot](images/69-baseline/step34.png) -/// +### Create a new Baseline for AGG1 (SRLinux) -/// note | And set the threshold value -![Step 35 screenshot](images/69-baseline/step35.png) -/// +In the previous task, you created a baseline for SR OS. Now, to gain more hands-on experience, create another subscription using an SRLinux node. This time, let’s focus on interface statistics. Port `ethernet-1/1` on node `agg1` is operational and carries some control-plane traffic, making it a good candidate for monitoring. If you choose raw counters such as received or transmitted octets, make sure to set the `Type` to `Counter`. -/// note | Click on UPDATE to add the changes -![Step 36 screenshot](images/69-baseline/step36.png) -/// +/// details | Solution (if getting stuck) + type: success +```yaml +General: + Collection Interval: 30 secs + Season: 5 mins + Window Duration: 1 min +Filter And Counters: + Object Filter: /nsp-equipment:network/network-element[ne-name='g1-agg1'] (update to match your group) + Telemetry Type: telemetry:/base/interfaces/interface + Selected Counters: received-octets (Counter) +Detector: + Algorithm: Z-Score Absolute + Comparison: Less than + Threshold: 3 +``` + +As in the previous task, after clicking `VERIFY RESOURCES` it takes about 30 seconds to populate the list of available interface resources. Once the list appears, stop verification, select interface `ethernet-1/1`, and proceed to create the baseline. +/// + +With these two baselines — CPU for SR OS and interface statistics for SR Linux — you now have vendor-agnostic metrics that provide a consistent, normalized view across device families and vendors. This makes it easy to work seamlessly across different platforms. + +### Check the Telemetry subscription + +Login into the SR OS node you are monitoring and check the active telemetry subscriptions from CLI. + +/// admonition | Do you spot the corresponding gRPC subscription? + type: question +The corresponding subscription is retrieving CPU usage stats at a 30sec interval. +/// + +/// details | gRPC Subscription Checking Hint + type: success +/// tab | List Active Subscriptions Command +``` +[/] +A:admin@g1-pe1# show system telemetry grpc subscription +``` +/// +/// tab | Example Output of Subscriptions +``` +=============================================================================== +Telemetry gRPC subscriptions +=============================================================================== +Id User Mode Port + Destination +------------------------------------------------------------------------------- +1 admin stream 58876 + 172.31.255.29 +2 admin stream 58876 + 172.31.255.29 +3 admin stream 58876 + 172.31.255.29 +4 admin stream 58876 + 172.31.255.29 +5 admin stream 58876 + 172.31.255.29 +6 admin stream 58876 + 172.31.255.29 +7 admin stream 58876 + 172.31.255.29 +13 admin stream 43182 + 172.31.255.29 +14 admin stream 43182 + 172.31.255.29 +15 admin stream 43182 + 172.31.255.29 +16 admin stream 43182 + 172.31.255.29 +17 admin stream 43182 + 172.31.255.29 +19 admin stream 45599 + 172.31.255.29 +23 admin stream 45599 + 172.31.255.29 +------------------------------------------------------------------------------- +No. of gRPC Telemetry subscriptions: 14 +=============================================================================== +``` +/// +/// tab | Get Subscribed Paths Command +The corresponding SR OS CLI command requires the subscription-id to be provided. You may need to check the corresponding subscriptions one after another to identify the correct one. As you've just added the new subscription, most likely it is the last one in the list. However, it is a good learning to check some of the listed subscriptions to better understand the structure. + +``` +[/] +A:admin@g1-pe1# show system telemetry grpc subscription 23 paths +``` +/// +/// tab | Example Output of Subscribed Paths +``` +=============================================================================== +Telemetry gRPC subscription +=============================================================================== +Subscription id : 23 +User : admin +Destination : 172.31.255.29 +Port : 45599 +Subscription mode : stream +Encoding : json +Notification count : 2428 +Context count : 2428 +Notification bundling : Disabled + +Extensions +------------------------------------------------------------------------------- +Config-Subscription : Disabled + +------------------------------------------------------------------------------- +Paths +------------------------------------------------------------------------------- +Path : /state/system/cpu[sample-period=1]/summary/usage/cpu- + usage +Path mode : sample +Sample interval : 30000 ms +Finished samples : 2428 +Deferred samples : 0 +Total collection time : 2428 ms +Min collection time : 1 ms +Avg collection time : 1 ms +Max collection time : 1 ms +------------------------------------------------------------------------------- +No. of paths : 1 +=============================================================================== +``` +/// +/// + +/// details | Pro Tip + type: tip +To check your SR Linux node for active subscriptions, you first need to enter `state` mode. + +``` +--{ + running }--[ ]-- +A:g1-agg1# enter state + +--{ + state }--[ ]-- +A:g1-agg1# system grpc-server insecure-mgmt + +--{ + state }--[ system grpc-server insecure-mgmt ]-- +A:g1-agg1# info + admin-state enable + timeout 7200 + rate-limit 65000 + session-limit 100 + max-concurrent-streams 65535 + metadata-authentication true + yang-models native + default-tls-profile false + network-instance mgmt + port 57400 + oper-state up + trace-options [ + request + response + common + ] + services [ + gnmi + gnoi + gnsi + gribi + p4rt + ] + source-address [ + :: + ] + gnmi { + commit-confirmed-timeout 0 + commit-save false + include-defaults-in-config-only-responses false + } + statistics { + access-rejects 1 + last-access-reject "2025-08-18T20:44:20.284Z (2 days ago)" + access-accepts 887 + last-access-accept "2025-08-21T16:25:53.883Z (10 minutes ago)" + rpc /gnmi.gNMI/Capabilities { + access-rejects 1 + last-access-reject "2025-08-18T20:44:20.284Z (2 days ago)" + access-accepts 1 + last-access-accept "2025-08-18T20:46:51.041Z (2 days ago)" + } + rpc /gnmi.gNMI/Get { + access-rejects 0 + access-accepts 441 + last-access-accept "2025-08-18T21:02:05.427Z (2 days ago)" + } + rpc /gnmi.gNMI/Set { + access-rejects 0 + access-accepts 1 + last-access-accept "2025-08-18T20:46:55.276Z (2 days ago)" + } + rpc /gnmi.gNMI/Subscribe { + access-rejects 0 + access-accepts 444 + last-access-accept "2025-08-21T16:25:53.883Z (10 minutes ago)" + } + } + unix-socket { + admin-state enable + socket-path /opt/srlinux/var/run/sr_grpc_server_insecure-mgmt + } + client 1 { + type gnmi + user admin + user-agent "gNMIc/0.38.2 grpc-go/1.63.2" + remote-host 10.128.1.71 + remote-port 39726 + start-time "2025-08-15T04:07:45.467Z (6 days ago)" + gnmi { + paths 1 { + path "/system/app-management/application[name=*]/..." + mode SAMPLE + sample-interval 5 + } + } + } + client 2 { + ... + } + ... +``` +/// + +### Trigger a Baseline Event + +By creating another subscription on `agg1` and reviewing the active subscriptions should have given NSP enough time to learn what is considered a normal CPU usage for `pe1`. This initial training phase takes about 3 seasons (≈15 minutes). Now, let’s generate some load to trigger a baseline event. + +One way to increase CPU usage is to run **rapid pings** between two nodes. Both the node sending pings and the node responding will experience higher CPU load. You may also use any other method that reliably increases CPU usage. + +/// details | Rapid Ping Hint + type: success +You can generate CPU load directly from the SR OS CLI using the command below to run rapid pings. Make sure to adjust the target IP address as needed. The actual CPU impact depends on the test parameters provided (count, interval, size). + +The example below runs a ping test from pe1 to p1, lasting about 60 seconds and using an interface IP address as the destination. Since interface addresses are identical across all groups, you can simply copy and paste the command on your system to quickly generate additional CPU load through rapid pings. + +``` +[/] +A:admin@g1-pe1# ping 10.64.11.0 router-instance Base count 6000 interval 0.01 size 1400 output-format summary +PING 10.64.11.0 1400 data bytes +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +---- 10.64.11.0 PING Statistics ---- +6000 packets transmitted, 6000 packets received, 0.00% packet loss +round-trip min = 1.56ms, avg = 4.64ms, max = 60.7ms, stddev = 4.10ms +``` +/// + +### Visualize your Baseline + +* Open `Data Collection and Analysis Visualizations` +* `PLOT` the selected baseline resource -/// note | Click on CANCEL to rerturn to baseline -![Step 37 screenshot](images/69-baseline/step37.png) -/// +/// note +The Baseline Visualization can directly be opened from Baseline Management. Check the context menu (3 dots) of the Baseline entry you've created. -/// note | Click on 3 dots to access visualization -![Step 38 screenshot](images/69-baseline/step38.png) +The anomalies are displayed as red dots on the plotter. The expected values are generated using the collected statistics, visualized using dotted lines. /// -/// note | Click on Open in Data Collection and Analysis Visualizations -![Step 39 screenshot](images/69-baseline/step39.png) +/// details | Step-by-Step (if getting stuck) + type: success +/// tab | 01 Telemetry Viewer Navigation +![visualisation-nav](../beginner/images/69-baseline/step39.png) /// - -/// note | Click on PLOT -![Step 40 screenshot](images/69-baseline/step40.png) - -/// warning -With the settings provided (collection: 30s, window: 1min, season: 5min) you should wait around 10min to see results! +/// tab | 02 Resource Selection to Plot +![resource-selection](../beginner/images/69-baseline/step40.png) /// +/// tab | 03 Result +![results](../beginner/images/69-baseline/Result-baseline.JPG) /// - -### Generate some traffic - -Use high frequency ping (rapid, large mtu) to generate some traffic to ensure hitting the baseline. -Continue monitoring the plotter. - -/// note -Based on the seasonality and window length, the detector rule will begin to apply. -You need to configure the comparator to detect values less than a threshold close to 0. -This helps identify anomalies such as port flapping, where there is a sudden drop in the metric value toward zero. - -Anamolies are pushed into a kafka topic which can be used to trigger email notification or closed of automation. /// -/// note | **SUMMARY** -Name: Detect Port Flaps +## Summary - Collection Interval: 30 secs - Sesonality: 5 mins - Window Duration: 1 mins - Telemetry Type: /interfaces/interface - Object Filter: /nsp-equipment:network/network-element[ne-id={{router-id}}] + Congratulations! You have completed this activity. Take this opportunity to look back on some of the things you have achieved: -Detector: +* Learn how to configure Baseline Analytics in the NSP WebUI. +* Understand how to train and apply statistical models on telemetry data. +* Detect anomalies using Z-Score based detection. +* Use object filters and telemetry paths to scope your analysis. +* Visualize baseline behavior and anomaly events. +* Understand the relationship between collection interval, seasonality, and window size. - Threshold: 0.0001 - Comparison: Less than - Algorithm: Z-score Absolute - Evaluate What: Value - Evaluate When: End of Window -/// +--- -### Next steps +## Next Steps -Here are some ideas on how to continue: +Here are some suggestions on how to continue: -* What's the difference between indicators and baseline? -* Add baselines for other KPIs like CPU and memory. +* Run the [Indicator Analytics](../beginner/68-indicator-analytics.md) activity and understand the differences between Indicators and Baselines. +* Add baselines for other KPIs like interface or ports. +* Run Baseline Analytics at scale targeting many objects. diff --git a/docs/nsp/beginner/70-nsp-inventory-report-using-workflow.md b/docs/nsp/beginner/70-nsp-inventory-report-using-workflow.md index a98c5b5..ab7ea51 100644 --- a/docs/nsp/beginner/70-nsp-inventory-report-using-workflow.md +++ b/docs/nsp/beginner/70-nsp-inventory-report-using-workflow.md @@ -1,112 +1,472 @@ --- tags: - - NSP - - Workflow Manager +- NSP +- RESTCONF +- Workflow Manager --- -# Inventory Report using Workflow Manager +# Inventory Reports | | | | --- | --- | -| **Activity name** | Inventory Report using Workflow | +| **Activity name** | Inventory Report | | **Activity ID** | 70 | -| **Short Description** | Collect detailed information about transceivers (SFPs, ...) installed | +| **Short Description** | Collect detailed information about installed transceivers | | **Difficulty** | Beginner | -| **Tools used** | | -| **Topology Nodes** | all SR OS and SRLinux nodes | -| **References** | | +| **Tools used** | NSP, Workflow Manager | +| **Topology Nodes** | all SR OS and SR Linux nodes | +| **References** | [NSP Developer Portal](https://developer.nokia.com/nsp) (free account required) | ## Objective -Retrieve detailed transceiver attributes (like vendor, type, wavelength) for all installed pluggable optics (like SFPs) in -the network using a workflow and visualize the data as an HTML report. +In daily operations, it is difficult to get a clear, up-to-date view of physical equipment installed across the network. Information is scattered across devices, time-consuming to retrieve, and hard to track over longer periods. This can slow down lifecycle management tasks such as identifying parts running out of maintenance or support. Furthermore, it impacts investigation of issues like optical signal degradation, when you need to correlate network insights with the inventory of optical transceivers. -This workflow demonstrates integration of: - -* RESTCONF API to query NE hardware -* Data filtering and extraction using Jinja-style selectors -* Result rendering as an HTML table +In this activity, you will build an NSP workflow that automatically generates an operator-friendly HTML report of all installed transceivers (e.g. SFPs) in the network. The report makes transceiver information easy to retrieve, store, and review, giving you a reliable basis for both routine lifecycle tasks and problem investigations. ## Technology Explanation -Nokia NSP supports collecting detailed hardware inventory using RESTCONF. -The `transceiver-details` subtree under each port in the hardware-component model exposes the SFP-specific information. +The following technologies work together to create a practical framework for automating the collection, transformation, and presentation of network inventory data. The process starts with retrieving raw device information and ends with sharing results in user-friendly or machine-readable formats. + +### RESTCONF API + +The **RESTCONF API** provides access to network inventory. It allows secure retrieval of physical and logical details from network elements, such as installed optical transceivers. In this activity, calls are made through `nsp.https`, which handles authentication and encryption, so you don’t have to manage credentials manually. + +### Workflows + +At the core of the automation is the **workflow engine**, which defines the sequence of tasks: + +1. Collecting inventory data. +2. Applying filters and transformations. +3. Formatting the results. +4. Delivering the output to the user or an external system. + +Workflows are written in [Mistral DSL](https://docs.openstack.org/mistral/ocata/dsl/dsl_v2.html), a YAML-based domain-specific language. YAML is easy to read and write, making workflows approachable even for beginners. + +#### Supporting Technologies for Workflow Authors + +To enrich workflow logic and presentation, several technologies can be combined: + +* **YAQL (Yet Another Query Language):** Used to filter, extract, and restructure data. For example, you might select only transceivers above a certain speed and reshape the results into a compact summary. +* **Jinja2:** A templating language for generating text dynamically. It’s often used to turn processed data into user-friendly reports. +* **Python / JavaScript:** For more advanced tasks, workflows can include snippets of Python or JavaScript to implement custom logic or handle data beyond what YAQL or Jinja2 can easily cover. + +### Output and Delivery Techniques + +Once the data is processed, workflows offer multiple ways to present or distribute the results: + +* **Direct HTML Output:** A workflow can generate an HTML report and return it directly to the user, making results instantly viewable in a browser. +* **Machine-Readable Formats:** Data can also be returned as JSON, YAML, XML, or CSV, which makes it easier to feed into other tools. +* **PDF Conversion:** For archival or distribution, reports can be exported as PDF files. +* **File Service:** Instead of showing results immediately, workflows can dump outputs into files stored on the file-service for later retrieval. +* **Email Delivery:** Results can be sent as email attachments or inline reports, making it simple to distribute findings to a broader audience. + +### Putting It All Together + +Think of this framework as a **recipe**: + +* The **RESTCONF API** is your ingredient supplier (raw inventory data). +* The **workflow** is the cooking process (steps in order). +* **YAQL** acts as your knife and strainer (selecting and reshaping the data). +* **Jinja2, Python, and JavaScript** are your seasoning and plating tools (making the output useful and appealing). +* The **output and delivery techniques** are the serving options—whether you hand someone a plated meal (HTML report), a recipe card (JSON/YAML), or a packaged lunchbox (PDF or email). + +## Tasks + +**You should read these tasks from top-to-bottom before beginning the activity.** + +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. + +/// warning +Remember that you are using a shared NSP system. Ensure your group number is part of the workflow name to guarantee uniqueness. +/// + + +You will build a workflow-based solution using the following core NSP capabilities and supporting technologies that work together to query, process, and present hardware inventory data in a consumable format. + +### Retrieve NSP hardware inventory via RESTCONF API + +Check the [NSP API documentation](https://network.developer.nokia.com/api-documentation) on the *Developer Portal*. As you are about to report the inventory of optical transceivers, search for *Physical Inventory*. In the corresponding Postman collection, you will find the required information under *Network Infrastructure Management* and then *Network Inventory* (Restconf API). + +To query NSP, you may have the choice between using either the a basic GET request (part of the RESTCONF standard) or the advanced `nsp-inventory:find` operation (using POST). More information about how to query information from NSP can be found under [Learn NSP](https://network.developer.nokia.com/learn/25_4/network-functions/network-inventory/get_find_apis) on the Developer Portal. + +/// admonition | What's the XPATH (RESTCONF/YANG) to retrieve optical transceiver information? + type: question +/// details | Answer + type: success +The following xpath could be used to query transceiver information: -/// tab | RESTCONF resource for transceiver information ``` -/network/network-element[ne-id=*]/hardware-component/port[component-id=*]/transceiver-details +/nsp-equipment:network/network-element/hardware-component/port/transceiver-details ``` + +Both `network-element` and `port` are both lists. The key for `network-element` is the `ne-id` and the key for `port` is the `component-id`. /// -/// tab | YANG Path Reference - -From the transceiver-details subtree, the following fields are retrieved: - -- `connector-code` *(string)* -- `vendor-o-u-i` *(string)* -- `laser-wave-length` *(decimal64)* -- `optical-compliance` *(string)* -- `specific-type` *(string)* -- `number-of-lanes` *(int64)* -- `connector-type` *(string)* -- `link-length-support` *(string)* /// -## Tasks +NSP API calls require authentication. API users must first generate an auth-token, which is then provided as a Bearer Token for all subsequent API requests. Note that tokens have a limited lifetime (default: 1 hour). To prevent token expiration, you can either refresh the token or request a new one if the previous token has expired. It is also recommended to revoke the token once it is no longer needed. Examples of token management are available in the corresponding Postman collections. + +Details about authentication and access-control can be found [here](https://network.developer.nokia.com/learn/25_4/common-functions/access-authentication-apis). + +* Use NSP action-execution (preferred), Postman, or `curl` to query transceiver data from NSP. + +/// details | Example Solution + type: success +/// tab | Solution using HTTP GET: + +**REQUEST:** + +```yaml +url: https://restconf-gateway/restconf/data/nsp-equipment:network/network-element/hardware-component/port/transceiver-details +method: GET +``` + +**RESPONSE:** + +```yaml +result: + url: >- + https://restconf-gateway/restconf/data/nsp-equipment:network/network-element/hardware-component/port/transceiver-details + content: + nsp-equipment:transceiver-details: + - '@': + nsp-model:schema-nodeid: >- + /nsp-equipment:network/network-element/hardware-component/port/transceiver-details + nsp-model:identifier: >- + /nsp-equipment:network/network-element[ne-id='fd00:fde8::2:11']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/c6/breakout-port=1/1/c6/1']/transceiver-details + nsp-model:creation-time: '2025-08-18T19:05:31.479Z' + nsp-model:last-modified-time: '2025-08-21T08:24:40.428Z' + nsp-model:sources: + - >- + fdn:app:mdm-ami-cmodel:fd00:fde8::2:11:equipment:TransceiverDetails:/port[port-id='1/1/c6/1'] + - >- + fdn:yang:nsp-network:/nsp-network:network/node[node-id='fd00:fde8::2:11']/node-root/nokia-state:state/port[port-id='1/1/c6/1'] + - >- + fdn:yang:nsp-network:/nsp-network:network/node[node-id='fd00:fde8::2:11']/node-root/nokia-conf:configure/port[port-id='1/1/c6/1'] + connector-code: null + vendor-o-u-i: null + diagnostic-capable: false + laser-wave-length: null + optical-compliance: null + specific-type: '' + media: N/A + number-of-lanes: null + connector-type: null + link-length-support: null + laser-tunability: Unequipped + - '@': + nsp-model:schema-nodeid: >- + /nsp-equipment:network/network-element/hardware-component/port/transceiver-details + nsp-model:identifier: >- + /nsp-equipment:network/network-element[ne-id='fd00:fde8::2:11']/hardware-component/port[component-id='shelf=1/cardSlot=1/card=1/mdaSlot=1/mda=1/port=1/1/c1/breakout-port=1/1/c1/1']/transceiver-details + nsp-model:creation-time: '2025-08-18T19:05:31.846Z' + nsp-model:last-modified-time: '2025-08-21T08:24:40.428Z' + nsp-model:sources: + - >- + fdn:yang:nsp-network:/nsp-network:network/node[node-id='fd00:fde8::2:11']/node-root/nokia-conf:configure/port[port-id='1/1/c1/1'] + - >- + fdn:yang:nsp-network:/nsp-network:network/node[node-id='fd00:fde8::2:11']/node-root/nokia-state:state/port[port-id='1/1/c1/1'] + - >- + fdn:app:mdm-ami-cmodel:fd00:fde8::2:11:equipment:TransceiverDetails:/port[port-id='1/1/c1/1'] + connector-code: null + vendor-o-u-i: null + diagnostic-capable: false + laser-wave-length: null + optical-compliance: null + specific-type: '' + media: N/A + number-of-lanes: null + connector-type: null + link-length-support: null + laser-tunability: Unequipped +``` -/// warning -Remind, that you are using a single NSP system (shared), that is used for all groups. Therefore, ensure -your group-number is part of the workflow name you are creating to ensure uniqueness. /// +/// tab | Solution using `nsp-inventory:find` (POST): -**You should read these tasks from top-to-bottom before beginning the activity.** +**REQUEST:** -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +```yaml +url: https://restconf-gateway/restconf/operations/nsp-inventory:find +method: POST +body: + input: + xpath-filter: /nsp-equipment:network/network-element/hardware-component/port/transceiver-details + include-meta: false +``` -### Explore NSP Physical Inventory +**RESPONSE:** -Nokia NSP supports collecting detailed hardware inventory via its RESTCONF gateway. -The `transceiver-details` subtree under each port in the hardware-component model exposes the SFP-specific information. +```yaml +result: + url: https://restconf-gateway/restconf/operations/nsp-inventory:find + content: + nsp-inventory:output: + data: + - connector-code: null + vendor-o-u-i: null + diagnostic-capable: false + laser-wave-length: null + optical-compliance: null + specific-type: '' + media: N/A + number-of-lanes: null + connector-type: null + link-length-support: null + laser-tunability: Unequipped + - connector-code: null + vendor-o-u-i: null + diagnostic-capable: false + laser-wave-length: null + optical-compliance: null + specific-type: '' + media: N/A + number-of-lanes: null + connector-type: null + link-length-support: null + laser-tunability: Unequipped + - connector-code: lc + vendor-o-u-i: 00:00:5f + diagnostic-capable: true + laser-wave-length: 1302 + optical-compliance: 100GBASE-LR4 + specific-type: cfp2-or-qsfp28 + media: ethernet + number-of-lanes: 4 + connector-type: qsfp + link-length-support: 10km for SMF + laser-tunability: Unequipped +``` -A good resource to get started is the API/model documentation available on Developer Portal. -Check information resources available about physical inventory. -Query NSP using curl, POSTMAN or WFM WebUI to explore inventory data available. +/// +/// tab | Alternative solution using `nsp-inventory:find` (POST) + +**REQUEST:** -/// note | Resource URI to query transceiver details ``` -/network/network-element[ne-id=*]/hardware-component/port[component-id=*]/transceiver-details +url: https://restconf-gateway/restconf/operations/nsp-inventory:find +method: POST +body: + input: + xpath-filter: /nsp-equipment:network/network-element/hardware-component/port[admin-state='unlocked'] + include-meta: false + fields: ne-id;name;description;oper-state;transceiver-details(vendor-o-u-i;diagnostic-capable;laser-wave-length;optical-compliance;media) +resultFilter: $.content.get('nsp-inventory:output').data ``` + +**RESPONSE:** + +``` +result: + url: https://restconf-gateway/restconf/operations/nsp-inventory:find + content: + - name: ethernet-1/1 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:52 + - name: ethernet-1/1 + oper-state: enabled + description: spine12-leaf1 + ne-id: fd00:fde8::2:32 + - name: ethernet-1/2 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:52 + - name: ethernet-1/1 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:51 + - name: ethernet-1/3 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:52 + - name: ethernet-1/2 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:51 + - name: ethernet-1/1 + oper-state: enabled + description: peering2-transit1 + ne-id: fd00:fde8::2:53 + - name: ethernet-1/2 + oper-state: enabled + description: peering2-ixp1 + ne-id: fd00:fde8::2:53 + - name: ethernet-1/3 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:51 + - name: ethernet-1/2 + oper-state: disabled + description: leaf12-client12 + ne-id: fd00:fde8::2:35 + - name: ethernet-1/3 + oper-state: enabled + description: leaf13-client13 + ne-id: fd00:fde8::2:35 + - name: ethernet-1/2 + oper-state: enabled + description: spine12-leaf2 + ne-id: fd00:fde8::2:32 + - name: ethernet-1/3 + oper-state: enabled + description: spine12-leaf3 + ne-id: fd00:fde8::2:32 + - name: ethernet-1/31 + oper-state: enabled + description: spine11-pe3 + ne-id: fd00:fde8::2:32 + - name: ethernet-1/32 + oper-state: enabled + description: spine11-pe2 + ne-id: fd00:fde8::2:32 + - name: ethernet-1/50 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:52 + - name: ethernet-1/49 + oper-state: enabled + description: leaf3-spine11 + ne-id: fd00:fde8::2:35 + - name: ethernet-1/50 + oper-state: enabled + description: leaf3-spine12 + ne-id: fd00:fde8::2:35 + - name: ethernet-1/1 + oper-state: enabled + description: spine11-leaf1 + ne-id: fd00:fde8::2:31 + - name: ethernet-1/2 + oper-state: enabled + description: spine11-leaf2 + ne-id: fd00:fde8::2:31 + - name: ethernet-1/3 + oper-state: enabled + description: spine11-leaf3 + ne-id: fd00:fde8::2:31 + - name: ethernet-1/31 + oper-state: enabled + description: spine11-pe3 + ne-id: fd00:fde8::2:31 + - name: ethernet-1/32 + oper-state: enabled + description: spine11-pe2 + ne-id: fd00:fde8::2:31 + - name: ethernet-1/1 + oper-state: enabled + description: leaf21-client21 + ne-id: fd00:fde8::2:41 + - name: ethernet-1/49 + oper-state: enabled + description: leaf1-pe1 + ne-id: fd00:fde8::2:41 + - name: ethernet-1/50 + oper-state: enabled + description: leaf1-pe4 + ne-id: fd00:fde8::2:41 + - name: ethernet-1/1 + oper-state: enabled + description: leaf11-client11 + ne-id: fd00:fde8::2:33 + - name: ethernet-1/2 + oper-state: disabled + description: leaf12-client12 + ne-id: fd00:fde8::2:33 + - name: ethernet-1/49 + oper-state: enabled + description: leaf11-spine11 + ne-id: fd00:fde8::2:33 + - name: ethernet-1/50 + oper-state: enabled + description: leaf11-spine12 + ne-id: fd00:fde8::2:33 + - name: ethernet-1/2 + oper-state: disabled + description: leaf12-client12 + ne-id: fd00:fde8::2:34 + - name: ethernet-1/49 + oper-state: enabled + description: leaf12-spine11 + ne-id: fd00:fde8::2:34 + - name: ethernet-1/50 + oper-state: enabled + description: leaf12-spine12 + ne-id: fd00:fde8::2:34 + - name: 1/1/c1 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:11 + transceiver-details: + - vendor-o-u-i: 00:00:5f + diagnostic-capable: true + laser-wave-length: 1302 + optical-compliance: 100GBASE-LR4 + media: ethernet + - name: 1/1/c2 + oper-state: enabled + description: null + ne-id: fd00:fde8::2:11 + transceiver-details: + - vendor-o-u-i: 00:00:5f + diagnostic-capable: true + laser-wave-length: 1302 + optical-compliance: 100GBASE-LR4 + media: ethernet +``` +/// /// -To query the inventory use the resource URI provided above. You can either run a simple `GET` or using -the more advaced `nsp-inventory:find`. Either way, the response will contain the list of optical modules -including key parameters such as: +* Inspect the JSON output to understand the data structure! You should see the following fields in the output: `connector-code`, `vendor-o-u-i`, `laser-wave-length`, `optical-compliance`, `specific-type`, `number-of-lanes`, `connector-type`, and `link-length-support`. -- Connector code and type -- Laser wavelength and tunability -- Optical compliance -- Vendor OUI -- Position in the chassis +/// tip +Based on the queries and responses above, you may notice a key challenge when working with nested tables or tables containing child containers: if the meta information is excluded, the response will only return the requested data as a list, with no way to link it back to a specific device or port. Since those keys are not repeated at child level, it is better to keep the meta information included - even though this adds significant overhead to the responses. -Once received, the data can be reformatted into a table (using markdown or html). This transformation -could be done using java-script, python or jinja2. To extract the data, YAQL expressions need to be -used. -  -### Create a basic workflow to retrieve transceiver data +The alternative solution example from above gives some direction for a reasonable compromise. It queries the ports including transceiver information, while using filters to reduce the output for what is considered important. By this, we remove the dependency on model meta, while providing native access to fields like `ne-id` and port `name`. You may want to spend some time to tweak the `xpath-filter` and `resultFilter` (YAQL expression) to simplify the processing of the data generated. -Implementation is rather straight forward. Using `nsp.https` you don't need to provide any access credentials. -Please ensure to use an unique workflow name to avoid conflicts with other hackathon participants. +/// + +### Create a Basic Workflow to Retrieve Transceiver Data + +Workflow Manager uses OpenStack Mistral as engine for workflow execution. To write a new workflow, the following resource might be helpful to you: + +* NSP Developer Portal: https://network.developer.nokia.com/learn/25_4/programming/workflows/wfm-workflow-development/ +* OpenStack Mistral: https://docs.openstack.org/mistral/ocata/dsl/dsl_v2.html#workflows + +Here a simple workflow boilerplate, you can start with: -/// details | Solution (if getting stuck) - type: success ```yaml +--- version: '2.0' -InventoryReportGroupXX: +workflowname: type: direct + + description: brief description for the workflow + + output: + result: "success" + + tasks: + task1: + action: std.noop +... +``` + +Adjust workflow name, description, inputs and tasks as needed. You may start without any input. The workflow itself, could be a single task that is running action `nsp.https` with the corresponding inputs, e.g. `method`, `url`, and `body`. + +The workflow action execution from before is a great way to write this new workflow. If you use the `COPY` button in the `Run Action Execution` form, the system will generate a fully populated task definition into your clipboard that you can simply paste into a new workflow. + +YAQL is a great way to transform objects and extract information in workflows. More information about YAQL can be found [here](https://yaql.readthedocs.io/). In this case, you can keep it simple the task result can be accessed by `<% task().result %>`. +Don't forget to use a unique name for your workflows, e.g. by adding your group number! + +/// details | Solution + type: success +```yaml +version: '2.0' +InventoryReportGroupXX: + type: direct output: result: <% $.response %> - tasks: getInfo: action: nsp.https @@ -118,23 +478,28 @@ InventoryReportGroupXX: ``` /// -Execute your workflow and check execution results. Instead of using RESTCONF GET, you could also use `nsp-inventory:find`. +### Enhance Output into a Human-Centric Format -### Extend you workflow to produce a dynamic HTML table +NSP workflows allow transforming structured data into readable formats. +Let’s render HTML. You can use Javascript, Python, or Jinja2. -Again, there are multiple ways to get here. You may decide to use JavaScript, Python or Jinja2. -There is no wrong or right, while it all may depend on your own preferences. +If you consider using JavaScript, you will find the corresponding information from OpenStack Mistral documentation [here](https://docs.openstack.org/mistral/ocata/dsl/dsl_v2.html#std-javascript). + +[Jinja Templating Language](https://jinja.palletsprojects.com/en/stable/templates) is another great way to render HTML from user data. The [usage of Jinja Template](https://network.developer.nokia.com/learn/25_4/programming/workflows/wfm-workflow-development/wfm-Advanced-Concepts#Advanced_concepts_Jinja_Templates) is discussed on the Developer Portal. + +To render the HTML you need to add another task to the workflow. Use `on-success`, `on-error`, or `on-complete` to transition from one task to another. While you may have the option to make task transitions conditional, in the case of reporting this might not be necessary. + +Use `publish` (and `publish-on-error`) to publish a dictionary of variables to the workflow context, so it can be used by follow-up actions using simple YAQL expressions (or Jinja) like this `<% $.variable_name %>`. + +/// details | Possible Solution + type: success -/// details | Solution (if getting stuck) ```yaml version: '2.0' - NspSfpInventoryGroupXX: type: direct - output: - result: <% $.html %> - + result: <% $.html %> tasks: getInfo: action: nsp.https @@ -158,7 +523,7 @@ NspSfpInventoryGroupXX: $.get("link-length-support"), $.get("@")]) .orderBy($[1]) %> - on-complete: + on-success: - renderTable renderTable: @@ -167,27 +532,13 @@ NspSfpInventoryGroupXX: context: <% $.testdata %> script: | var row = $[4]; - var header = $; - var report = ""; - - report += ""; - report += ""; - report += ""; - report += "
" + header[0] + "
" + header[1] + "
" + header[2] + "
" + header[3] + "

"; - - report=report+"" - + var report = ""; + report += "
ConnectorO-U-IWavelengthComplianceTypeLanesConnector TypeLink Length SupportSFP Position
"; for (var i = 0; i < row.length; i++) { - if (row[i][0] != null) { - report += ""; - } + let text = row[i][8]["nsp-model:identifier"] || ""; + let pos = (text.match(/\[(.*?)\]/g) || []).join(" "); + report += ``; } - report += "
ConnectorOUIWavelengthComplianceTypeLanesConnector TypeLink LengthPosition
" + row[i][0] + "" + row[i][1] + "" + row[i][2] + "" + row[i][3]; - report += "" + row[i][4] + "" + row[i][5] + "" + row[i][6] + "" + row[i][7]; - let text = row[i][8]["nsp-model:identifier"]; - let pattern = /\[(.*?)\]/g; - let result = text.match(pattern); - report += "" + result + "
${row[i][0]}${row[i][1]}${row[i][2]}${row[i][3]}${row[i][4]}${row[i][5]}${row[i][6]}${row[i][7]}${pos}
"; return report; publish: @@ -195,36 +546,79 @@ NspSfpInventoryGroupXX: ``` /// -**Sample Output:** +### Bonus: Extend Your Solution (Optional) -| Connector | O-U-I | Wavelength | Compliance | Type | Lanes | Connector Type | Link Length Support | SFP Position | -|-------|---------|------------|------------|--------|-------|-----------------|--------|-----------------------------| -| LC | 00:25:90| 1310 nm | LR4 | QSFP28 | 4 | Duplex | 10 km | [ne-id=SR01][port=1/1/1] | +Make your solution **robust and scalable**. +#### Add Workflow Input -### Now it's your turn +Let users filter by NE-ID -Since we've provided a complete solution for the initial workflows, now we want to test your understanding. -There is also an opportunity here to make some reasonable changes... +/// details | Hint +Add a workflow input attribute `neId` and adjust the resource URL being queried accordingly. Consider auto-generating an input-form, to simplify the node selection by the user. As long you use the attribute name *neId*, the auto-generator will provide you with a pre-defined device picker component. -**Q: What are the caveats of the solution workflow provided?** +Input section may look like this: +```yaml + input: + - neId +``` -/// details | Solution +URL to become: +```yaml + url: https://restconf-gateway/restconf/data/nsp-equipment:network/network-element=<% $.neId %>/hardware-component/port/transceiver-details +``` + +You may consider keeping the `neId` input attribute optional. If not provided, the workflow would still return all transceivers of the entire network. +/// + +#### Add Scheduling + +Run the report every hour/day + +#### Export + +Allow saving as CSV / JSON / Markdown + +/// details | Hint +Workflows can write data onto the [NSP file-server](https://network.developer.nokia.com/learn/25_4/nsp-administration/nsp-file-server). Check for API operation `uploadTextToFile` in the corresponding Postman collection (Developer Portal). +/// + +#### Scalability Note + +/// admonition | Do you see any issues with the current workflow if run at scale? + type: question +/// details | Answer type: success +The current implementation retrieves all data at once. -The initial task `getInfo` publishes a complex data structure. This could be simplified. -Using JavaScript to render HTML output is not straightforward and difficult to test. -Using Jinja2 (or python) makes things easier. -Instead of rendering HTML, Markdown could be considered. +On large networks this could: +- Slow down execution +- Hit RESTCONF API size limits +- Overload WebUI render Consider pagination or filtering per NE. -What happens, if the network has millions of physical ports? -Would the solution still work? Could we use pagination to make it scale? How? +If network size grows (1000s of ports), consider pagination or limiting results. +Use `nsp-inventory:find` with filtering to build a more scalable and performant solution. /// - -**Possible modifications:** +/// + + +## Summary + + Congratulations! You have completed this activity. Take this opportunity to look back on some of the things you have achieved: + +- Explored NSP RESTCONF API +- Created a working workflow to collect SFP data +- Formatted output as an HTML report +- Learned YAQL and workflow design concepts + +--- + +## Next Steps + +Here are some suggestions on how to continue: -* Add error handling and timeout logic -* Refactor the workflow to simplify YAQL and use Jinja2 instead of JavaScript -* Filter results by NE-ID provided by operator (w/ schema-form input) -* Export output to CSV, JSON or PDF -* Store files (CSV, JSON, PDF, MD, or PDF) on file-service \ No newline at end of file +* Let the user provide the `ne-name` to make the solution more operator-friendly +* Update the workflow to accept a list of nodes as input, rather a single device only +* Use Jinja2 (or Python) instead of JS to render the HTML output +* Explore action `nsp.generatePDF` for generating PDF reports +* Creating similar workflows for **cards** and **ports** reporting diff --git a/docs/nsp/beginner/images/68-indicators/create-indicator.png b/docs/nsp/beginner/images/68-indicators/create-indicator.png new file mode 100644 index 0000000..0946580 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/create-indicator.png differ diff --git a/docs/nsp/beginner/images/68-indicators/create-threshold.png b/docs/nsp/beginner/images/68-indicators/create-threshold.png new file mode 100644 index 0000000..9fa7a45 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/create-threshold.png differ diff --git a/docs/nsp/beginner/images/68-indicators/executions1.png b/docs/nsp/beginner/images/68-indicators/executions1.png new file mode 100644 index 0000000..aa3c56d Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/executions1.png differ diff --git a/docs/nsp/beginner/images/68-indicators/executions2.png b/docs/nsp/beginner/images/68-indicators/executions2.png new file mode 100644 index 0000000..742d987 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/executions2.png differ diff --git a/docs/nsp/beginner/images/68-indicators/kafka-wf-association.png b/docs/nsp/beginner/images/68-indicators/kafka-wf-association.png new file mode 100644 index 0000000..98caf4a Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/kafka-wf-association.png differ diff --git a/docs/nsp/beginner/images/68-indicators/trigger.png b/docs/nsp/beginner/images/68-indicators/trigger.png new file mode 100644 index 0000000..4267759 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/trigger.png differ diff --git a/docs/nsp/beginner/images/68-indicators/verify-resources.png b/docs/nsp/beginner/images/68-indicators/verify-resources.png new file mode 100644 index 0000000..9d1c982 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/verify-resources.png differ diff --git a/docs/nsp/beginner/images/68-indicators/visualize1.png b/docs/nsp/beginner/images/68-indicators/visualize1.png new file mode 100644 index 0000000..c0c2fd3 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/visualize1.png differ diff --git a/docs/nsp/beginner/images/68-indicators/visualize2.png b/docs/nsp/beginner/images/68-indicators/visualize2.png new file mode 100644 index 0000000..ece0970 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/visualize2.png differ diff --git a/docs/nsp/beginner/images/68-indicators/visualize3.png b/docs/nsp/beginner/images/68-indicators/visualize3.png new file mode 100644 index 0000000..c6b34cb Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/visualize3.png differ diff --git a/docs/nsp/beginner/images/68-indicators/visualize4.png b/docs/nsp/beginner/images/68-indicators/visualize4.png new file mode 100644 index 0000000..0c3c348 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/visualize4.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wf-execution-view.png b/docs/nsp/beginner/images/68-indicators/wf-execution-view.png new file mode 100644 index 0000000..8644eb7 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wf-execution-view.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wf-output.png b/docs/nsp/beginner/images/68-indicators/wf-output.png new file mode 100644 index 0000000..58f3ee4 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wf-output.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wf-times-matched-kafka.png b/docs/nsp/beginner/images/68-indicators/wf-times-matched-kafka.png new file mode 100644 index 0000000..a90ad26 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wf-times-matched-kafka.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-create-wf.png b/docs/nsp/beginner/images/68-indicators/wfm-create-wf.png new file mode 100644 index 0000000..cee5bb3 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-create-wf.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-kafka-trigger-nav.png b/docs/nsp/beginner/images/68-indicators/wfm-kafka-trigger-nav.png new file mode 100644 index 0000000..bd33784 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-kafka-trigger-nav.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-nav.png b/docs/nsp/beginner/images/68-indicators/wfm-nav.png new file mode 100644 index 0000000..69af6d3 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-nav.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-update-validate.png b/docs/nsp/beginner/images/68-indicators/wfm-update-validate.png new file mode 100644 index 0000000..7e74da6 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-update-validate.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-wf-change-state.png b/docs/nsp/beginner/images/68-indicators/wfm-wf-change-state.png new file mode 100644 index 0000000..c1971ef Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-wf-change-state.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-wf-exec-nav.png b/docs/nsp/beginner/images/68-indicators/wfm-wf-exec-nav.png new file mode 100644 index 0000000..1b945ad Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-wf-exec-nav.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm-wf-nav.png b/docs/nsp/beginner/images/68-indicators/wfm-wf-nav.png new file mode 100644 index 0000000..0243ae0 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm-wf-nav.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm1.png b/docs/nsp/beginner/images/68-indicators/wfm1.png new file mode 100644 index 0000000..ea46dd9 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm1.png differ diff --git a/docs/nsp/beginner/images/68-indicators/wfm2.png b/docs/nsp/beginner/images/68-indicators/wfm2.png new file mode 100644 index 0000000..30b3083 Binary files /dev/null and b/docs/nsp/beginner/images/68-indicators/wfm2.png differ diff --git a/docs/nsp/beginner/images/69-baseline/Result-baseline.JPG b/docs/nsp/beginner/images/69-baseline/Result-baseline.JPG new file mode 100644 index 0000000..424bfd8 Binary files /dev/null and b/docs/nsp/beginner/images/69-baseline/Result-baseline.JPG differ diff --git a/docs/nsp/index.md b/docs/nsp/index.md index ff2e344..58aec7f 100644 --- a/docs/nsp/index.md +++ b/docs/nsp/index.md @@ -32,10 +32,11 @@ It allows seamless integration with your CI/CD pipelines, north-bound 3rd-party While NSP WebUI is the quick choice for developing automation use-cases, we are promoting the use of Visual Studio Code as Integrated Development Environment by choice. If you have the ability to install VS Code on your computer, just do it. It's powerful! It's free! -And it's fun! If you are into programming, you may already have it... If you cannot install it for administrative reasons: Don't Worry! -There is `code-server` which is basically a server-hosted version of VS Code that can be accessed using your web-browser, coming with -the same great experience. The good news: We've got code-server deployed in the hackathon labs, so it is just waiting for -you to connect. +And it's fun! If you are into programming, you may already have it. + +/// note +If you cannot install VS Code for administrative reasons, don’t worry! You can use `code-server`, a server-hosted version of VS Code that runs in your web browser while offering the same familiar experience. Even better: code-server is already deployed in the hackathon labs with all required extensions pre-installed, ready for you to connect. This means you can run Visual Studio Code during this hackathon directly from your browser without any setup. +/// NOKIA is actively contributing VS Code extensions to improve Developer eXperience around our networking products and technologies being used. In this hackathon, you have the opportunity to use the following extensions contributed by Nokia in action: diff --git a/docs/nsp/intermediate/48-nsp-device-specific-infra-config.md b/docs/nsp/intermediate/48-nsp-device-specific-infra-config.md index aac0068..982f20c 100644 --- a/docs/nsp/intermediate/48-nsp-device-specific-infra-config.md +++ b/docs/nsp/intermediate/48-nsp-device-specific-infra-config.md @@ -6,45 +6,57 @@ tags: - Visual Studio Code --- -# NSP Device Configuration - +# Infrastructure Configuration | | | | --- | --- | -| **Activity name** | NSP Device Configuration | -| **Activity ID** | 48 | -| **Short Description** | Use generator tool to build new intent-types for SR OS | -| **Difficulty** | Intermediate | -| **Tools used** | IM VS Code Extension, ICM | -| **Topology Nodes** | :material-router: PE1 | -| **References** | [VSCode IM Extension](https://github.com/nokia/vscode-intent-manager) | +| **Activity name** | Infrastructure Configuration | +| **Activity ID** | 48 | +| **Short Description** | Auto-generate new device-specific infrastructure intent-types for SR OS and use them with Device Configuration | +| **Difficulty** | Intermediate | +| **Tools used** | NSP, Visual Studio Code | +| **Topology Nodes** | :material-router: PE1 | +| **References** | [Visual Studio Code IM Extension](https://github.com/nokia/vscode-intent-manager) | ## Objective -Use Visual Studio Code (or code-server) with the NSP Intent Manager extension to create -device-specific intent-types that can be used in the context of *Device Configuration*. +As a network operator, you probably deal with these common challenges: + +* Device configurations are stored in different places (CLI history, text files, templates), so it’s never clear what the configuration baseline is. +* Manual CLI changes creep in over time, introducing drift and making it harder to align devices back to a known state. +* Onboarding new devices or enabling new features often means starting from scratch, repeating the same manual work again. + +In this activity, you will: + +* Learn how to auto-generate a brand-new intent-type from the device model so you can manage all configuration attributes consistently from day one. +* See how intents, once generated, become the central source of truth — enabling audits, drift detection, and realignment with far less manual effort. +* Understand how this tool-based approach shortens onboarding and provides more flexible options than relying only on pre-defined templates. + +In this activity we are use Visual Studio Code (or code-server) with the NSP Intent Manager extension to create device-specific intent-types that can be used in the context of *Device Configuration*. ## Technology explanation +This section describes the concepts used in this activity. + ### Visual Studio Code -**[Visual Studio Code (VS Code)](https://code.visualstudio.com/)** is a free, lightweight, and cross-platform source-code +**[Visual Studio Code (Visual Studio Code)](https://code.visualstudio.com/)** is a free, lightweight, and cross-platform source-code editor developed by Microsoft, with its core available under [MIT License](https://github.com/microsoft/vscode/blob/main/LICENSE.txt). While the official Microsoft distribution includes telemetry and branding, the underlying [open-source project](https://github.com/microsoft/vscode) is actively developed by thousands of contributors worldwide. Backed by Microsoft and deeply integrated with [GitHub](https://github.com/), -VS Code offers rich extensibility through the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/vscode), enabling +Visual Studio Code offers rich extensibility through the [Visual Studio Code Marketplace](https://marketplace.visualstudio.com/vscode), enabling developers to tailor their development environments with themes, debuggers, linters, and language support. -VS Code runs seamlessly on **Windows, MacOS X, and Linux**, and also powers browser-based development via [code-server](https://github.com/coder/code-server) +Visual Studio Code runs seamlessly on **Windows, MacOS X, and Linux**, and powers browser-based development via [code-server](https://github.com/coder/code-server) and [GitHub Codespaces](https://github.com/features/codespaces). Features like built-in Git support, [Remote SSH](https://code.visualstudio.com/docs/remote/ssh), IntelliSense, and live share collaboration making it a top choice for developers. The well-documented [extension API](https://code.visualstudio.com/api), comprehensive [examples](https://github.com/microsoft/vscode-extension-samples), and clean [UX Guidelines](https://code.visualstudio.com/api/ux-guidelines) encourage a thriving eco-system and consistent user experience. -You can download VS Code [here](https://code.visualstudio.com/Download) and start exploring the modern, extensible, and developer-friendly environment +You can download Visual Studio Code [here](https://code.visualstudio.com/Download) and start exploring the modern, extensible, and developer-friendly environment shaping how code is written today. -NOKIA is actively contributing VS Code extensions to improve Developer eXperience around our networking products and technologies being used. +Nokia is actively contributing Visual Studio Code extensions to improve Developer eXperience around our networking products and technologies being used. In this hackathon, you have the opportunity to use the following extensions contributed by Nokia in action: * [NSP Intent Manager extension](https://github.com/nokia/vscode-intent-manager) @@ -55,48 +67,28 @@ In this hackathon, you have the opportunity to use the following extensions cont * [Containerlab extension](https://github.com/srl-labs/vscode-containerlab) * [NETCONF extension](https://github.com/nokia/vscode-netconf) + +/// warning | Disclaimer +The NSP Intent Manager Extension for Visual Studio Code including the intent-type generator tool is a community-driven open-source initiative. Support status of intent-types generated using Visual Studio Code is experimental! Before using those in production environments, extended testing must be applied to ensure functionality, robustness, usability, performance, and scale. + +If you encounter issues with the generator tool or the intent-types being created, please submit a support request and share your feedback with the community by raising an issue on GitHub. If you’ve discovered a solution that works for you, we would greatly appreciate it if you contributed your code changes back to the project. In doing so, you become an active part of our community and help it grow. +/// + + ### Intent Manager -Intent Manager is a module within the Nokia Network Services Platform (NSP) that enables intent-based networking (IBN) by translating -higher-level objectives into automated network actions. It has the ability to abstract the complexity of network configuration by -allowing operators to express what they want, rather than how to do it. +Intent Manager is a module within the Nokia Network Services Platform (NSP) that enables intent-based networking (IBN) by translating higher-level objectives into automated network actions. It has the ability to abstract the complexity of network configuration by allowing operators to express what they want, rather than how to do it. -By separating declarative intent configuration (w/ validation) from intent operations like audits and synchronization, Intent Manager -enables CRUD operations with operational lifecycle and control. The sync operation is used for deploying changes into the network but -also to reconcile network object configuration in cases of misalignment, while audits are used to identify misalignments including -network configuration drift. +By separating declarative intent configuration (including validation) from intent operations like audits and synchronization, Intent Manager enables CRUD operations with operational lifecycle and control. The sync operation is used for deploying changes into the network but also to reconcile network object configuration in cases of misalignment, while audits are used to identify misalignments including network configuration drift. -The library of intent-types can be updated at runtime, while intent-types are developed in JavaScript using YANG-defined intent -models. Using JavaScript enables full flexibility beyond pure configuration management. Intent Manager supports natively -heterogeneous networks (multi-vendor, multi-domain). +The library of intent-types can be updated at runtime, while intent-types are developed in JavaScript using YANG-defined intent models. Using JavaScript enables full flexibility beyond pure configuration management. Intent Manager natively supports heterogeneous networks (multi-vendor, multi-domain). ### NSP Device Configuration -Device Management Configuration is an intent-based app for infrastructure configuration management (ICM). It uses Intent Manager -as engine underneath, but comes with an optimized user-interface tailored for the needs of device-centric configuration. ICM adds -advanced operational procedures for brownfield configuration discovery and cloning of intent instances. - -There is the concept of *device-specific intent-types* in ICM, where a defined subtree of the device is exposed as intent-model. -The main rational to use device models is to provide control over 100% of the device-level attributes, while device experts are -not confused by any sort of normalization as the intent model is identical to what operators already know. Another advantage of -this is, that intent-types can be widely auto-generated. Remind, going device-specific is a compromise, as intent-types -become specific to given device vendors, families and releases, adding operational and integration complexity. While there is -no abstraction using this approach, all configuration details are accessible via rich configuration forms, however, it is -possible to adjust configuration forms to show the relevant configuration attributes only. +Device Management Configuration is an intent-based app for infrastructure configuration management (ICM). It uses Intent Manager as the engine underneath and comes with an optimized user-interface tailored for the needs of device-centric configuration. ICM adds advanced operational procedures for brownfield configuration discovery and cloning of intent instances. -## Before you start +There is the concept of *device-specific intent-types* in ICM, where a defined subtree of the device is exposed as intent-model. The main rational to use device models is to provide control over 100% of the device-level attributes, while device experts are not confused by any sort of normalization as the intent model is identical to what operators already know. Another advantage of this is that intent-types can be auto-generated. Keep in mind that going device-specific is a compromise, as intent-types become specific to given device vendors, families and releases, adding operational and integration complexity. While there is no abstraction using this approach, all configuration details are accessible via rich configuration forms, and it is possible to adjust those forms to show the relevant configuration attributes only. -/// warning | Disclaimer -The NSP Intent Manager Extension for VS Code including the intent-type generator tool is a community-driven -open-source initiative. Support status of intent-types generated using Visual Studio Code is experimental! -Before using those in production environments, extended testing must be applied to ensure functionality, -robustness, usability, performance, and scale. - -If you find issues around the generator tool or the intent-types being created, please issue your support -requests and provide feedback to the community directly, by raising issues on GitHub! If you've found a -solution that works for you, we if you contribute code changes back to the project. -By this you become part of our community helping it to grow. -/// ## Tasks @@ -104,101 +96,92 @@ By this you become part of our community helping it to grow. It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -### Install / Setup VS Code and the required extensions +### Install / Setup Visual Studio Code and the required extensions + +Prepare your environment for creating ICM intents by installing and setting up Visual Studio Code on your computer. /// tip | Using code-server -If you don't have the necessary privileges to install Visual Studio Code on your computer, the -hackathon lab has code-server deployed, so you can run the editor and the extensions from your -web-browser. +If you don't have the necessary privileges to install Visual Studio Code on your computer, the hackathon lab has code-server deployed, so you can run the editor and the extensions from your web-browser. /// +These are the steps you must perform. Below you can also find a short video demonstrating the process. + * Install Visual Studio Code -* Open VS Code and go to the Extensions side-bar -* Search for "NOKIA Intent Manager" and click "Install" to add the extension to your workspace. -* Open the Settings for the Intent Manager Extension -* Adjust the connection details for your NSP system: `nsp.srexperts.net`with the username/password provided -* Change will take effect immediately; Reload is not required -* If you use the *NSP connect* extension (preferred), you can configure/connect to your NSP straight from the sidebar -* Once done, a new folder named *Intent Manager* appears in your VS Code workspace. -* This folder contains subfolders for intent-types (definitions) and intents (instances). +* Open Visual Studio Code and go to the Extensions sidebar +* Search for "NOKIA Intent Manager" and click "Install" to add the extension to your workspace +* Setup your NSP Connection (Option A, preferred) + - If you use the *NSP connect* extension, you can configure/connect to your NSP straight from the sidebar + - Add a new connection targeting your NSP system: `nsp.srexperts.net` with the username/password provided and connect +* Traditional Setup of your NSP Connection (Option B) + - Open the Settings for the Intent Manager Extension + - Adjust the connection details for your NSP system: `nsp.srexperts.net` with the username/password provided + - Change should take effect immediately. In case it does not, please reload Visual Studio Code +* Once done, a new folder named *Intent Manager* appears in your Visual Studio Code workspace +* This folder contains subfolders for intent-types (definitions) and intents (instances). The content you see is polled from the live system. /// tip | Video: Installing and setting up the extension -{{video(url="https://gitlab.com/-/project/69754954/uploads/b96983518f12ecd4f7ca064fc71d6745/setup-extension.mp4")}}- /// -### Create a new Intent-Type and Intent Instance +### Create a new Intent-type and a new Intent Instance **Create and import intent-types:** -* In your workspace, create an *.igen file with the desired NE configuration context (see [below](#intent-type-generator-files)). -* As your NSP instance is shared between all participating groups, use unique filenames. -* The filename will become the name of the new intent-type, so it must be in kebap-case. -* Remind, the device must point to the `ne-id` (device-id) of a device with matching vendor, - family, and release. In case of **SR** OS routers this is the IP-address of the system interface. - For this hackathon, you may just select the system ip-address of PE1. -* You find an example below the instructions; -* Right-click on the *.igen file and select `Generate intent-type` from the context menu. -* The generation might take some time. You can monitor the progress in the `OUTPUT` panel. -* Check the intent-type contents. -* Right-click on the intent-type folder and select `Upload intent-type` from the context menu. -* The intent-type should appear on the NSP GUI https://nsp.srexperts.net/web/intent-manager/intent-types - -/// note | Example: `demo-icm-sros-ip-filter-group50.igen` +In a directory inside your workspace, create a file named `demo-icm-sros-ip-filter-group01.igen` with the desired NE configuration context, like this: + +/// note | Example: `demo-icm-sros-ip-filter-group01.igen` ```json { "description": "L3 ACL for Nokia SR OS devices (MD MODE)", "category": "policies", "role": "logical", - "device": "XXXXXXXX", + "device": "fd00:fde8::1:21", "context": "/nokia-conf:configure/filter/ip-filter" } ``` /// +* The filename will become the name of the new intent-type, so it must be in kebap-case. +* The `device` value in your *.igen file must point to the `ne-id` of device with the correct vendor, family, and software release. In case of SR OS routers this is the IPv6 address of the system interface. For this hackathon, you may just select the system IP-address of PE1. The example above is for group 1. Adjust the filename and `device` to match your group! +* Right-click on the *.igen file and select `Generate intent-type` from the context menu. +* The generation might take some time. You can monitor the progress in the Visual Studio Code `OUTPUT` panel. +* Once creation finished, verify the contents of the generated intent-type. +* Right-click on the intent-type folder and select `Upload intent-type` from the context menu. +* The intent-type should appear on the [NSP WebUI](https://nsp.srexperts.net/web/intent-manager/intent-types) in `Released` state + +To get a more detailed understanding about *.igen files, please check in the [reference section](#reference-intent-type-generator-files) below. + /// tip -Spend some time to go through the generated code. The intent-type uses a visionary decomposed design. Resources -in the `common` folder are the same for all intent-types generated. A default view-config is created to improve -WebUI usability. The main files that contain custom code are the YANG module and the `script-content.mjs`. If -you've designed intent-types for NSP before, you may recognize the object-oriented design. Be aware, this takes -advantage of the new JavaScript engine (GraalJS), that is available since 24.11. +Spend some time to go through the generated code. The intent-type uses a visionary modular design. Resources in the `common` folder are the same for all intent-types generated. A default view-config is created to improve WebUI usability. The main files that contain custom code are the YANG module and the `script-content.mjs`. If you've designed intent-types for NSP before, you may recognize the object-oriented design. Be aware, this takes advantage of the new JavaScript engine (GraalJS), that is available since NSP 24.11. /// **Import intent-types and creating templates in ICM**: -* Navigate to `Device Management > Configuration intent-types`. +* Navigate to `Device Management > Configuration Intent Types`. * Import the newly created intent-type. * Navigate to `Configuration Templates`. * Create a new template using your intent-type. **Create an intent**: -* Now you can move to Configuration Deployments. +Now you can move further to `Configuration Deployments`. + * Create a new deployment using the previous template. -/// tip | Video: Creating a new Intent-Type and Intent Instance to enable a port +/// tip | Example solution: Creating a new intent-type and intent instance to enable a port -{{video(url="https://gitlab.com/-/project/69754954/uploads/c6334e7d83192a2d5e6aa5522825cb2c/enable-port.mp4")}}- /// -### Create intent-types to configure ports, interfaces and ISIS bindings +We've just learned step-by-step on how to quickly create brand new intent-types from small *.igen files. Now, turn is on you to create all required intent-types required for base router connectivity: Port Configuration, Interface Configuration and IS-IS Interface Configuration. -We've just learned step-by-step on how to quickly create brand new intent-types from small *.igen -files. Now, turn is on you to create all required intent-types required for base router connectivity: -Port Configuration, Interface Configuration and IS-IS Interface Configuration. - -#### Port Config +### Port Config Let's start with port configuration. /// tip -The most important part when creating *.igen files is device-model path. This is where -the subtree starts, that is owned by the corresponding intents. In SR OS MD-CLI one can -use the command `pwc model-path` to retrieve the corresponding string. You should consider -removing the list-key identifiers along the path, to make those identifiers part of the -intent target. +The most important part when creating *.igen files is device-model path. This is where the subtree starts, that is "owned" by the corresponding intents. In SR OS MD-CLI one can use the command `pwc model-path` to retrieve the corresponding string. You should consider removing the list-key identifiers along the path, to make those identifiers part of the intent target. -You may decide to exclude certain children subtrees from the intent-type to reduce the -intent complexity and to speed up rendering time using the `exclude` and/or `max-depth` -statements. +You may decide to exclude certain children's subtrees from the intent-type to reduce the intent complexity and to speed up rendering time using the `exclude` and/or `max-depth` statements. Port configuration is a special case, using `role: physical` and `category: port`. /// @@ -211,13 +194,15 @@ Port configuration is a special case, using `role: physical` and `category: port "description": "Port configuration on Nokia SR OS devices (MD MODE)", "category": "port", "role": "physical", - "device": "XXXXXXXX", + "device": "fd00:fde8::1:21", "context": "nokia-conf:/configure/port", "icmstyle": true, "maxdepth": 2, "exclude": ["sonet-sdh","tdm","otu","network","gnss","dwdm","access","scheduler","transceiver","dist-cpu-protection","ethernet","hybrid-buffer-allocation","modify-buffer-allocation"] } -``` +``` + +Once again, be sure to update the `device` attribute so it matches the `PE1` node for your group. The example shown above corresponds to `group 1`. /// /// note | Device Configuration: Port on PE1 @@ -246,18 +231,14 @@ A:admin@g1-pe1# info configure port 1/1/c1/1 Now, import the intent-type into ICM, create a template and deployments. -#### Interface Config +### Interface Config -We continue with the IP interface configuration associated with the Base router instance. +We continue with the IP interface configuration associated with the `Base` router instance. /// tip -In this case we may keep the router instance reference `router=Base` as part of the -model-path. In this case, the operator cannot select the routing instance anymore and -it would be hardcoded using the `Base` instance. +Since the interfaces we configure in this section always reside in the `Base` routing instance, there is no need to remove that element from the model path. This avoids requiring an unnecessary selection. When creating your *.igen file, ensure that this selection filter is included in the model path. -As role *physical* is used exclusively for hardware configuration like ports and cards, -in all other cases we use role *logical*. The *category* has no functional meaning -and is rather used as a way to categorize intent-types similar to labels. +The role *physical* is reserved for hardware configuration such as ports and cards. In all other cases, we use the role *logical*. The category field has no functional impact; it simply serves to group intent-types in a label-like manner. /// /// details | Solution @@ -268,12 +249,14 @@ and is rather used as a way to categorize intent-types similar to labels. "description": "Interfaces creation on Nokia SR OS devices (MD MODE)", "category": "interface", "role": "logical", - "device": "XXXXXXXX", + "device": "fd00:fde8::1:21", "context": "nokia-conf:/configure/router=Base/interface", "icmstyle": true, "exclude": ["egress","ingress","ldp-sync-timer","load-balancing","lag","ptp-hw-assist","autoconfigure","ipsec","cflowd-parameters","hold-time","eth-cfm","ipv6","qos","if-attribute","untrusted","network-domains","external-reference","ipv4/icmp","ipv4/unnumbered","ipv4/urpf-check","ipv4/dhcp","ipv4/bfd","ipv4/secondary","ipv4/neighbor-discovery","ipv4/vrrp"] } ``` + +Quick reminder: have you updated the `device` attribute to match your group? /// /// note | Device Configuration: Interface on PE1 @@ -296,13 +279,13 @@ A:admin@g1-pe1# info configure router interface p1 ``` /// -Again, import the intent-type into ICM, create a template and deployments. +As already done previously, import the intent-type into ICM, create a template and deployments. -#### IS-IS Interface Config +### IS-IS Interface Config -This is now out last step intent-type to bind the new IP interface to the IS-IS protocol. +As a final step, create an intent-type that will allow operators to associate router network interface with the IS-IS protocol in model-driven SR OS using the NSP WebUI. -/// details | Solution +/// details | Example solution type: success ``` json @@ -310,11 +293,14 @@ This is now out last step intent-type to bind the new IP interface to the IS-IS "description": "ISIS Interfaces on Nokia SR OS devices (MD MODE)", "category": "interface", "role": "logical", - "device": "XXXXXXXX", + "device": "fd00:fde8::1:21", "context": "nokia-conf:/configure/router=Base/isis=0/interface", "icmstyle": true } ``` + +Hackathon activities are not meant to be simple copy-and-paste exercises. Even if you rely on the provided example solution, be sure to update the `device` attribute before generating the intent-type. + /// /// note | Device Configuration: ISIS Interface on PE1 @@ -365,52 +351,36 @@ Adjacencies : 2 ``` /// -## What else could you do??? - -Brilliant, you've mastered this exercise. Using the community approach with *.igen files -really makes the job of intent-type development easy. Even if you are expert on the node -or management systems - but not soo much a JavaScript/YANG developer. +## Summary -But you don't need to stop here. Have you already tried the discover a brownfield -configuration from PE1, or did you create a new one? Have you tried to change the -device configuration directly using CLI and then run audits and reconcile? There -are many things to try out. Maybe you just want to get more knowledgeable on -schema-form customization using our new graphical view-config editor. Remind, -the limit is your own creativity. +Well done — you’ve successfully completed this activity! By working with community-driven *.igen files, you’ve seen how intent-type development can be greatly simplified. This approach lets you focus on the network and management aspects without needing to be an expert in JavaScript or YANG. -Here some more asks, if you are overwhelmed by the simplicity of this approach and your -creativity got blocked: +But this is just the beginning. You might explore discovering a brownfield configuration from PE1, experiment by changing device settings directly through the CLI and then running audits and alignment, or dive deeper into schema-form customization with the graphical view-config editor. -* create an intent-type for customers -* create an intent-type for lag -* create an intent-type for ISIS instance but exclude interfaces. +The possibilities are wide open — how far you go is up to your curiosity and creativity. -## Reference +## Reference: Intent-type Generator Files -### Intent Type Generator Files - -Remember, the starting point for device-specific auto-generation is always an *.igen file, which are in JSON format. -As Visual Studio Code is a text editor, nothing is as easy to create those files. -Here is the list of supported attributes of *.igen files: +The starting point for device-specific auto-generation is always an *.igen file, provided in JSON format. Since Visual Studio Code is a text editor, creating these files is straightforward. Below is the list of supported *.igen file attributes: | Attribute | Type | Default | Usage | |---|---|---|---| | **category** | string | -- | icm_descriptor: helps to categorize the intent (shortcut) | | **role** | string | -- | icm_descriptor: physical or logical (shortcut) | | **description** | string | -- | icm_descriptor: description (shortcut) | -| icmDescriptor | dict | {} | icm_descriptor: transparent access to all descriptor fields | +| **icmDescriptor** | dict | {} | icm_descriptor: transparent access to all descriptor fields | | **context** | string | -- | device-model subtree to cover, example: nokia-conf:/configure/qos/sap-egress | | **device** | string | -- | ne-id of the device used for auto-generation | -| intent_type | string | *filename of the igen-file* | intent-type name | -| author | string | NOKIA | intent-type author | -| exclude | string[] | [] | list of children subtrees to be excluded | -| maxdepth | number | -1 | maximum depth to cover (deeper hierarchies are excluded) | -| labels | string[] | [] | additional labels, `InfrastructureConfiguration` is always added | -| date | string | today | date used for YANG model revision | -| withdefaults | boolean | false | enable/disable default values in YANG | -| applygroups | boolean | false | enable/disable apply-group statements | -| constraints | boolean | false | enable/disable WHEN statements | -| icmstyle | boolean | false | enable/disable top-level container to match ICM needs | +| **intent_type** | string | *filename of the *.igen file* | intent-type name | +| **author** | string | NOKIA | intent-type author | +| **exclude** | string[] | [] | list of children subtrees to be excluded | +| **maxdepth** | number | -1 | maximum depth to cover (deeper hierarchies are excluded) | +| **labels** | string[] | [] | additional labels, `InfrastructureConfiguration` is always added | +| **date** | string | today | date used for YANG model revision | +| **withdefaults** | boolean | false | enable/disable default values in YANG | +| **applygroups** | boolean | false | enable/disable apply-group statements | +| **constraints** | boolean | false | enable/disable WHEN statements | +| **icmstyle** | boolean | false | enable/disable top-level container to match ICM needs | /// note | Example: demo-icm-sros-sap-ingress-policy.json ``` json @@ -420,7 +390,7 @@ Here is the list of supported attributes of *.igen files: "description": "SAP ingress QoS policy on Nokia SR OS devices (MD MODE)", "context": "nokia-conf:/configure/qos/sap-ingress", - "device": "XXXXXXXX", + "device": "fd00:fde8::1:21", "intent_type": "icm-sros-sap-ingress-policy", "author": "hackthon25", @@ -435,4 +405,4 @@ Here is the list of supported attributes of *.igen files: "icmstyle": true } ``` -/// +/// \ No newline at end of file diff --git a/docs/nsp/intermediate/51-nsp-access-port-migration.md b/docs/nsp/intermediate/51-nsp-access-port-migration.md index 8285a92..aaa88de 100644 --- a/docs/nsp/intermediate/51-nsp-access-port-migration.md +++ b/docs/nsp/intermediate/51-nsp-access-port-migration.md @@ -1,68 +1,229 @@ --- tags: - - NSP - - Workflow Manager - - Service Management + +- NSP +- Workflow Manager +- Service Management +- Service Fulfillment Operations --- -# Access Port Migration Automation +# Access Port Migration | | | | --- | --- | -| **Activity name** | Access Port Migration Automation | +| **Activity name** | Access Port Migration | | **Activity ID** | 51 | -| **Short Description** | Migration of EPIPE SAPs from one port to another | +| **Short Description** | Migration automation of `epipe` SAPs from one port to another | | **Difficulty** | Intermediate | -| **Tools used** | Visual Studio Code (or code-server) | +| **Tools used** | NSP, Visual Studio Code | | **Topology Nodes** | :material-router: PE1, :material-router: PE3 | -| **References** | | +| **References** | [NSP Docs](https://infocenter.nokia.com), [OpenStack Mistral](https://docs.openstack.org/mistral/latest/) | + +## Objective + +In this activity you will address a common operational challenge: migrating customer services from one access port to another. Whether you are preparing for a planned card replacement or reacting to a sudden failure, moving SAPs and services manually is both slow and prone to error. +Using NSP Workflow Manager, you will automate this migration. You will prepare the target port, deploy a workflow that moves SAPs and associated services, and validate the outcome. By the end, you will have applied NSP automation to a real-world problem, reducing manual steps, minimizing risk, and accelerating recovery — all while keeping control of the process. + +## Technology Explanation + +Automation of access port migration relies on two main capabilities in NSP: **Workflows** and **Intents** Together, Workflows and Intents allow you to move beyond manual CLI operations, enabling structured, repeatable, and reliable service migrations while maintaining control and oversight. + +### Workflow Manager + +Workflow Manager (WFM) enables operators to automate repetitive or error-prone tasks. Instead of performing manual actions individually, WFM lets you chain API calls into a single, reusable process. This allows you to define end-to-end procedures, including validation, execution, and post-operation checks, all in a structured and repeatable way. + +Besides name and description, workflows may have optional tags. While these tags are mainly informational and allow for quicker filtering, in NSP some values, like `KafkaTrigger`, enable usage in specific contexts. In this exercise, we encourage triggering workflows in-context from the Service Activation WebUI, which requires adding the tag `sf-network-operation`. For more details, check the [Developer Portal](https://network.developer.nokia.com/learn/25_4/programming/workflows/workflow-manager-apis). + +### Intent Manager -In this activity we use NSP Workflow Manager to move SAPs from one port to a backup port. This can be useful -for activities like planned maintenance (card swap) or as temporary solution to quick fix a port that went -down. The workflow is expected to be triggered manually from the NSP WebUI. This exercise will focus on -**`redundant-eline`** and **`epipe`** services, but the implementation could be extended in context of -this hackathon to support other services like VPLS and VPRN. +Intent Manager is a module within the Nokia Network Services Platform (NSP) that enables intent-based networking (IBN) by translating higher-level objectives into automated network actions. It has the ability to abstract the complexity of network configuration by allowing operators to express what they want, rather than how to do it. + +By separating declarative intent configuration (including validation) from intent operations like audits and synchronization, Intent Manager enables CRUD operations with operational lifecycle and control. The sync operation is used for deploying changes into the network but also to reconcile network object configuration in cases of misalignment, while audits are used to identify misalignments including network configuration drift. + +The library of intent-types can be updated at runtime, while intent-types are developed in JavaScript using YANG-defined intent models. Using JavaScript enables full flexibility beyond pure configuration management. Intent Manager natively supports heterogeneous networks (multi-vendor, multi-domain). + +### Tools + +These capabilities are complemented by operator-facing tools that make automation accessible and integrated into daily workflows: + +* **NSP WebUI**: Manage workflows, intents, and services end-to-end in a graphical interface. +* **Visual Studio Code Plugin**: Author and validate workflows and forms locally, then publish directly to NSP, providing a smooth development experience. + +--- ## Tasks -**You should read these tasks from top-to-bottom before beginning the activity.** +### Validate Port Configuration -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +Ensure the following on PE1 and PE3: -### Ensure Port Configuration and Usage +- The breakout ports `1/1/c6` and `1/1/c8` exist +- Ports `1/1/c6/1` and `1/1/c8/1` are configured as access ports with dot1q encapsulation +- No critical conflicting services exist -In this activity we are planning to use ports `1/1/c6/1` and `1/1/c8/1` on **PE1** and **PE3**. -Port `1/1/c6/1` should be used for initial service configuration. -Port `1/1/c8/1` is about to become our backup port to move the configuration to. +Use NSP MDC or CLI to check and modify configurations. If conflicting services exist, either: -Execute the following steps on PE1 and PE3: +- Use a different port pair, or +- Remove the existing service if it's not required for this activity -* Check if the corresponding break-out ports `1/1/c6` and `1/1/c8` are setup. Configure if needed! -* Check if the ports `1/1/c6` and `1/1/c8` are setup as access port, with dot1q encap. Configure if needed! -* Check for pre-existing services, to avoid conflicts running this activity - -### Create an ELINE service +--- -Configure at least one service of type `redundant-eline` or `epipe` between PE1 to PE3 using port `1/1/c6/1`. -Ideally, you want multiple services to be created while even a mix of epipes and redundant elines is possible. +### Create a Sample Service + +Provision a service using NSP IBSF (Intent-Based Service Fulfillment): + +- Service type: `epipe` or `redundant-eline` +- Endpoint A: PE1, port `1/1/c6/1` +- Endpoint B: PE3, port `1/1/c6/1` + +Options: + +- Use NSP WebUI IBSF wizard +- Use Visual Studio Code Plugin (recommended for versioning and local validation) +- Use RESTCONF APIs directly (advanced) + +This service will later be migrated using the workflow. + +--- ### Create Workflows in NSP -Create the following two workflows in NSP. As NSP is shared across all hackathon labs, make sure using unique -names. Because the first workflow is calling the second as sub-workflow, make sure to apply the renaming -consistently. +Create two workflows using the YAML content provided below: + +- Main Workflow: `PortMigration_` +- Sub-Workflow: `PortMigrationSubworkflow_` + +Ensure: + +- Workflow tags include `sf-network-operation` +- Status is set to `PUBLISHED` +- Group ID is inserted in workflow names for uniqueness + +/// admonition | What are the workflows doing? + type: question +/// details | Answer + type: success +The main workflow queries intents on a specific port and calls the sub workflow to patch them with a backup port. The sub workflow builds the PATCH payload and executes RESTCONF operations. +/// +/// + +/// admonition | What changes are needed for other service types? + type: question +/// details | Answer + type: success +Add parsing and payload logic for other intent types (e.g., `vpls`, `vprn`) in the Python block of `generatePatchPayload`. +/// +/// -At this stage, we are providing you with full working examples of those workflows. +--- + +### Create Input Forms + +Use `AUTO GENERATE UI` in NSP to auto-fill basic input fields. Then manually enhance forms with the following example for `backupPort`: -/// tab | Main Workflow `PortMigration` ```yaml -version: '2.0' +- name: backupPort + title: BACKUP PORT + description: move all SAPs here + columnSpan: 4 + newRow: true + readOnly: false + required: true + type: string + component: + input: autoComplete + suggest: + action: nspWebUI.portList + name: + - name +``` + +This enables dynamic suggestions in the UI based on available NSP ports. + +--- + +### Pre-Migration Check + +Scenario: Migrate a service on PE1 from `1/1/c6/1` to `1/1/c8/1`. + +Using NSP WebUI, CLI, or MDC: + +- Confirm that the source port `1/1/c6/1` is in use by the service +- Ensure `1/1/c8/1` is configured and not already in use + +Only proceed once pre-checks validate the environment. + +--- + +### Run the Workflow via NSP + +1. Navigate to **NSP > Service Management** +2. Select an active service with SAPs on `1/1/c6/1` +3. Click the 3-dot menu and choose **Execute Workflow** +4. Select your custom `PortMigration_` workflow +5. Enter inputs based on your validation: +```yaml +neId: PE1 +port: 1/1/c6/1 +backupPort: 1/1/c8/1 +intentType: redundant-eline +intentTypeVersion: 2 +``` +6. Click **Run** + +--- + +### Validate Migration + +After execution, verify: + +- Service intent now references `1/1/c8/1` +- Old SAP on `1/1/c6/1` has been removed + +Use NSP Service Management view, RESTCONF API, or CLI output to confirm. + +--- + +## Summary -PortMigration: +Congratulations — you’ve completed this activity! Take a moment to look back at what you achieved: + +* Prepared port configurations +* Deployed a test `epipe` or `redundant-eline` service +* Built and published NSP workflows +* Customized workflow UI forms +* Executed a migration through Service Management +* Verified SAP movement to the backup port + +You’ve now seen how NSP simplifies port migration through reusable automation. + +## Next Steps + +If you’d like to explore further, you could: + +* Extend the logic to support `vpls` or `vprn` services +* Add rollback handling in case of a PATCH failure +* Consolidate the subworkflow into the main workflow + +This gives you the chance to deepen your understanding and push NSP workflows even further. + +--- + +## Full YAML Workflows + +/// note +Remember, your NSP system is shared! Don't just copy paste the workflows below! Ensure to replace `` with the id of your group to avoid conflicts with other groups executing the same activity. +/// + +### Main Workflow: PortMigration + +```yaml +version: '2.0' +PortMigration_: type: direct - - description: to be added by you - + description: Migrate SAPs from source port to backup port + tags: + - sf-network-operation input: - neId - port @@ -113,7 +274,7 @@ PortMigration: patchIntentServices: with-items: intent_data in <% $.service_data %> concurrency: 5 - workflow: PortMigrationSubworkflow + workflow: PortMigrationSubworkflow_ input: neId: <% $.neId %> port: <% $.port %> @@ -135,13 +296,13 @@ PortMigration: status: "success" message: <% str($.patchIntentStatus) %> ``` -/// -/// tab | Sub Workflow `PortMigrationSubworkflow` +### Sub-Workflow: PortMigrationSubworkflow + ```yaml version: '2.0' -PortMigrationSubworkflow: +PortMigrationSubworkflow_: type: direct description: to be added by you @@ -269,124 +430,4 @@ PortMigrationSubworkflow: port: <% $.port %> backupPort: <% $.backupPort %> service-name: <% $.svcInfo.target %> -``` -/// - -Study both workflows carefully! - -/// admonition | Questions - type: question -What are the workflows doing and how do they interact? -Update the workflow descriptions accordingly! - -/// details | Solution - type: success -The first workflow is the main workflow to be called by the operator. It consumes the -node, the port and the backup port. It calls the Intent Manager RESTCONF API to get -the list of all SAPs terminating on the node/port provided. It calls the 2nd workflow -as sub-workflow with a concurrency of 5 executions. - -The 2nd workflow is doing the actual SAP migration, one intent-instance at a time. - -As the first workflow requires intent-type and version as input, if there is a mix -of service intent-types being used, the script may need to be called multiple times. -/// - -Would those workflows support other service-types but `redundant-eline` or `epipe`? -What would need to be changed to make it work for other service-types? - -/// details | Solution - type: success -Dependencies exist mainly in the 2nd workflow, as the API calls to -migrate services require adjustments based on the service-type. -/// -/// - -/// tip -We want to execute the `PortMigration` workflow from the **Service Management** -application in NSP. That's why the workflow must be labeled correctly using the -**`sf-network-operation`** tag. -/// - -Edit the `PortMigration` workflow and ensure the following tag is present: - -```yaml - tags: - - sf-network-operation -``` - -Feel free to add other tags! - -**Don't forget to update the status from `DRAFT` to `PUBLISHED`!** - -### Generate input forms - -To improve usability, generate input-forms. Give it a start using the `AUTO GENERATE UI` button. -There are some rules in place, that auto-render the form based on attribute-names and default-values. - -In the given examples, the auto-generator does not work for `BACKUP PORT`and `INTENT TYPE VERSION`. -Consider using `PORT` as template to come up with your own definition of `BACKUP PORT`. - -/// details | Possible solution (only look here as a last resort!) - type: success - -```yaml - - name: backupPort - title: BACKUP PORT - description: move all SAPs here - columnSpan: 4 - newRow: true - readOnly: false - required: false - type: string - component: - input: autoComplete - suggest: - action: nspWebUI.portList - name: - - name -``` -/// - -### Simulate a Port Down Scenario - -* Ensure a service (`redundant-eline` or `epipe`) is provisioned with SAP on a port like `1/1/c6/1` -* The corresponding node (e.g., `PE1`) must have a backup port available (e.g., `1/1/c8/1`) - -### Run the Workflow via Service Management - -1. Go to **NSP > Service Management** -2. Find and select an existing service instance -3. Click `⋮` (3-dot menu) > **Execute Workflow** -4. Choose `PortMigration` from the list (use your custom name!) -5. Fill in the inputs: - -| Field | Description | -| --------------------- | ------------------------------------------------------- | -| `NE ID` | Source port to be retired (`1/1/c6/1`) | -| `PORT` | Node where port exists (`PE1`) | -| `BACKUP PORT` | New port to migrate SAPs to (e.g., `1/1/c8/1`) | -| `INTENT TYPE` | Set to `redundant-eline` | -| `INTENT TYPE VERSION` | Typically `2` or `3`, depending on the deployed service | - -6. Click **Run** - -### Validate the Outcome - -* Check using `Service Management` -* Ensure all SAPs have been moved to the backup port (`1/1/c6/1` ==> `1/1/c8/1`) - -### Bonus - -Here some additional ideas on how to continue: - -* Try to run the sub-workflow directly -* Run the python-code outside WFM to test changes in isolation -* Further optimize the input (auto-pick intent-type-version) -* Generate a HTML/PDF report, which SAPs have been migrated -* Implement a dry-run option, to validate which services/saps would be affected -* Extend the workflows to support other service-types like ELAN or L3VPN -* Combine both workflows into a single one -* Maximize experience: Ask for NE, port and backup-port only! Migrate all services found! -* Trigger the workflow automatically, based on kafka events (port-down alarm raised on topic `nsp-fm-alerts`) -* Rollback configuration changes, if PATCH failed \ No newline at end of file +``` \ No newline at end of file diff --git a/docs/nsp/intermediate/66-nsp-ne-password-audit.md b/docs/nsp/intermediate/66-nsp-ne-password-audit.md index 34289f6..390c05d 100644 --- a/docs/nsp/intermediate/66-nsp-ne-password-audit.md +++ b/docs/nsp/intermediate/66-nsp-ne-password-audit.md @@ -2,104 +2,105 @@ tags: - NSP - Workflow Manager - - Device Operations + - Device Operation + - LSO (Large Scale Operation) - Artifact Manager ---- +--- # Network Element Password Audit and Alignment | | | | --- | --- | -| **Activity name** | Network Element (NE) Password Audit and Alignment | +| **Activity name** | Network Element Password Audit and Alignment | | **Activity ID** | 66 | | **Short Description** | Audit the NE user password and align to the target password if misaligned | | **Difficulty** | Intermediate | -| **Tools used** | | -| **Topology Nodes** | :material-router: PE1 | -| **References** | | +| **Topology Nodes** | any SR OS node | +| **References** | [LSO Framework](https://network.developer.nokia.com/learn/24_11/network-functions/device-management/lsom-framework-apis/#Guidelines), [Workflow Development](https://network.developer.nokia.com/learn/25_4/programming/workflows/wfm-workflow-development/), [RFC8072 (YANG PATCH)](https://www.rfc-editor.org/rfc/rfc8072.html) | -## Objectives +## Objective -Design, implement and test a custom two-phase **Device Operations** using the NSP Large-Scale Operations Manager (LSOM) framework to manage and synchronize NE user passwords. +You need a reliable way to enforce your organization’s passwords on many devices—without manual spot checks, risky ad-hoc fixes, or “hope it’s compliant” assumptions. In this activity, you’ll use a custom, two-phase **Device Operation** built on NSP’s **Large-Scale Operation Manager (LSOM)** to: -## Technology Overview +* **Detect** non-compliant device user passwords at scale (validation phase). +* **Reconcile** only where needed, safely and predictably (fix phase). -**Device Operations** are part of the NSP *Device Management*, designed to support a wide range of operations including Audits, Backups/Restores and Software Upgrades. -To enable customizability, those operations are running programmable **workflows**, while LSOM orchstrates the execution of those workflows while improving the operational -experience by adding progress monitoring and execution control. +The outcome is a repeatable, operator-friendly control you can run on any set of targets nodes to continuously check and enforce device-level passwords to be set correctly and update if needed. -The target of any operation are devices, which depending on the use-case can be either a single network element or multiple. -Consequently, every workflow associated with an operation includes the `ne-id` (device identifier) as required input. -In our scenario, since we're managing nodal users, `username` and `password` become additional input parameters. +## Technology explanation -Our automation activity will require 3 artifacts to be created… -First, there is a workflow to audit the current password of the NE user to check for misaligments. -Second, there is another workflow to realign the user password in case there was a mismatch. -Third, there is the operation, bringing everything together. +**Device Operation** in NSP are tools that help manage network devices. They can do many things, like checking device settings, making backups, restoring data, or upgrading software. -Finally, to simplify the transfer and installation of these 3 artifacts that belong together, -you will package everything together becoming an `artifact bundle`. +These operations run through workflows — think of them like step‑by‑step instructions. Another part of NSP, called LSOM, oversees running those workflows, keeping track of their progress, and giving you control over when and how they run. -## Artifact Bundle +An operation always targets one or more devices. To run it, the workflow needs to know the device’s ID (called `ne-id`). In our case, since we’re managing device user accounts, we also need a `username` and `password`. -To implement the device operation that orchestrates multiple workflows, the operation must adhere to a prescribed directory structure. -Each file and component within this structure fulfills a specific function ensuring clean modularity between the execution logic and the user interface definition. +For our automation, we need to create three things: -| Path | Description | -|------------------------------------------------------------------------------------|-------------------------------------------------------------------| -| `metadata.json` | **Artifact Bundle meta-data** | -| `workflows/` | **Directory for workflows** | -| \|__`audit-misaligned-pass/` | | -|       \|__`audit-misaligned-pass-<< groupId >>.yaml` | Workflow #1 to audit the NE password | -| \|__`force-update-pass/` | | -|       \|__`force-update-pass-<< groupId >>.yaml` | Workflow #2 to realign the password if misalignment exists | -| `operation-types/` | **Directory for operation-types** | -|       \|__`operation_types.json` | Operation-type meta information | -|       \|__`misaligned-pass-<< groupId >>.yang` | Operational model (in YANG) defining operation input and output | -|       \|__`misaligned-pass-<< groupId >>.yaml` | Mapping profile: Defines phases with workflow references | +1. A workflow to check if a device user’s password is correct. +2. A workflow to fix the password if it’s wrong. +3. An operation that ties these workflows together so they can be run easily. -/// warning +To make sharing and installing these three parts simple, we’ll put them all together into one package called an **Artifact Bundle**. + +The YAML syntax for writing workflows is very intuitive, as it uses simple English expressions to describe the execution and data flow including conditional statements. Please study the workflow code carefully to get used to the syntax and principles, soon you will write your first own workflow. + +### Artifact Bundle +To build a device operation that runs multiple workflows, you need to follow a specific directory structure. Each file and folder in this structure has its own purpose, keeping the execution logic separate from the user interface so everything stays clean and well‑organized. + +| Path | Description | +|-----------------------------------------------------|-------------------------------------------------------------------| +| `metadata.json` | **Artifact Bundle meta-data** | +| `workflows/` | **Directory for workflows** | +| `|__audit-misaligned-pass/` | | +| ` |__audit-misaligned-pass-<< GroupId >>.yaml` | Workflow-1 to audit the NE password | +| `|__force-update-pass/` | | +| ` |__force-update-pass-<< GroupId >>.yaml` | Workflow-2 to realign the password if misalignment exists | +| `operation-types/` | **Directory for operation-types** | +| ` |__operation_types.json` | Operation-type meta information | +| ` |__misaligned-pass-<< GroupId >>.yang` | Operational model (in YANG) defining operation input and output | +| ` |__misaligned-pass-<< GroupId >>.yaml` | Mapping profile: Defines phases with workflow references | + +/// warning The YANG-defined operation input (and output) is provided and persisted in clear-text. As this applies to every field regardless of confidentiality, having user passwords unencrypted impacts applicability for production environments. /// ## Tasks +**You should read these tasks from top-to-bottom before beginning the activity.** + +It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. + /// warning -Remind, that you are using a single NSP system (shared), that is used for all groups. Therefore, ensure +Remember that you are using a single shared NSP system that is used for all groups. Ensure your group-number is part of the operation and workflow names you are creating to ensure uniqueness. /// -**You should read these tasks from top-to-bottom before beginning the activity.** +### Getting started + +Creating things from scratch can feel daunting and even overwhelming. To save you from piecing together all the required components that define the structure and format of an operation, we provide you with a [LSO Skeleton Bundle Generator](./resources/bundle-generate-66.html). This tool creates an artifact bundle in the exact structure expected by the system, giving you a ready-made starting point. From there, you can easily build upon it and move on to more advanced use cases. -It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. +### Password Audit Workflow -### Workflow 1 - Password Audit +Part of monitoring local user configuration in a network element is being able to audit what is there. Let's create the workflow to audit the NE user password. -First, lets create the workflow to audit the NE user password. The general flow is the following: 1. Retrieve the current password from the NE 2. Compare it to the configured target password 3. Generate an audit result indicating compliance or deviation -NSP Workflow Manager user OpenStack Mistral, while we've added a lot of actions and expressions to tailor it for network automation. -[Click here](https://network.developer.nokia.com/learn/24_11/programming/workflows) for a quick starter guide on writing workflows. - -To keep things efficient, we are providing you with the complete workflow code. - -/// details | Possible solution (only look here as a last resort!) - type: success +To keep things efficient, we are providing you with the complete workflow code in the box below. -/// note -Keep in mind that this workflow execution is intended to fail if the password is a match (or aligned) while it is expected to succeed if there is a misalignment. The reason behind this change is to faciliate the LSO flow to transition from Audit to Align phase. -/// +/// details | Workflow code + type: note ```yaml version: '2.0' -audit-misaligned-pass-<>: +audit-misaligned-pass-<>: tags: - LSO @@ -110,15 +111,16 @@ audit-misaligned-pass-<>: output: lsoInfo: <% $.lsoInfo %> ## mandatory output for LSO operations - misaligned: <% $.misaligned %> ## mandatory output leaf parameter defined in misaligned-pass.yang + misaligned: <% $.misaligned %> ## mandatory output leaf parameter defined in misaligned-pass.yang output-on-error: lsoInfo: <% $.lsoInfo %> ## mandatory output for LSO operations for errors - misaligned: <% $.misaligned %> ## mandatory output leaf parameter defined in misaligned-pass.yang + misaligned: <% $.misaligned %> ## mandatory output leaf parameter defined in misaligned-pass.yang vars: lsoInfo: Failed lsoStageError: Unknown ## mandatory for LSO operations stage level errors + misaligned: "no" tasks: checkUsernameIsAdmin: @@ -135,7 +137,7 @@ audit-misaligned-pass-<>: getAdminPass: ## access the configured hashed password via MDC API action: nsp.https - input: + input: url: https://restconf-gateway/restconf/data/network-device-mgr:network-devices/network-device=<% $.neId %>/root/nokia-conf:/configure/system/security/user-params/local-user/user=<% $.username %> resultFilter: $.content.get("nokia-conf:user").first().password publish: @@ -172,37 +174,26 @@ audit-misaligned-pass-<>: lsoInfo: "Info: Password of <% $.username %> user is aligned" lsoStageError: Password of <% $.username %> user is aligned ``` + +/// note +Keep in mind that this workflow is intended to fail if the password matches and succeed if it does not. This ensures the Operation Manager multi-phase transition from Audit to Align: a mismatch triggers progression to the align phase, while a match halts it since no action is needed. Though logical, this may feel counterintuitive—success on mismatch and failure on match. +/// + /// -The YAML syntax for writing workflows is very intuitive, as it uses simple English expressions to describe the -execution and data flow including conditional statements. Please study the workflow code carefully, to get used -to the syntax and principles, as soon you will write your first own workflow. - -Observations: - -* Some specific rules apply to make the workflow fit the needs of LSO. Have a look, how the environment/output variables - `lsoInfo` and `lsoStageError` are used. Those variables provide a feedback loop to *Device Operations* to understand - execution progress and reasoning of the result. -* NSP uses the `admin` user for mediation (CLI, xFTP, NETCONF and gRPC). As we don't want to break your lab, an initial - check is done to avoid updating the admin users password by accident. -* The workflow input needs to fit the needs of the operation, so it needs to match the operation model (while values - could also be statically set in the mapping profile). -* The general logic in LSOM is, that only target that have successfully passed one phase are considered for the execution - of the next phase(s). That's why, we need to be careful about the execution state we are returning. If and only if the - check was executed successfully, but we found a misalignment, the workflow will return `success`. Aka, the target device - would be selected for the next phase, to realign the password. In all other cases, like if the password was aligned, we - mark the target as `failed` and the target would not be considered for realignment of the password. +A few observations worth noting: + +* Some specific rules need to be adhered to for the workflow to be valid LSO. Have a look at how the variables `lsoInfo` and `lsoStageError` are used. Those variables provide a feedback loop to *Device Operations* to understand execution progress and reasoning of the result. +* NSP uses the `admin` user for mediation (CLI, xFTP, NETCONF and gRPC). As we don't want to break your lab, an initial check is done to avoid updating the admin user's password by accident. +* The workflow input must fit the needs of the operation, so it needs to match the operation model. Alternatively, values could be set statically in the mapping profile. +* The general logic in LSO is that only targets that have successfully passed one phase are considered for the execution of the next phase(s). That's why we need to think carefully about the returned execution state. If and only if the check was executed successfully and we found a misalignment will the workflow return `success`. In other words, only then would the target device be selected for the next phase to realign the password. In all other cases (password was aligned already, workflow failed) the target is marked as `failed` and it would not be considered for realignment of the password. /// note | Give it a try! -You don't need to wait until everything comes together as operation, you can try out the workflow right now. -You may user either NSP WebUI or Visual Studio Code (or code-server) with the NOKIA WFM extension to create -and run the workflow. For now, you can use the `admin` user, but ideally you can already create another NE -user like `nsptest`. -/// +You don't need to wait until everything comes together as an operation. You can try out the workflow right now. You may use either the NSP WebUI or Visual Studio Code (or code-server) with the NOKIA WFM extension to create and run the workflow. For now, you can use the `admin` user, but ideally you can already create another NE user like `nsptest` on your targeted SR OS node. -/// details | Want to create a NE user using MD-CLI? - type: tip +/// details | Creating a local user using MD-CLI in SR OS + type: hint ```bash edit-config private @@ -210,39 +201,31 @@ configure system security user-params local-user user nsptest password t0ps3creT commit ``` -Same could be used to update the user password at any time. +You can use the same approach to update the user password to test your implementation. /// +/// + +### Password Update Workflow -### Workflow 2 - Update/Align User Password +Now that we know when users are in violation of our organization's password policy, we need to automate remedying that situation. -Now that you are familiar with the mechanics and structure of workflows, turn is on you to create the second workflow all -by yourself. While the first workflow was about identifying misalignments, the second workflow is update the NE user -password to match the provided password. +Having familiarity with the mechanics and structure of workflows, it is your turn to create the second workflow. While the first workflow identifies password rule violations, the second workflow can update configured NE user passwords with a password that is specified as input. -Create a workflow called force-update-pass-`<>`. You may user either NSP WebUI or Visual Studio Code (or code-server) -with the NOKIA WFM extension to create and run the workflow. Test your workflow properly before you continue! +Create a workflow called `force-update-pass-<>`. You may user either NSP WebUI or Visual Studio Code (or code-server) with the NOKIA WFM extension to create and run the workflow. Test your workflow properly before you continue! /// details | Hint type: tip -1. In the first workflow we've used the NSP RESTCONF API to access the device using the device model. - In MD-CLI you may use `info json` and `pwc model-path` to help constructing the resource URI and - the body payload. But it might be even simpler: The URI from reading the user password contains - all details to construct the corresponding write request. -2. In RESTCONF there are multiple ways to update the password. You may decide to use HTTP PUT, to - **replace** the current password value. You may use HTTP PATCH, to **merge** it. The most - flexible way is using **YANG PATCH** (RFC8072). -3. To execute a RESTCONF call, ultimately you can use WFM action `nsp.https`. -4. If you feel more comfortable usign CLI you may consider using `nsp.mdm_cli`. - -We provide you with a working, but only look there if you totally get stuck as last resort! -Try to figure it out yourself, and if you hit a roadblock ask the hackathon support team. -Remind, the provided working example is not the only solution possible. You are free to use the -[nsp.mdm_cli](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-workflow-actions) -action which would perform the same usign CLI commands. Or why not getting used to the NETCONF protocol -using action [netconf.configure](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-workflow-actions)? - -Whatever path you go, if **your code** works, that's great while you've achieved something! +1. While you can use MD‑CLI commands like `info json` and `pwc model-path` to help build the resource URI and payload, it’s often easier to check the workflow you already have — the URI it uses contains everything needed for your write request. +2. In RESTCONF there are multiple ways to update the password. You may decide to use HTTP PUT, to **replace** the current password value. You may use HTTP PATCH, to **merge** it. The most flexible way is using **YANG PATCH**. +3. Use the WFM action `nsp.https` to execute a RESTCONF call from the workflow. + +If you feel that you are hitting a roadblock in your development of this second workflow you can ask the hackathon support team for some advice. There are many possible solutions using various approaches for contacting the node, what matters in the end is the functionality of your code. + +Remember, the provided working example is not the only possible solution. You are free to use the [nsp.mdm_cli](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-workflow-actions) action which would perform the same using CLI commands. Or look at the NETCONF protocol with action [netconf.configure](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-workflow-actions). + +Whatever path you end up taking, once your code works the foundation has been laid, you'll have learned some new skills and will be able to build from there. + /// /// details | Possible solution (only look here as a last resort!) @@ -251,7 +234,7 @@ Whatever path you go, if **your code** works, that's great while you've achieved ```yaml version: '2.0' -force-update-pass-<>: +force-update-pass-<>: tags: - LSO @@ -289,7 +272,7 @@ force-update-pass-<>: updateAdminPass: ## update the NE User password using MDC API action: nsp.https input: - method: PATCH + method: PATCH url: https://restconf-gateway/restconf/data/network-device-mgr:network-devices/network-device=<% $.neId %>/root/ accept: application/yang-data+json contentType: application/yang-patch+json @@ -313,28 +296,37 @@ force-update-pass-<>: ``` /// -Now that we have learnt and tried how to audit and force update NE password misalignments individually, lets see how to combine them into a single operation. +Now that we have automated auditing and updating NE password configuration individually, let's see how to combine that into a single operation. ### Operation Type -First part of creating an LSO operation is defining the operation type. This is done as part of the operation_types.json +The first part of creating an operation in the LSOM framework is defining the operation type. -/// details | operation_types.json - type: success +| **Key** | **Description** | +|----------------------|------------------------------------------------------------------| +| `name` | Same as the bundle name | +| `description` | Short description | +| `category` | Operation type category (`other`, `backup`, `restore`, `upgrade`) | +| `created-by` | Created by (e.g., `nsp_internal_system_user`) | +| `operation-model` | `.yang` | +| `profile` | `.yaml` | +| `life-cycle-state` | Release status (`draft`, `released`, `withdrawn`) | +| `additional-tag` | Customs tags, e.g., `["LSO", "SR OS"]` | +| `version` | Version number in `x.y.z` format (e.g., `1.0.0`) | -/// warning -Code comments are defined purely for readability. Make sure the comments are removed when saving the file. -/// + +/// details | `operation_types.json` + type: success ```json { "operation-type": { - "name": "misaligned-pass-<< groupId >>", // same as the bundle name - "description": "Operation for Misaligned Pass << groupId >>", // short description - "category": "other", // default (do not change) - "created-by": "nsp_internal_system_user", // default (do not change) - "operation-model": "misaligned-pass-<< groupId >>.yang", // .yang - "profile": "misaligned-pass-<< groupId >>.yaml", // .yaml + "name": "misaligned-pass-<< GroupId >>", + "description": "Operation for Misaligned Pass << GroupId >>", + "category": "other", + "created-by": "nsp_internal_system_user", + "operation-model": "misaligned-pass-<< GroupId >>.yang", + "profile": "misaligned-pass-<< GroupId >>.yaml", "life-cycle-state": "released", "additional-tag": ["LSO", "SR OS"], "version": "1.0.0" @@ -346,44 +338,38 @@ Code comments are defined purely for readability. Make sure the comments are rem ### Operation Input-Output -Regardless of whether the operation is single-phase or multi-phase, all phases share the same input and output parameters. -If you believe a particular phase does not require certain inputs, default values can also be defined within the phase -definition itself (which we’ll cover in the next section). +Regardless of whether the operation is single-phase or multi-phase, all phases share the same input and output parameters. If you believe a particular phase does not require certain inputs, default values can also be defined within the phase definition. We will cover this in the next section. /// note -The input and output for any LSO operation are defined using YANG format. +The input and output of any LSO operation are defined in YANG. /// /// details | Hint type: tip -When creating the operation's YANG file, keep the following points in mind: +When updating the operation's YANG file which was already generated using the [LSO Skeleton Bundle Generator](#getting-started), keep the following points in mind: 1. The module name, prefix, and the final segment of the namespace (after the colon) must all match. -2. The when clause of the augment statement, the value being compared should always be the module name. +2. In the `when` clause of the augment statements, the value being compared should always be the module name. 3. Only the container elements within the two augment sections should be modified based on the specific requirements. /// -/// details | misaligned-pass`-<< groupId >>`.yang +/// details | `misaligned-pass-<< GroupId >>.yang` type: success -/// warning -Code comments are defined purely for readability. Make sure the comments are removed when saving the file. -/// - ```yang -module misaligned-pass-<< groupId >> { +module misaligned-pass-<< GroupId >> { yang-version 1.1; - namespace "urn:nokia:nsp:model:lso:operation:misaligned-pass-<< groupId >>"; - prefix misaligned-pass-<< groupId >>; + namespace "urn:nokia:nsp:model:lso:operation:misaligned-pass-<< GroupId >>"; + prefix misaligned-pass-<< GroupId >>; - import nsp-lso-operation { // dont not change + import nsp-lso-operation { prefix nlo; } - organization "Nokia"; // dont not change + organization "Nokia"; contact ""; - description "Operation for Misaligned Pass"; // same short description as provided in operation_types.json + description "Operation for Misaligned Pass"; revision 2024-10-08 { description "version 1"; @@ -391,9 +377,9 @@ module misaligned-pass-<< groupId >> { } augment "/nlo:lso-operations/nlo:operation" { - when "operation-type='misaligned-pass-<< groupId >>'"; // compare parameter has to be the module name always + when "operation-type='misaligned-pass-<< GroupId >>'"; description "Augmentation of operation input"; - container misaligned-pass-<< groupId >>-operation { // syntax: -operation + container misaligned-pass-<< GroupId >>-operation { leaf username { type string; mandatory true; @@ -408,9 +394,9 @@ module misaligned-pass-<< groupId >> { } augment "/nlo:lso-operations/nlo:operation/nlo:executions/nlo:execution" { - when "../../operation-type='misaligned-pass-<< groupId >>'"; // compare parameter has to be the module name always + when "../../operation-type='misaligned-pass-<< GroupId >>'"; description "Augmentation of operation execution state data"; - container misaligned-pass-<< groupId >>-execution { // syntax: -execution + container misaligned-pass-<< GroupId >>-execution { leaf misaligned { type string; description "Indicates misalignment of password"; @@ -422,38 +408,52 @@ module misaligned-pass-<< groupId >> { /// -With the operation's input & output defined lets see how we define the phase. +With the operation's input and output defined let's see how we specify the operation's phases. ### Operation Phases -/// details | misaligned-pass`-<< groupId >>`.yaml +This section defines the phases used in the Operation Type execution. It includes the phase name, description, concurrency limits, supported NE families and versions as well as the workflow triggered during each phase. + +| **Key** | **Description** | +|-----------------------|---------------------------------------------------------------------------------------------| +| `phase` | Phase name (e.g., `Audit`) — also indicates phase order | +| `description` | Description of what the phase does | +| `concurrency_count` | Number of NEs on which the phase can run concurrently | +| `phase_timeout` | Timeout for the phase (in minutes) | +| `ne_families` | NE families on which this workflow phase can be executed (list) | +| `|__family_type` | Specific NE family types (e.g., `7750 SR, 7950 XRS, 7450 ESS, 7250 IXR`) | +| `|__ne_versions` | Version information for the NE family (list) | +| ` |__version` | Specific NE version supported (e.g., `all`) | +| ` |__workflow_name` | Workflow to be called when executing this phase | +| ` |__workflow_inputs` | Workflow inputs (leave empty if not required) | + + +/// details | `misaligned-pass-<< GroupId >>.yaml` type: success ```yaml phases: - - phase: Audit ## Phase 1 + - phase: Audit description: Audit for misaligned Admin user password - concurrency_count: 20 ## No. of NE on which the phase can run concurrently + concurrency_count: 20 phase_timeout: 15 ne_families: - - family_type: 7750 SR, 7950 XRS, 7450 ESS, 7250 IXR ## NE family on which this WF phase can be executed on + - family_type: 7750 SR, 7950 XRS, 7450 ESS, 7250 IXR ne_versions: - version: all - workflow_name: audit-misaligned-pass-<< groupId >> ## workflow to be called on the execution of this phase - workflow_inputs: ## not default inputs (leave it empty) + workflow_name: audit-misaligned-pass-<< GroupId >> + workflow_inputs: ``` /// -Now that we're familiar with writing the Audit phase, I'll let you work out how to construct the Update/Align phase. +Now that we're familiar with writing the Audit phase, it is left up to you as an exercise to construct the Update phase. This phase is like the Audit phase shown above. /// details | Possible solution (only look here as a last resort!) type: success -/// details | Update/Align Phase - ```yaml - - phase: Update ## Phase 2 + - phase: Update description: Force update Admin user password concurrency_count: 20 phase_timeout: 15 @@ -461,24 +461,41 @@ Now that we're familiar with writing the Audit phase, I'll let you work out how - family_type: 7750 SR, 7950 XRS, 7450 ESS, 7250 IXR ne_versions: - version: all - workflow_name: force-update-pass-<< groupId >> + workflow_name: force-update-pass-<< GroupId >> workflow_inputs: ``` - -/// /// -Now that we've created all the files related to the LSO operation, let's consolidate this information into an operation metadata file. This file enables NSP to verify the integrity of the operation file and determine the target application onto which the files should be deployed. +Now that we've created all the files related to the LSO operation, let's consolidate this information into an operation metadata file. This file enables NSP to verify the integrity of the operation package and determine the target application onto which the files should be deployed. ### Operation Metadata -/// details | metadata.json +This section defines the **metadata and artifact details** required for the Device Operation. It describes the versioning scheme, creation details, and the list of files included in the artifact, along with their format and purpose. + +| **Key** | **Description** | +|--------------------------------|-------------------------------------------------------------------| +| `meta-data-header` | Metadata container for information describing the operation type | +| `|__version` | Version of the operation type in `x.y.z` format (e.g., `1.0.0`) | +| `|__buildNumber` | First number from the `version` (e.g., `1` from `1.0.0`) | +| `|__formatVersion` | First two parts of the `version` (e.g., `1.0` from `1.0.0`) | +| `|__createdBy` | Created by | +| `|__creationDate` | Date and time of creation (UTC) | +| `|__title` | Operation Type title | +| `|__description` | Short description of the Operation Type | +| `artifact-meta-data` | List of artifacts used by this operation | +| `|__name` | Name of the operation type or workflow artifact | +| `|__version` | Version of the artifact in `x.y.z` format (e.g., `1.0.0`) | +| `|__targetApplication` | Target application (e.g., `lsom-server-app`, `workflow-manager`) | +| `|__applicationCompatibility` | NSP release version from which the operation can be executed | +| `|__artifact-content` | List of files included in the artifact | +| ` |__fileName` | File name of the artifact | +| ` |__path` | Path inside the package where the file is stored | +| ` |__type` | MIME type of the file (e.g., `application/octet-stream`) | + + +/// details | `metadata.json` type: success -/// warning -Code comments are defined purely for readability. Make sure the comments are removed when saving the file. -/// - ```json { "meta-data-header": { @@ -487,23 +504,23 @@ Code comments are defined purely for readability. Make sure the comments are rem "formatVersion": "1.0", "createdBy": "SRX Hackathon 2025", "creationDate": "Tue, 06 May 2024 00:00:00 UTC", - "title": "Operation for Misaligned Pass << groupId >>", // Operation Type title - "description": "Operation for Misaligned Pass" // short description of Operation Type + "title": "Operation for Misaligned Pass << GroupId >>", + "description": "Operation for Misaligned Pass" }, "artifact-meta-data": [ { - "name": "misaligned-pass-<< groupId >>", - "version": "1.0.0", // same as the version in meta-data-header - "targetApplication": "lsom-server-app", // mandatory do not change - "applicationCompatibility": "23.3+", // NSP release from which the operation can be executed on + "name": "misaligned-pass-<< GroupId >>", + "version": "1.0.0", + "targetApplication": "lsom-server-app", + "applicationCompatibility": "23.3+", "artifact-content": [ { - "fileName": "misaligned-pass-<< groupId >>.yaml", + "fileName": "misaligned-pass-<< GroupId >>.yaml", "path": "operation-types", "type": "application/octet-stream" }, { - "fileName": "misaligned-pass-<< groupId >>.yang", + "fileName": "misaligned-pass-<< GroupId >>.yang", "path": "operation-types", "type": "application/octet-stream" }, @@ -515,26 +532,26 @@ Code comments are defined purely for readability. Make sure the comments are rem ] }, { - "name": "audit-misaligned-pass-<< groupId >>", + "name": "audit-misaligned-pass-<< GroupId >>", "version": "1.0.0", - "targetApplication": "workflow-manager", // mandatory do not change + "targetApplication": "workflow-manager", "applicationCompatibility": "23.3+", "artifact-content": [ { - "fileName": "audit-misaligned-pass-<< groupId >>.yaml", + "fileName": "audit-misaligned-pass-<< GroupId >>.yaml", "path": "workflows/audit-misaligned-pass", "type": "application/octet-stream" } ] }, { - "name": "force-update-pass-<< groupId >>", + "name": "force-update-pass-<< GroupId >>", "version": "1.0.0", - "targetApplication": "workflow-manager", // mandatory do not change + "targetApplication": "workflow-manager", "applicationCompatibility": "23.3+", "artifact-content": [ { - "fileName": "force-update-pass-<< groupId >>.yaml", + "fileName": "force-update-pass-<< GroupId >>.yaml", "path": "workflows/force-update-pass", "type": "application/octet-stream" } @@ -546,22 +563,26 @@ Code comments are defined purely for readability. Make sure the comments are rem /// -### Execution +### Build & Installation + +We now have all the necessary files and directories in place to proceed uploading the LSO operation we have created to NSP. -Now that we have all the necessary filed and directory structure in place, +To do that, perform the following: -1. Lets ZIP the directory content and install the package into NSP using the Artifact Admin Application. -2. Rename the file to misaligned-pass-<< groupId >>.zip -3. Once the Artifact has been installed. go to the Device Management App. -4. From the dropdown select All Operations and create a new Operation from `+OPERATION` button on top right. -5. Provide in the necessary input and click Run. +/// details | Target directory structure (sample for Group 4) +![execution](./images/66-ne-password/directory-struct.png) +/// + +1. Let's ZIP the directory content (not the directory itself). +2. Rename the file to `misaligned-pass-<< GroupId >>.zip` +3. Install the package into NSP using the Artifact Administrator WebUI. /// warning -If you are compressing to zip on MacOS, run the following commands to remove unnecessary system files: +If you are zipping the files on MacOS, run the following commands to remove unnecessary system files: ```bash -zip -d Archive.zip __MACOSX/\* -zip -d Archive.zip \*/.DS_Store +zip -d misaligned-pass-<< GroupId >>.zip __MACOSX/\* +zip -d misaligned-pass-<< GroupId >>.zip \*/.DS_Store ``` /// @@ -569,16 +590,30 @@ zip -d Archive.zip \*/.DS_Store ![execution](./images/66-ne-password/execution.png) /// -## Summary and review +/// note +If you’re having trouble building the bundle with the correct content and directory structure, use the [Complete LSO Bundle Generator](./resources/bundle-generate-66.html?kind=complete) to create a fully‑structured bundle with all required contents. +/// + +### Execution + +0. Create a new user `nspuser` on both PE1 and PE2 using random passwords. +1. After the artifact installation is complete, open the Device Management application. +2. From the dropdown menu, select `All Operations`, then create a new operation by clicking the `+ OPERATION` button in the top-right corner. +3. Execute the audit/realign operation on PE1 and PE2. +4. Verify the operation results and confirm the device passwords. +5. Modify the password on PE1 only. +6. Execute the audit/realign operation again. +7. Check the operation results and verify the device passwords once more. + +Expected result: Any password misalignment is detected and automatically corrected. -Congratulations! If you have got this far you have completed this activity and achieved the following: +## Summary -* You have learnt how to write Workflows -* You have learnt how to combine workflows to make an LSO Operation -* You have learnt to build NSP Artifacts -* You have learnt how to use RESTCONF APIs to interact with MD nodes managed in NSP -* You have worked with YANG modeled data +Congratulations — you’ve completed this activity! Take a moment to reflect on what you achieved: -This is a pretty extensive list of achievements! Well done! +* Built and packaged NSP workflows into an Artifact Bundle +* Combined validation and remediation logic into a single Device Operation +* Enforced password compliance across devices through LSOM-managed execution +* Interacted with devices using YANG-modeled data and RESTCONF APIs -If you're hungry for more feel free to explore the same activity for an SRL node. +You now have a reusable control that keeps device credentials in line with policy, backed by automation you can trust. diff --git a/docs/nsp/intermediate/71-nsp-ne-config-snapshot-rollback.md b/docs/nsp/intermediate/71-nsp-ne-config-snapshot-rollback.md index 9d8478d..5ec3b51 100644 --- a/docs/nsp/intermediate/71-nsp-ne-config-snapshot-rollback.md +++ b/docs/nsp/intermediate/71-nsp-ne-config-snapshot-rollback.md @@ -6,290 +6,205 @@ tags: - Visual Studio Code --- -# NE config snapshot/rollback +# Network Element Configuration Snapshot/Rollback | | | | --- | --- | -| **Activity name** | NE config snapshot/rollback | +| **Activity name** | Network Element Configuration Snapshot/Rollback | | **Activity ID** | 71 | -| **Short Description** | This activity is about device operation to take configurations snapshots from a device and to rollback to snapshots. | +| **Short Description** | Take nodal configuration snapshots and rollback without the need to reboot. | | **Difficulty** | Intermediate | -| **Tools used** | VS Code with NSP extensions for Workflows and Artifacts | +| **Tools used** | NSP
Visual Studio Code with NSP extensions for Workflows and Artifacts | | **Topology Nodes** | :material-router: PE1, :material-router: PE2, :material-router: PE3, :material-router: PE4, :material-router: P1, :material-router: P2 | -| **References** | [WFM Best Practices](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-best-practices)
[WFM Actions/Functions](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-workflow-actions)
[WFM with vsCode](https://network.developer.nokia.com/learn/24_4/network-programmability-automation-frameworks/workflow-manager-framework/wfm-workflow-development/workflow-manager-visual-studio-code-extension/?highlight=vscode) | - -## Prerequisites -* Basic knowledge the NSP UI -* Basic knowledge about Workflow Manager -* Basic knowledge about Device Operations -* No fear to touch code (for the 2nd part of this activity) - -/// note | from beginner to intermediate -If you consider to do the coding part of this activity, you will need to explore the code and -eventually apply some code modification. For improved Developer eXperience, consider using -Visual Studio Code (or code-server) with the WFM VS Code extension available from -[marketplace](https://marketplace.visualstudio.com/items?itemName=Nokia.nokia-wfm).wh -/// +| **References** | [Nokia Developer Portal](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-best-practices) (Sign up for a free account)
[WFM Best Practices](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-best-practices)
[WFM Actions/Functions](https://network.developer.nokia.com/learn/24_11/programming/workflows/wfm-workflow-development/wfm-workflow-actions)
[WFM with vsCode](https://network.developer.nokia.com/learn/24_4/network-programmability-automation-frameworks/workflow-manager-framework/wfm-workflow-development/workflow-manager-visual-studio-code-extension/?highlight=vscode) | ## Objectives -The purpose of this activity is to take advantage of NSP Device Operations to take NE configuration snapsnhots allowing to -rollback to snapshots taken. NE snapshot/rollback operations will appear as backup/restore operation-category under NSP -Device Management. - -The difference to backup/restore operations that come as part of the product is, that we are taking advantage of transactional, -declarative device management protocols (gNMI, NETCONF). One of the benefits of this approach is, that we can directly access -the running configuration while there is no need to save the configuration prior to the download. Another -benefit is, that the solution can easily be adopted to other device vendors/families, as long those support NETCONF or gNMI. -Finally, there is no dependency to file-transfer (xFTP/SCP) and vendor-specific filenames. +Network device configurations evolve continuously, and its common practice to track configuration drift over time. When recent changes cause issues, you need to quickly understand what changed and when. Beyond analysis, you want the ability to revert to a known stable configuration—ideally applying a rollback as a quick fix without disrupting other services, avoiding outages that would otherwise need to wait for the next scheduled maintenance window. -In order to keep the barrier for executing this activity low, we will provide you with a template and simple recipe to -create your own unsigned artifact bundle, that you can import into NSP using Artifact Manager to get started. +In this activity, you will explore an alternative to the traditional NE Backup/Restore capabilities in NSP. Key differences include: -## Goals to achieve +* **On-demand snapshots**: Capture configurations at any time without persisting the full nodal configuration (e.g., `admin save`). +* **Partial coverage**: Focus snapshots on specific configuration subtrees rather than capturing the entire configuration. +* **In-service rollbacks**: Revert only the delta, avoiding service interruptions and nodal reboots. -### Part 1 - Beginner (steps 1-5) +In this activity, you will create your own unsigned artifact bundle, which can be imported into NSP via Artifact Manager to get started quickly. A template and simple recipe are provided to minimize setup overhead. -Grain practical experience in following areas of NSP: +The design goal is to make snapshot/rollback operations appear as standard Device Operations (LSO) in NSP. As a result, you will be able to: -* NSP Artifact Manager, by importing the artifact bundle and monitoring the installation process. -* NSP Operations Manager and Device Management by executing snapshot and rollback operations, view and compare snapshots -* NSP Workflow Manager, by checking the execution results +* Capture snapshots of individual devices or groups, on-demand and scheduled. +* View configuration snapshots directly from the Device Management WebUI. +* Compare snapshots to identify changes (e.g. drift). +* Rollback to a snapshot safely, without disrupting ongoing services. -### Part 2 - Intermediate (step 6, 7) +## Technology Explanation -Extend the operation capabilities by updating the workflows: - -* Improve the workflow by applying some best practices -* Extend the workflow to support SR Linux nodes +NSP snapshots leverage transactional, declarative device management protocols (e.g., NETCONF, gNMI), providing a universal and lightweight approach for configuration capture and rollback. This avoids dependency on vendor-specific file formats or file transfer protocols and reduces the risk of service disruption during configuration changes. ## Tasks /// note -The provided operation is unsigned, allowing the user to modify the workflows without the need to recreate and reinstall -the bundle (convenient for prototyping). However, due to access-control restrictions we will need to give your user/group -access to the workflows after importing. +The device operation bundle you are developing is unsigned, allowing you to modify the workflows without the need to recreate and reinstall the bundle (convenient for prototyping). However, due to access-control restrictions we will need to give your user/group access to the contained workflows after importing. /// /// warning -Remind, that you are using a single NSP system (shared), that is used for all groups. Therefore, ensure -your group-number is part of the operation and workflow names you are creating to ensure uniqueness. +Remember, that you are using a shared NSP system. Therefore, ensure your group-number is part of the operation and workflow names you are creating to ensure uniqueness. /// **You should read these tasks from top-to-bottom before beginning the activity.** It is tempting to skip ahead but tasks may require you to have completed previous tasks before tackling them. -### Step 1 - Download, customize and install bundle: +--- -1. Clone this repo to your local system. -2. Check the content of [cfg-snapshot-artifact-bundles](./resources/cfg-snapshot-artifact-bundle.zip) -3. Adjust the artifact-bundle content for your group and build the artifact. -4. Login to NSP. Access details will be provided during the hackathon. -5. In NSP, open the hamburger menu and select `Artifacts`. -6. Select `Import and Install`, find the zip file and install the bundle. +In the first part of this activity, you will gain practical experience in following areas of NSP: -/// details | Solution to make it your own bundle: - type: success +* **Artifact Manager** will be used to import the artifact bundle and monitor the installation process. +* **Operations Manager** and Device Management* control snapshot and rollback operations. +* **Workflow Manager** can be used to examine an operation execution's result. + +### Getting Started -/// note | Content of the folder is: +Creating things from scratch can feel daunting and even overwhelming. To save you from piecing together all the required components that define the structure and format of the `snapshot` and `rollback` operations, we provide you with a [**LSO Skeleton Bundle Generator**](./resources/bundle-generate-71.html). This tool creates an artifact bundle in the exact structure expected by the system, giving you a ready-made starting point. From there, you can easily build upon it and move on to more advanced use cases. + +* Unpack and review the content. + +/// note | Artifact Bundle Content: ``` -% cd cfg-snapshot-artifact-bundle +% cd ne-snapshot-rollback-2 % tree . ├── metadata.json -├── operation-rollback -│ ├── ne-rollback-groupxx.yaml -│ ├── ne-rollback-groupxx.yang -│ └── operation_types.json -├── operation-snapshot -│ ├── ne-snapshot-groupxx.yaml -│ ├── ne-snapshot-groupxx.yang -│ └── operation_types.json -├── workflow-rollback -│ ├── README.md -│ └── ne-rollback-groupxx.yaml -└── workflow-snapshot - ├── README.md - ├── ne-snapshot-groupxx.json - └── ne-snapshot-groupxx.yaml - -4 directories, 12 files +├── operation-types +│   ├── rollback +│   │   ├── ne-rollback-2.yaml +│   │   ├── ne-rollback-2.yang +│   │   └── operation_types.json +│   └── snapshot +│   ├── ne-snapshot-2.yaml +│   ├── ne-snapshot-2.yang +│   └── operation_types.json +└── workflows + ├── rollback + │   ├── ne-snapshot-2.yaml + │   └── README.md + └── snapshot + ├── ne-snapshot-2.json + ├── ne-snapshot-2.yaml + └── README.md + +7 directories, 12 files ``` /// -Here is how to replace `groupxx` with `group02`. -Please, adjust to the group that has been assigned to you! - -/// tab | MacOS -``` -export instance=group02 -cp -r cfg-snapshot-artifact-bundle /tmp -cd /tmp/cfg-snapshot-artifact-bundle -find . -name '*groupxx*' -exec bash -c 'mv "$0" "${0//groupxx/$instance}"' {} \; -find . -type f -exec sed -i '' s/groupxx/$instance/g {} \; -zip -r /tmp/cfg-snapshot-$instance.zip * -``` -/// -/// tab | Linux -``` -export instance=group02 -cp -r cfg-snapshot-artifact-bundle /tmp -cd /tmp/cfg-snapshot-artifact-bundle -find . -name '*groupxx*' -exec bash -c 'mv "$0" "${0//groupxx/$instance}"' {} \; -find . -type f -exec sed -i s/groupxx/$instance/g {} \; -zip -r /tmp/cfg-snapshot-$instance.zip * -``` -/// -/// tab | Windows PowerShell -``` -Copy-Item -Path "cfg-snapshot-artifact-bundle" -Destination "C:\tmp" -Recurse -Force -Set-Location -Path "C:\tmp\cfg-snapshot-artifact-bundle" -$instance = "group002" -Get-ChildItem -Path "." -Filter "*groupxx*" | Rename-Item -NewName { $_.Name -replace 'groupxx', $instance } -Get-ChildItem -Path "." -File | ForEach-Object { - $content = Get-Content -Path $_.FullName - $newContent = $content -replace 'groupxx', $instance - Set-Content -Path $_.FullName -Value $newContent -} -$outputZip = Join-Path -Path "C:\tmp" -ChildPath "cfg-snapshot-$instance.zip" -Compress-Archive -Path "*" -DestinationPath $outputZip -Force -``` -/// -/// tab | Details -- rename `operation-rollback/ne-rollback-groupxx.yaml` to `operation-rollback/ne-rollback-group02.yaml` -- rename `operation-rollback/ne-rollback-groupxx.yang` to `operation-rollback/ne-rollback-group02.yang` -- rename `operation-snapshot/ne-snapshot-groupxx.yaml` to `operation-snapshot/ne-snapshot-group02.yaml` -- rename `operation-snapshot/ne-snapshot-groupxx.yang` to `operation-snapshot/ne-snapshot-group02.yang` -- rename `workflow-rollback/ne-rollback-groupxx.yaml` to `workflow-rollback/ne-rollback-group02.yaml` -- rename `workflow-snapshot/ne-snapshot-groupxx.yaml` to `workflow-snapshot/ne-snapshot-group02.yaml` -- rename `workflow-snapshot/ne-snapshot-groupxx.json` to `workflow-snapshot/ne-snapshot-group02.json` -- replace `groupxx` with `group02` in file `metadata.json` (11 occurrences) -- replace `groupxx` with `group02` in file `operation-rollback/operation_types.json` (3 occurrences) -- replace `groupxx` with `group02` in file `operation-rollback/ne-rollback-groupxx.yaml` (1 occurrences) -- replace `groupxx` with `group02` in file `operation-rollback/ne-rollback-groupxx.yang` (7 occurrences) -- replace `groupxx` with `group02` in file `operation-snapshot/operation_types.json` (3 occurrences) -- replace `groupxx` with `group02` in file `operation-snapshot/ne-snapshot-groupxx.yaml` (1 occurrences) -- replace `groupxx` with `group02` in file `operation-snapshot/ne-snapshot-groupxx.yang` (4 occurrences) -- replace `groupxx` with `group02` in file `workflow-rollback/ne-rollback-groupxx.yaml` (2 occurrences) -- replace `groupxx` with `group02` in file `workflow-snapshot/ne-snapshot-groupxx.yaml` (2 occurrences) -/// -/// +* Import the customized artifact bundle into NSP +* Login to NSP. +* Open the hamburger menu and select `Artifacts`. +* Select `IMPORT & INSTALL`. +* Select the zip-file to proceed by clicking on `IMPORT & INSTALL`. /// note -At this point, we recommend the explore usage of the [Artifact Manager VS Code extension](https://marketplace.visualstudio.com/items?itemName=Nokia.artifactadminstrator). -It will help you to explore/download artifact bundles installed to NSP, Create, Update and Package artifact bundles, and finally upload/install artifact bundles in NSP. - -Documentation is available on [Developer Portal](https://network.developer.nokia.com/learn/24_11/nsp-administration/artifacts/artifact-visual-studio-codeextension/). +For easier bundle management, consider using the [Artifact Manager Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=Nokia.artifactadminstrator). It helps with listing, packaging, and installing artifacts directly from your IDE. Documentation is available on the [Developer Portal](https://network.developer.nokia.com/learn/24_11/nsp-administration/artifacts/artifact-visual-studio-codeextension/). /// /// warning -If an artifact bundle contains device operations, you may struggle to update/uninstall/delete this bundle using Artifact Manager. Reason is, -that after installation the device operation is assumed in-use, so you first need to deprecate it by setting the lifecycle state accordingly. +Your artifact bundle contains device operations (LSO artifacts). These are considered in-use after deployment. The LSO deployer blocks Artifact Manager uninstalling or removing the bundle until such operations are `withdrawn`. + +Updating your bundle works without withdrawing/deleting the previous version, as long the updated bundle and artifacts have higher version numbers. Updating an operation-type may fail if the new YANG model is incompatible with model of the previously installed operation-type. /// -**Once your bundle is shown as `Installed`, you can continue...** +Once your bundle is shown as `Installed`, you can continue. + +### Taking Configuration Snapshots + +In this step you will test your new operation. We continue using group 2 as an example. Please remember to adjust it to your group in the steps below. -### Step 2 - Test the operation 1. In NSP, select `Device Management` in the hamburger menu. -2. In the dropdown menu, select `All Operations` -3. Click on "+ OPERATION" to create a new operation -4. Select Operation Type `ne-snapshot-group02` (adjust to your group) -5. Provide operation name, for example `initial-cfg-snapshot-group02` (adjust to your group) -6. Select P1, P2, PE1, PE2, PE3, PE4 as `Target NEs` to take a snapshot (adjust to your group) -7. After the creation the user can check the operation status, it should set to completed. -8. Check the operation result and cross-navigate to see the underlying workflow executions - -### Step 3 - Explore NSP WebUI shortcuts -The `Operation` section under `Device Management` is common for all NSP operations. -To simplify usability, you can access the snapshot/rollback operations and results -from the `Managed Network Elements` view. +2. In the dropdown menu, select `All Operations`. +3. Click on `+ OPERATION` to create a new operation. +4. Select Operation Type `ne-snapshot-2`. +5. Provide operation name, for example `initial-cfg-snapshot-2`. +6. Select P1, P2, PE1, PE2, PE3, PE4 as `Target NEs` to take a snapshot. +7. After the creation the user can check the operation status, it should set to `completed`. +8. Check the operation result and cross-navigate to see the underlying workflow executions. + +After finishing all steps we would have successfully used a custom workflow to create NE snapshots without relying on copying `config.cfg` from the NE. + +### Access Configuration Snapshots + +The `Operation` section under `Device Management` is common for all NSP operations. To simplify usability, you can access the snapshot/rollback operations and results from the `Managed Network Elements` view. 1. In NSP, select `Device Management` in the hamburger menu. 2. In the dropdown menu, select `Managed Network Elements` -3. Click on the 3 dots for your `P1` node to open the context menu for device specific `Operations` (adjust to your group) -4. Explore the options to access operation history, review backups and create backups. -5. In NSP, select `File Server` in the hamburger menu (section: `NSP Administration`) +3. Click on the 3 dots for your `P1` node to open the context menu for device specific `Operations` +4. Explore the options to access operation history, review and create backups. +5. In NSP, select `File Server` in the hamburger menu (under `NSP Administration`) to locate the backup files. -/// note | Questions +/// admonition | Questions + type: question - What are the different ways to list and display configuration snapshots? - In what format are configuration snapshots stored? - Find a way to compare configuration snapshots! - What is the directory, in which backups/snapshots are stored on the File Server? -- Do you spot differences between `File Server` and `View all backup files`? /// -### Step 4 - Taking it a step further -1. Apply changes to a node using CLI or MDC and take another config snapshot! - Example: Add/Update location and contact information under `configure > system`. - Do you see the changes? +### Compare and Rollback Configuration Snapshots + +1. Apply changes to a node using CLI or Model Driven Configurator WebUI and take another config snapshot! Example: Add or update location and contact information under `configure > system`. Do you see the changes? 2. Use the rollback operation to restore the initial configuration (without reboot)! Was the config restored? -3. Update your operations to become the default operation. What has changed? +3. Update your `snapshot` operation to become the default `backup` operation. 4. Try the option to `Compare with current NE config` (only works, if your operation is the default operation) -5. Delete snapshot operations. Do you still have access to the snapshot itself? Can it be displayed/restored? -6. Create a scheduled operation, that takes NE snapshots from all SR OS nodes every hour. +5. Create a scheduled operation, that takes NE snapshots from all SR OS nodes every hour. /// warning -Be aware, that only one backup operation and one restore operation can be made `default`! In conclusion, -you may experience issues if other hackathon participants execute this activity, as we are using a shared -NSP system. +Be aware, that only one(!) backup operation can be made default! In conclusion, you may experience issues if others execute this activity, as we are using a shared NSP system. /// -### Step 5 - Digging into the code -Review the code examples provides for the operation-types and the workflows. -There is different ways to access the code using vsCode or from WebUI. +--- -/// admonition | Questions - type: question -- Explore the different spots in the NSP WebUI that show the code! Which ones allow write-access? -- What are the components of an artifact bundle? -- What are the components of an operation artifact? -- What's the function of the mapping profile in operations? -- Compare the workflow input/output against the operation model/mapping and WebUI rendering! -- The rollback operation input has redundancies (`backup_operation` versus backup path and filename). Do you know why? -- The path to store snapshots contains the nodal release. Explore, why this is the case! -/// +In the second part of this activity, we will get into coding. We will extend the operation capabilities by updating the underlying workflows to: + +* Improve the workflow by applying best practices +* Extend the workflow to support SR Linux nodes -### Step 6 - Improve the operation -Review the workflow that takes the configuration snapshot. -Check, if there is anything that can be improved! -Are best practices appropriately applied? +### Digging into the Code -You may find, that action `getConfigSROS` publishes the configuration as JSON string. -This approach works well for smaller configurations, like in context of this Hackathon. -But considering production-scale nodal configurations, be reminded that publishing -mega-bytes of data is not recommended, as it impacts resource usage of the WFM services -and DB footage. +Review the code examples provided for operation-types and workflows. +You can access the code either through Visual Studio Code or directly in the Workflow Manager WebUI. -To work around this, you may consider updating the workflow. The `nsp.https` action allows -to store the result in the local file-system by using the input attribute called `fileName`. -Change the task to store the JSON response as file under the path -`/tmp/<% $.neName %>.nokia-conf.json`. When applying this change, you need to consider -to add another input attribute `resultFilter : $.content`. This applies a YAQL expression -to the response before writing it to a file, else everything would be wrapped into a -top-level element called `content`. +Exploration Points: -Please ensure to use an unique filename, as multiple snapshot operations for different -targets may run in parallel. +* Identify where in the NSP WebUI you can view code, and note which areas provide read-only vs. editable access. Check Artifact Manager, Workflow Manager, and Device Operation-Types (LSOM). +* Break down the components of an artifact bundle to understand how artifacts are packaged and deployed. +* Analyze the elements of an operation artifact (operation model, mapping, script, etc.) and how they work together. +* Examine the role of the mapping profile in linking inputs and outputs to the underlying model. +* Compare workflow input/output definitions against the operation model and mapping, and see how they align with the WebUI rendering. +* Notice redundancies in rollback operation inputs (e.g., backup operation vs. backup path/filename). Reflect on why these exist, by triggering rollbacks from different WebUI contexts to observe differences in workflow execution inputs. +* Observe how the snapshot storage path includes the nodal release, and consider how this design choice ensures version accuracy and compatibility. -To upload the file to the file-service, you need to update the task `writeConfigFile`. Uploading -files is relatively easy using the `nsp.uploadFile` action. +### Improve your Operation -As `/tmp` is a shared file-system, validate if you can take multiple snapshots from different devices -in parallel! We are not removing files from `/tmp`. Does this cause any further issues? +Review the workflow that takes configuration snapshots. Check, if there is anything that can be improved! Are [best practices]("https://network.developer.nokia.com/learn/24_4/network-programmability-automation-frameworks/workflow-manager-framework/wfm-workflow-development/wfm-best-practices/") appropriately applied? -You may spot, that the JSON file is now minified, while it was prettified before. This impacts -usability when displaying or comparing backups. As of today, the action `nsp.https` does not -have an option to store the result as pretty JSON. You may consider using python to make it pretty. +You may find that the action `getConfig` publishes the configuration as a JSON string. This approach works well for smaller configurations like we have in this hackathon. Applying this approach to production-scale nodal configurations can lead to publishing mega-bytes of data and is not recommended as it impacts resource consumption. -While we've applied the best practices change for taking a configuration snapshots, you may -observe that the rollback workflow publishes the configuration too and renders a full blown -`nsp.https` request, that contains the entire config in the body payload. Please note, the action -`nsp.https` does not have an option to load the payload body from the filesystem. +To work around this, you may consider updating the workflow. The `nsp.https` action allows to store the result in the local filesystem by using the input attribute called `fileName`. Change the task to store the JSON response as file under the path `/tmp/<% $.neName %>.nokia-conf.json`. When applying this change, you need to consider to add another input attribute `resultFilter : $.content`. This applies a YAQL expression to the response before writing it to a file, else everything would be wrapped into a top-level element called `content`. + +/// warning +By using `/tmp` for temporary storage, consider the case that multiple snapshots (typically on different target nodes) are generated in parallel. Therefore, consider using unique filenames, so parallel operation executions will not impact each other. +/// + +To upload the file to the file-service, you need to update the task `uploadConfig`. Uploading files is relatively easy using the `nsp.uploadFile` action. + +You may spot that the JSON payload is now minified, while it was prettified before. This impacts usability when displaying or comparing backups. As of today, the action `nsp.https` does not have an option to store the result as pretty JSON. You may consider using Python to make it pretty. + +/// warning +While we've applied the best practices changes on the snapshot artefacts, you may observe that the rollback workflow renders a large `nsp.https` request, that contains the entire config in the body payload. Please note, the action `nsp.https` does not have an option to load the payload body from the filesystem. +/// /// details | Cheatsheet -Updated definition for `getConfigSROS`: +Updated definition for `getConfig`: ``` action: nsp.https input: @@ -304,7 +219,7 @@ on-success: - createBackupFolder ``` -Updated definition for `writeConfigFile`. You may even consider renaming it to `uploadConfigFile`: +Updated definition for `uploadConfig`: ``` action: nsp.uploadFile input: @@ -314,7 +229,7 @@ on-success: - zipConfig ``` -To prettify a JSON file in the file-system, the following task in Python may help: +To prettify a JSON file in the filesystem, the following task in Python may help: ``` prettify: action: nsp.python @@ -332,61 +247,56 @@ To prettify a JSON file in the file-system, the following task in Python may hel /// -### Step 7 - Extend the operation -Congrats, if you already made it to this point! You've mastered operations and workflows and even -you've done a bit of coding. This is excellent! In the final part of this activity, we want to go -practical. The ask is to extend the snapshot operation/workflow to support SR Linux. +### Extend your Operation to support SR Linux -/// warning -If you've modified your snapshot workflow in the previous part of this activity, please consider -to copy the workflow content to your local system to avoid losing it. +If you made it to this point you have mastered operations and workflows and have even done a bit of coding. In this final part of this activity, we want to extend the snapshot operation/workflow to support SR Linux. + +/// note +If you've modified your snapshot workflow in the previous part of this activity, please consider copying the workflow content to your local system to avoid losing it. /// -Let's start with the operation first. As the mapping profile associates supported device-types -with workflows to be executed, you need to extend the mapping profile to support the corresponding -SR Linux families. Take a look into the NSP operation `nsp-ne-backup` that is installed by default. -It contains the entries `7220 IXR SRLinux` and `7250 IXR SRLinux` for `family_type`. Extend -the list of supported families for your own operations, while we will keep the same workflows! +Let's start with the operation first. As the mapping profile associates supported device-types with workflows to be executed, you need to extend the mapping profile to support the corresponding SR Linux families. Take a look into the NSP operation `nsp-ne-backup` that is installed by default. It contains the entries `7220 IXR SR Linux` and `7250 IXR SR Linux` for `family_type`. Extend the list of supported families for your own snapshot operation while still pointing to the same workflows! /// note -Updating an operation in NSP is supported neither from the NSP WebUI nor there is a vsCode extension -for Operation Manager. Therefore, the only way to update operations in NSP is via Artifact Manager! -In consequence, you will need to update the mapping profile on your local machine and rebuild the bundle. -Because bundles and artifacts are versioned, Artifact Manager will not update installed artifacts if -the version number stays the same. You may consider to either uninstall/remove your artifact bundle -(option 1) or increase the version numbers (option 2). In case of option 1, please be aware that -operation-types can only be removed when marked as `withdrawn` in `Device Administration`. +Updating an operation-type in NSP is not supported from the NSP WebUI nor through the use of APIs. Therefore, the only way to update operations in NSP is via Artifact Manager. You will need to update the mapping profile on your local machine and rebuild the bundle. Because bundles and artifacts are versioned, Artifact Manager will not update installed artifacts if the version number stays the same. You must either uninstall your artifact bundle or increase the version numbers. In case of option 1, please be aware that operation-types can only be removed when marked as `withdrawn` in `Device Administration`. Increasing the version number is the recommended approach. /// -After you've imported your updated bundle, you may consider running a test to validate, that the -existing functionality still works. Once this is done you can start updating your workflows. +After you've imported your updated bundle, run a test to validate that the existing functionality still works. -The most notable difference between SR OS and SR Linux would be, that SR OS stores all configuration -in a single root module (/nokia-conf:configure) while SR Linux uses multiple root-level modules. +The most notable difference between SR OS and SR Linux would be that SR OS stores all configuration in a single root module `/nokia-conf:configure` while SR Linux has multiple root-level modules. -In addition, be aware that SR Linux mixes configuration (read/write) and state attributes (read-only) -in the same subtree. As the ask is to capture the configuration only, the RESTCONF query parameter -`?content=config` should be added to the corresponding RESTCONF `GET` request. +In addition, be aware that SR Linux mixes configuration (read/write) and state attributes (read-only) in the same subtree. As the ask is to capture the configuration only, the RESTCONF query parameter `?content=config` should be added to the corresponding RESTCONF `GET` request. /// note -The NSP implementation executes a `` netconf rpc, if the query-parameter -`?content=config` is provided. For gNMI the behavior depends on the path being queried. -If a class (yang list) is requested, gNMI Subscribe is used. If an object (yang list entry) -is requested, gNMI Get is used. Only the later (gNMI Get) has an object to restrict the -content to configuration only. - -In this activity we are focusing on root-paths to be queried, which are all classes -(not objects). In consequence the responses will contain state attributes regardless of -the query-option `?content=config` being provided or not. +The NSP implementation executes a `get-config` NETCONF RPC if the query-parameter `?content=config` is provided. For gNMI, the behavior depends on the path being queried. If a class (e.g. YANG `list`) is requested, gNMI Subscribe is used. If an object (e.g. YANG `list entry` or `container`) is requested, gNMI Get is used. Only the latter has a means of restricting the content received in response to configuration only. + +In this activity we are focusing on root-paths to be queried, all of which are classes. In consequence the responses will contain state attributes regardless of the query-option `?content=config` being provided or not. /// -As MDC does not support to fetch all module instance by accessing /root, and because we are not -interested in OpenConfig models, you may use the [SRL YANG Explorer](https://yang.srlinux.dev) or +You may use the [SRL YANG Explorer](https://yang.SR Linux.dev) or NSP MDC to find appropriate root paths. You may want to start with the following root paths: -* srl_nokia-network-instance:/network-instance -* srl_nokia-interfaces:/interface +* srl_nokia-network-instance:network-instance +* srl_nokia-interfaces:interface * srl_nokia-system:system -It's recommended to store the output of those queries in separate files, while the ZIP archive would -now contain multiple files. +It's recommended to store the output of those queries in separate files when creating your configuration snapshot, the resulting ZIP archive should now contain multiple files. + +/// note + type: success + +If you got stuck with the coding exercises, use the [**Complete LSO Bundle Generator**](./resources/bundle-generate-71.html?kind=complete) to create a bundle that contains an updated snapshot operation, to apply best-practices and support SRLinux. Compare the original operation with the updated operation, to understand the updates that have been applied. +/// + + +## Summary + +Congratulations! You have completed this activity. Take a moment to review what you achieved: + +* Experienced Device Management Operations to trigger configuration snapshot and rollback operations. +* Learned how to display and compare configuration snapshots to detect configuration drift. +* Understood the differences between traditional backup/restore and snapshot/rollback operations. +* Customized and installed an artifact bundle using NSP Artifact Manager. +* Extended the artifact bundle provided to support SR Linux. +* Explored the relationship of Device Operations, Workflows, Artifact Bundles and File Service. +* Looked in WFM design best-practices. \ No newline at end of file diff --git a/docs/nsp/intermediate/images/66-ne-password/directory-struct.png b/docs/nsp/intermediate/images/66-ne-password/directory-struct.png index 8c48cd1..454934a 100644 Binary files a/docs/nsp/intermediate/images/66-ne-password/directory-struct.png and b/docs/nsp/intermediate/images/66-ne-password/directory-struct.png differ diff --git a/docs/nsp/intermediate/resources/bundle-generate-66.html b/docs/nsp/intermediate/resources/bundle-generate-66.html new file mode 100644 index 0000000..176e59c --- /dev/null +++ b/docs/nsp/intermediate/resources/bundle-generate-66.html @@ -0,0 +1,648 @@ + + + + + SReXperts 2025 + + + + + + + + +

+
+
+

SReXperts 2025

+

NE Password Audit/Align (NSP - Intermediate)

+

LSO Artifact Bundle Generator (skeleton)

+ +
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+

+
+
+
+ + + + diff --git a/docs/nsp/intermediate/resources/bundle-generate-71.html b/docs/nsp/intermediate/resources/bundle-generate-71.html new file mode 100644 index 0000000..6f1ffb9 --- /dev/null +++ b/docs/nsp/intermediate/resources/bundle-generate-71.html @@ -0,0 +1,996 @@ + + + + + SReXperts 2025 + + + + + + + + +
+
+
+

SReXperts 2025

+

NE Config Snapshot/Rollback (NSP - Intermediate)

+

LSO Artifact Bundle Generator (skeleton)

+ +
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+

+
+
+
+ + + + diff --git a/docs/tools/tools-clab-vscode-plugin.md b/docs/tools/tools-clab-vscode-plugin.md index a642ac9..7553088 100644 --- a/docs/tools/tools-clab-vscode-plugin.md +++ b/docs/tools/tools-clab-vscode-plugin.md @@ -11,15 +11,15 @@ tags: | | | | ----------------------------- | --------------------------------------------- | -| **Activity name** | VScode Containerlab extension | +| **Activity name** | VS Code Containerlab extension | | **Activity ID** | 44 | | **Short Description** | Learn how to use the Containerlab extension for VS Code to improve your lab workflow. | | **Difficulty** | Beginner | -| **Tools used** | [Visual Studio Code](https://code.visualstudio.com/)
[Containershark Plugin](https://github.com/siemens/cshargextcap/tree/v0.10.7) | +| **Tools used** | [Visual Studio Code](https://code.visualstudio.com/) | | **References** | [VS Code containerlab Extension](https://marketplace.visualstudio.com/items?itemName=srl-labs.vscode-containerlab)
[Containerlab VS Code documentation](https://containerlab.dev/manual/vsc-extension/)
| -The **VS Code Containerlab Extension** enhances the Containerlab user experience. Taking advantage of powerful text editing functionality in [Visual Studio Code](https://code.visualstudio.com/), the extension provides an easy way to manage the entire lifecycle of your labs. +The **VS Code Containerlab Extension** enhances the Containerlab user experience. Taking advantage of powerful text editing functionality and the extensibility of [Visual Studio Code](https://code.visualstudio.com/), the extension provides an easy way to manage the entire lifecycle of your labs. ## Objective @@ -31,59 +31,80 @@ First let's go over some key functionality of what makes the extension so good. You can view a [video walkthrough](https://www.youtube.com/watch?v=NIw1PbfCyQ4) which shows some basic usage of the extension. -### Lab explorer +### Tree views -The aptly named lab explorer is a panel (similar to the file explorer in VS Code) which displays all running labs on the system, as well as locally discovered containerlab topology files for your [open workspace](https://code.visualstudio.com/docs/editing/workspaces/workspaces) in Visual Studio Code. +When opening the Containerlab extension, you will notice there are three distinct panels; being: -The lab explorer is a tree view, which means you can expand each lab to drill down to containers and their interfaces for further interaction. +- [Running labs](#running-labs) +- [Undeployed local labs](#undeployed-local-labs) +- [Help & feedback](#help--feedback) + + +/// note +The panels are referred to as tree views because when populated with elements, they will be displayed following a hierarchical tree structure with root nodes which can branch down to leaf nodes. +/// + +![Containerlab VS Code tree view panels](../images/tools-clab-vscode-plugin/01-annotated-treeview.png) + +#### Running labs + +The running labs panel will display all deployed containerlabs on the system. + +You can expand the running lab to view the individual containers which belong to the lab, and interact with them (ie. telnet, SSH, start/stop etc.) + +You can expand each container to view it's interfaces, set link impairments and perform packet captures. + +#### Undeployed local labs + +The undeployed local labs panel will show all discovered topology files in the directory of your current [VS Code Workspace.](https://code.visualstudio.com/docs/editing/workspaces/workspaces) + +Topology files are discovered by recursively searching your workspace directory and subdirectories for files which have the `*.clab.yaml` or `*.clab.yml` file extension. + +#### Help & Feedback + +The aptly named 'Help & Feedback' panel displays shortcuts to documentation pages which can be of help when using Containerlab. ### Visualization and editing -The extension makes it easy to visualize and edit topologies. +The extension makes it easy to visualize and edit topologies by introducing the TopoViewer tool. -You can either edit the YAML file we are all used to using the in-built VS Code editor. The extension also introduces the TopoViewer and TopoEditor tools which respectively give you beautiful GUIs to visualize and create/edit your topologies. +The TopoViewer is a graphical topology creator/editor allowing Containerlab topologies to be created interactively. TopoViewer also is a visualization tool to interact with your running lab topologies. -The extension makes it easy to use existing visualization tools such as the web graph, or [clab-io-draw](https://github.com/srl-labs/clab-io-draw). +The extension makes it easy to also use the existing visualization tooling, such as the web graph or [clab-io-draw](https://github.com/srl-labs/clab-io-draw). -### Edgeshark +![TopoViewer Graphical topology editor](../images/tools-clab-vscode-plugin/02-topo_viewer_editor.png) -[Edgeshark](https://github.com/siemens/edgeshark) is a tool which makes container packet capture extremely easy, we have had it available to use with Containerlab for a while, but the experience is made one step easier by having it integrated in the extension making the workflow to initiate a capture extremely fast. +### Integrated packet capture + +Packet capture is an integral component of labbing. [Edgeshark](https://github.com/siemens/edgeshark) is a tool which makes container packet capture extremely easy, we have had it available to use with Containerlab for a while. + +The extension further improves on this by integrating Wireshark directly into your VS Code window to make packet capture extremely easy. No dependencies required on your laptop at all. + +![Integrated Wireshark Packet Capture](../images/tools-clab-vscode-plugin/03-integrated_wireshark.png) ### Link impairments In Containerlab you are able to set link impairments for your labs. The impairments are delay, jitter, corruption and packet loss. -The extension simplifies the method of managing these impairments with a table view or quick-input box activated from the tree view. +The extension simplifies the method of managing these impairments by providing a page to manage all impairments for a nodes' interface(s); or quickly setting an impairment on an interface via the interface element in the running labs tree. + +![Link impairment editor](../images/tools-clab-vscode-plugin/04-link-impairments.png) ## Tasks It's now time to give the extension a test-drive. We will first do some basic setup to get the extension up and running. - + ### Connect to Containerlab host If you are using Visual Studio code on your own machine, you must connect to the lab environment using the Remote SSH functionality in VS Code, as this is where Containerlab is running. ??? tip "How to use Remote SSH" - /// tab | Install SSH - - ![install-ssh](../images/tools-clab-vscode-plugin/1-install-ssh.png) - - /// - /// tab | Connect to Host - - ![connect-host](../images/tools-clab-vscode-plugin/2-connect-host.png) - - /// - /// tab | Select SSH host - - ![ip-address](../images/tools-clab-vscode-plugin/3-ip-address.png) - - /// + ![Using VS Code Remote SSH](../images/tools-clab-vscode-plugin/install-ssh.gif) !!!info - If you are unable to install Visual Studio Code on your laptop. You can use the code-server instance for a browser-based Visual Studio code instance. + If you are unable to install Visual Studio Code on your laptop. You can use the code-server instance for a browser-based Visual Studio Code instance. Simply navigate to `.srexperts.net` in your browser to access the code-server. You can skip the next installation step if using this method. @@ -93,9 +114,16 @@ If you are running VS Code locally on your laptop you can navigate to [container You can also navigate to the extensions tab inside of VS Code and serach for 'Containerlab': -![Containerlab extension installation](../images/tools-clab-vscode-plugin/extension-install.png) +![Containerlab extension installation](../images/tools-clab-vscode-plugin/install-ext-steps.png) + +After installation, you should see a new 'Welcome to Containerlab' page appear. -If installing the extension on a system without Containerlab installed, the extension will prompt you to **Install Containerlab**. Now you don't even need to manually install Containerlab, simply push the **Install Containerlab** button and Containerlab + all dependencies will automatically install. +/// admonition | Containerlab installation + type: tip +The extension will also detect if Containerlab is installed on your system, if it's not found you will get a prompt in the bottom right to **Install Containerlab**. + +Hit **Install Containerlab**, tada! as easy as that Containerlab (and it's depedencies) are now installed and ready to go on your system. +/// Let's also create a directory we will work out of. @@ -109,41 +137,47 @@ Enter that folder in VS Code by navigating to the file menu (top left), and sele You will notice the Containerlab logo now appears on your extension bar. Click on it to open the extension, you will see the tree view. -At the top-right of the extension panel, you can see some common functions. If you hover over each one a small tooltip will show to describe the icon's functionality. +You should notice the 3 distinct panels. Let's create a topology using TopoViewer: the bundled graphical topology creation & editing tool. -![Lab explorer actions](../images/tools-clab-vscode-plugin/explorer-actions-2.png) +Launch TopoViewer by clicking on the :material-file-plus-outline: icon; or the 'Create topology with TopoViewer' button. -Click on the :material-file-plus-outline: icon to open TopoEditor. +![Open TopoViewer](../images/tools-clab-vscode-plugin/05-launch_topo_viewer_editor.png) You will be prompted for a path for where to put the new topology file. Type the name you want for your topology. -![TopoEditor file path input box](../images/tools-clab-vscode-plugin/topoeditor-filename-2.png) +![TopoViewer file path input box](../images/tools-clab-vscode-plugin/06-topo_viewer_editor_file_name_input.png) -TopoEditor will now open. On one side of the screen you will see the Containerlab YAML file, and on the other is the TopoEditor graphical topology editor. +TopoViewer will now open. On one side of the screen you will see the Containerlab YAML file, and on the other is the TopoViewer graphical topology editor. -The default topology consists of 2 SR Linux nodes connected back to back. +The default topology consists of 2 SR Linux nodes connected back to back with a link on both the `e1-1` and `e1-2` interfaces. -![TopoEditor](../images/tools-clab-vscode-plugin/topoeditor-splitscreen-2.png) +![TopoViewer split screen view](../images/tools-clab-vscode-plugin/07-topo_viewer_editor_splitscreen.png) -You can click and drag on nodes to move them around, hold right click on nodes or links to open an editor wheel. You can also use left click with the Shift or Alt keys to quickly add/remove nodes/links. +You can click and drag on nodes to move them around. Add nodes using the :octicons-plus-16: icon, hold right click on a node or a link to open an editor wheel which lets you edit properties of the node/link, or add/remove a node/link. -After getting some usage with the TopoEditor, stick to a basic two-nodes SRL topology, with a single link between the two nodes. +You can also reposition and lock the position of the floating editor panel. Hover over the icons on the floating panel to see what function each button does. -### Deploy the lab +![TopoViewer usage example](https://gitlab.com/srexperts/artifacts/-/wikis/uploads/a74b2f7d873f2fbea117daf75bacf999/08-topo_viewer_editor_demo.gif) -Now that we have created a topology, lets use the extension to manage the lab lifecycle. +After getting some usage with the TopoViewer, stick to a basic two-nodes SRL topology, with at least one link between the two nodes on their `e1-1` interfaces. -In the lab explorer, you should now see the lab we just created, you can deploy the lab either of below methods: +### Manage lab lifecycle -- [x] Right click on the lab in the lab explorer and choose **Deploy** or **Deploy (cleanup)**. - - Once the lab is running, from here you can also destroy (bring down) or redeploy (restart) your lab. +Now that we have created a topology, lets use the extension to manage the lab lifecycle. + +In the lab explorer, you should notice the lab we have created under the 'Undeployed local labs' tab. You can deploy the lab either of below methods: - ![right-click-deploy](../images/tools-clab-vscode-plugin/deploy-clab-2.png) +- Use the Deploy (:fontawesome-solid-play:) button on the floating panel in TopoViewer. -- [x] Enter the `Edit Lab topology` and use the play icon :fontawesome-solid-play: at upper-right corner for the lab management options. + ![Deploy via TopoViewer](../images/tools-clab-vscode-plugin/09-topo_viewer_editor_deploy.png) - ![play-icon-clab](../images/tools-clab-vscode-plugin/play-icon-clab-2.png) +- Right click on the lab in the lab explorer and click **Deploy**. + + ![Deploy via lab explorer](../images/tools-clab-vscode-plugin/10-tree_view_deploy.png) + +- Enter the `Edit Lab topology` and use the play icon :fontawesome-solid-play: at upper-right corner for the lab management options. + + ![Deploy via YAML editor](../images/tools-clab-vscode-plugin/11-editor_quick_deploy.png) When the lab deployment starts, a small box will show on the *bottom right* to notify us that the lab is in the process of deploying. @@ -151,148 +185,192 @@ We can click the **View Logs** button of this box to open the **Output** panel a Looking back at the tree view, you should be able to see the icon colour of the lab change to a  :green_circle:  when the lab is up and running. -With the lab running, you can expand the lab in the tree view and go all the way down to interface level. +You should also notice that the TopoViewer has now changed into viewer mode, editing functionality is no longer available, and the mode inidicator below the TopoViewer text in the navbar says 'Viewer'. -By hovering on the lab, containers or interfaces you can see a small tooltip which displays some key info, such as node name, image, kind, IP address or interface MAC addresses and MTU. +With the lab running, you can expand the lab in the tree view and drill all the way down to per-node interface level. - -![output](../images/tools-clab-vscode-plugin/output-2.png) +By hovering on the lab, containers or interfaces you can see a small tooltip which displays some key info, such as node name, image, kind, IP address or interface MAC addresses and MTU. + +![Screenshot of VS Code after lab deployment](../images/tools-clab-vscode-plugin/12-post_deploy_screenshot.png) We can also inspect the lab in the tabular format you may be used to from the Containerlab CLI. This is a great way to quickly take a look at all information of the lab. -Simply right click on the lab name then click **Inspect Lab** +Simply right click on the lab name then click **Inspect Lab**. + +There is a search box to aide in filtering if your topology has many nodes. -![inspect-clab](../images/tools-clab-vscode-plugin/inspect-2.png) +![inspect-clab](../images/tools-clab-vscode-plugin/13-inspect_webivew.png) ### Interact with nodes -The tree view provides quick action buttons for common actions, such as connecting to a node via SSH by making use of the built-in VS Code terminal we get tabbed terminal sessions. +You can interact with the lab nodes either via the tree view or TopoViewer. -You can also right-click on the node in the tree view to see all functionality available to interact with a node. +#### Using tree view -Try it out, and connect to the nodes in your topology. +If you hover over the container node in the tree, you should notice on the right side that there are three quick actions for the node. -![Node quick actions](../images/tools-clab-vscode-plugin/node-quick-actions-2.png) +- :fontawesome-solid-bars: lets you view the containers logs. Useful to see any bootup or crash information. +- :octicons-terminal-16: lets you connect to the container shell. This is useful for linux nodes, or troubleshooting. +- :material-remote-desktop: lets you connect via SSH to the node. This is the how you can easily drop into the CLI of the NOS. -### Topology visualization +You can also right-click on the node in the tree view to see all functionality available to interact with a node, for example: to connect via telnet. -Now that the lab is deployed, in this exercise we will see the graphing functionality provided by the extension. +/// tip +If you right click on the lab node in the tree, you can SSH to all nodes in your topology using VS Codes' integrated multi tabbed terminal. +/// #### Using TopoViewer -[TopoViewer](https://github.com/asadarafat/topoViewer) is a network visualization tool that transforms the Containerlab topology data into a visual diagram that network engineers are more familiar with. +Since we have deployed the lab, TopoViewer has detected our lab is running and accordingly switched to view mode. This means the radial menu when you right click on a node has changed. + +With this context-aware radial menu, you can: + +- SSH to the node. +- Drop into the node's container shell. +- View the nodes's container logs. +- View node properties. + +Try it out, and connect to the nodes in your topology. + +### Topology visualization -It is based on Cytoscape.js and looks and is very similar to the TopoEditor we used earlier. +Let's take a look at some of the enhanced graphing functionality the extension provides. -The tight integration of TopoViewer into the extension means that you can interact with your nodes directly from the extension via TopoViewer. +#### TopoViewer enhanced visualization -- [x] Right-click on the lab in lab explorer and select **Graph Lab (TopoViewer)**; you will have a view of your topology with options like toggling the endpoint tags, reloading the topoviewer and saving changes. +With TopoViewer, there are extra functions to aid in the visualization of your lab topology. -- [x] Moreover by selecting each node, a **Node Properties** window will open that provides some information about each container and an **Actions** drop-down menu with useful options such as `Connect to SSH`, `View Logs`, etc . +In the floating panel there is the :fontawesome-solid-layer-group: Add Group, and :fontawesome-solid-font: Add Text buttons. -![topoviewer](../images/tools-clab-vscode-plugin/topoviewer-2.png) +These allow you to enhance the topology diagram to make your topology truly beautiful. -- [x] Finally position the nodes in the way you would like to see in a network and save. After saving, if you look to the `lab.clab.yml` file you will see that labels are edited accordingly for each node. +/// tip +In the top right of the TopoViwer navbar, there is a :fontawesome-solid-camera: icon. This will export the TopoViewer canvas to an SVG file, effectively exporting an image of your topology to make sharing easy. +/// -TopoViewer is very useful for rearranging the nodes position especially for large topologies with numerous network elements. +#### draw.io -#### Generate draw.io diagrams +To take your diagrams to the next level let's introduce [draw.io](https://github.com/jgraph/drawio), it is a free and open-source diagramming tool. -[clab-io-draw](https://github.com/srl-labs/clab-io-draw/tree/main?tab=readme-ov-file#clab-io-draw) enables seamless conversion between containerlab YAML files and [draw.io](https://draw.io) diagrams. This simplifies visualization, documentation, and sharing of network topologies. +Pairing this with the [clab-io-draw](https://github.com/srl-labs/clab-io-draw/tree/main?tab=readme-ov-file#clab-io-draw) tool, we can easily export our topology to a draw.io compatible diagram. + +This saves a lot of effort in manual diagramming, and is useful for creating enhanced diagrams as well as enabling exporting to standard tools such as Visio. You can generate draw.io diagrams from the extension with a few clicks. -- [x] Right-click on the lab in lab explorer and select **Graph Lab (draw.io)**. The draw.io diagram will be automatically generated. Notice that all the labels such as link_id are available as properties for the draw.io objects. +Right-click on the lab in the tree view and hover over **Graph Lab (draw.io)**. This will open a submenu where you can choose between + +- Horizontal mode (automatically lay out nodes horizontally - position from left to right). +- Interactive mode (opens a terminal UI to configure the diagram output style). +- Vertical mode (automatically lay out nodes vertically - position top to bottom). -![drawio](../images/tools-clab-vscode-plugin/drawio-2.png) +The diagram opens inside a draw.io editor inside VS Code so that you can edit away. +![Export graph using draw.io](../images/tools-clab-vscode-plugin/14-draw_io_export.png) ### Links In this exercise we will take a look at some of the available interaction with links in our topology; these being link impairments and packet capture. -#### Configure Interfaces +#### Configure IP addressing -Let's first configure the interfaces on our two SRL nodes. +Let's first configure the interfaces on our two SRL nodes. We need to bring them up and assign some IP addresses. -- [x] Connect to SSH of both nodes to configure the interface toward the other node. +1. Connect via SSH to both nodes. The default password is `NokiaSrl1!` -![connect-ssh](../images/tools-clab-vscode-plugin/connect-ssh-2.png) +2. Configure the `ethernet-1/1` interfaces of each of the nodes. -- [x] Configure the IP addresses on the connecting interface between nodes; below you can find a sample. + Don't worry if you're unfamiliar with the SR Linux CLI, refer to the configuration sample below. -/// tab | srl-1 + /// tab | srl1 -``` srl-1 -A:srl-1# enter candidate - / interface ethernet-1/1 admin-state enable - / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable - / interface ethernet-1/1 subinterface 0 ipv4 address 10.1.2.1/30 - / network-instance default type default - / network-instance default admin-state enable - / network-instance default interface ethernet-1/1.0 -A:srl-1# commit now -``` + ``` srl1 + A:srl1# enter candidate + / interface ethernet-1/1 admin-state enable + / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable + / interface ethernet-1/1 subinterface 0 ipv4 address 10.1.2.1/30 + / network-instance default type default + / network-instance default admin-state enable + / network-instance default interface ethernet-1/1.0 + A:srl1# commit now + ``` -/// -/// tab | srl-2 - -``` srl-2 -A:srl-2# enter candidate - / interface ethernet-1/1 admin-state enable - / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable - / interface ethernet-1/1 subinterface 0 ipv4 address 10.1.2.2/30 - / network-instance default type default - / network-instance default admin-state enable - / network-instance default interface ethernet-1/1.0 -A:srl-1# commit now -``` -/// + /// + /// tab | srl2 + + ``` srl2 + A:srl2# enter candidate + / interface ethernet-1/1 admin-state enable + / interface ethernet-1/1 subinterface 0 ipv4 admin-state enable + / interface ethernet-1/1 subinterface 0 ipv4 address 10.1.2.2/30 + / network-instance default type default + / network-instance default admin-state enable + / network-instance default interface ethernet-1/1.0 + A:srl2# commit now + ``` + /// -#### Link impairments +3. Perform a test ping to make sure our configuration works + + ``` + A:admin@srl1# ping 10.1.2.2 network-instance default -c 4 + Using network instance default + PING 10.1.2.2 (10.1.2.2) 56(84) bytes of data. + 64 bytes from 10.1.2.2: icmp_seq=1 ttl=64 time=2.29 ms + 64 bytes from 10.1.2.2: icmp_seq=2 ttl=64 time=3.17 ms + 64 bytes from 10.1.2.2: icmp_seq=3 ttl=64 time=3.25 ms + 64 bytes from 10.1.2.2: icmp_seq=4 ttl=64 time=3.50 ms -Now that the interfaces between the nodes are configured, we can try out the link impairment functionality. + --- 10.1.2.2 ping statistics --- + 4 packets transmitted, 4 received, 0% packet loss, time 3004ms + rtt min/avg/max/mdev = 2.289/3.050/3.496/0.455 ms + ``` -Start a ping between the two nodes, and introduce delay using either of the following methods. +#### Packet capture -1. The impairment editor: +Now that we have established connectivity between the two nodes, let's try and take a look at what is actually going across the link. - You can navigate to the link impairment editor by right clicking on the node in the tree view and selecting **Link Impairments**. In realtime we should see the ping RTT increase due to the delay. +Packet capture is important to see what's happening in your lab. In the extension this is made easy with a fully integrated Wireshark experience. - ![Link impairment editor](../images/tools-clab-vscode-plugin/impairment-editor.png) +Go back to the tree view, expand the lab and container nodes so that you can see their interfaces. If you hover over the interfaces you should see a Wireshark icon  :simple-wireshark:. -2. Set delay on the Interface: +Upon clicking it, you should notice Wireshark has now opened in a tab in your VS Code window. - Right-click on the intended interface and select set delay, you will be prompted to set the link delay. +If you inititate another ping, you should see the ICMP packets on the link. - ![Link impairment editor](../images/tools-clab-vscode-plugin/set-delay-2.png) +/// admonition | How does this work? + type: question +Wireshark runs in a Linux container on the Containerlab host. The container has minimal packages ensure the Wireshark GUI is displayed. The Wireshark window is launched and then streamed via VNC into your VS Code window. -#### Packet capture +When connecting using VS Code remote functionality, the VNC is streamed securely through the VS Code remote tunnel. No extra external ports are opened. +/// + +#### Link impairments + +We can ping between our nodes, and inspect the packets with Wireshark. Last of all let's try the link impairments. -Packet capture is important to see what's going on in your lab. In the extension we can initiate a packet capture by simply clicking on the  :simple-wireshark:  icon on the interface in the tree view. +Link impairments let us impair the quality of the link by setting packet loss, corruption, jitter and packet corruption. This is useful for simulation of real-world scenarios such as long-distance or damaged/degraded links. -This will only work if you: +Let's start a ping between the two nodes (omit the `-c 4` option so the ping is infinite). -1. Have Edgeshark installed on your Containerlab system. -2. Have the local [cshargextcap](https://github.com/siemens/cshargextcap/releases/latest) plugin for Wireshark installed locally. +Enter the impairment editor by right clicking on one of the nodes in the tree, and selecting the 'Link impairments' option in the context menu. This will open the impairment editor. -??? tip "How to install edgeshark" - Press `CTRL`+`SHIFT`+`P` to open the command palette. You can then type 'Edgeshark' and select **Containerlab: Install Edgeshark**. Done. +Set some significant delay on the `e1-1` interface, such as 1 second. You should notice the time in your ping increase accordingly. - ![Install Edgeshark command palette](../images/tools-clab-vscode-plugin/install-edgeshark.png) +Play around with the other impairments. Set some packet loss, or corruption and check the Wireshark capture. Sky is the limit. +![Link impairment delay ping verification](https://gitlab.com/srexperts/artifacts/-/wikis/uploads/52b291053586c35f3481c926ba40faa1/15-link_impairment_demo.gif) -![Capture interface](../images/tools-clab-vscode-plugin/capture-interface-2.png) ## Summary Now that you have reached the end of this activity, you should now know the following: - How to use the Containerlab VS Code extension. -- How to create a topology using the TopoEditor GUI. +- How to create a topology using the TopoViewer GUI. - How to manage the lifecycle of a lab from the tree view. - Visualization of labs. - Interaction with interfaces of your lab. - Interaction with nodes of your lab. -Keep exploring, there are far more possibilities provided by VS Code Containerlab extension. \ No newline at end of file +Keep exploring, there are far more possibilities provided by VS Code Containerlab extension. diff --git a/eda/README.md b/eda/README.md index 5673f22..86e7bd3 100644 --- a/eda/README.md +++ b/eda/README.md @@ -2,28 +2,6 @@ Note: these commands are for documentation purposes only, everything has been preempted on the cloud instances. -## Copy files - -To copy the files from this repo to a remote system: - -```shell -# RS_DEST=nokia@1.edadev.srexperts.net -# RS_REMOTE_DEST=/home/nokia/eda -RS_DEST=demo1.ohn81 -RS_REMOTE_DEST=/root/eda -rsync -avz --delete eda/fabric ${RS_DEST}:${RS_REMOTE_DEST} -``` - -```shell -# RS_DEST=nokia@1.edadev.srexperts.net -# RS_REMOTE_DEST=/home/nokia/eda -RS_DEST=demo1.ohn81 -RS_REMOTE_DEST=/root/eda -rsync -avz --delete eda/topo-onboard ${RS_DEST}:${RS_REMOTE_DEST} -``` - -will move the `fabric` dir to `/root/eda` on the remote system. - ## Clone playground The playground dir needs to be present on the target system @@ -56,8 +34,8 @@ make download-k9s Copy the kubectl and k9s tools from the playground/tools dir to `/usr/local/bin` so they are available to a user: ```shell -cp ./tools/kubectl* /usr/local/bin/kubectl -cp ./tools/k9s* /usr/local/bin/k9s +cp $(realpath ./tools/kubectl) /usr/local/bin/kubectl +cp $(realpath ./tools/k9s) /usr/local/bin/k9s ``` ### kubectl completions @@ -98,7 +76,7 @@ alias edactl='kubectl -n eda-system exec -it $(kubectl -n eda-system get pods \ ## Deploy containerlab topo -The clab topo needs to be deployed without startup configs mounted to the DC1 nodes; this requirement will be lifted once the BGP fix is merged into SRL. +The clab topo needs to be deployed without startup configs mounted to the DC1 nodes; this requirement will be lifted with 24.10.5 and 25.7+ releases (DTS 479993). For now, we need to comment out the startup configs by running the following: @@ -108,16 +86,27 @@ uv run clab/comment-startup.py Note, that currently the client nodes require the bonding kernel to be loaded to support the bond interfaces: -``` +```bash sudo modprobe bonding mmiimon=100 mode=802.3ad lacp_rate=fast ``` +The clab topology make use of the following env vars, make sure they are set in your env: + +- INSTANCE_ID +- EVENT_PASSWORD +- NOKIA_UID +- NOKIA_GID + +Proceed with deploying the topology: + +```bash +containerlab deploy -c -t ./clab +``` + ## Deploy EDA ```shell -# EDA_DN=1.edadev.srexperts.net -EDA_DN=10.181.131.41 -SIMULATE=false EXT_DOMAIN_NAME=${EDA_DN} make try-eda +SIMULATE=false make try-eda ``` ## Add EDA License @@ -136,13 +125,9 @@ To enable users to revert to an initial state the EDA was deployed, we need to s Execute `bash eda/record-init-tx.sh` script that will store the `TX_ID TX_HASH` pair in the `/opt/srexperts/eda-init-tx` file. This file then can be used to revert EDA to this transaction. -## Exposing EDA UI +## Accessing EDA UI -EDA UI is automatically exposed when `make try-eda` finishes. But whenever there are issues with UI access we might need to restart the service: - -``` -make start-ui-port-forward -``` +EDA UI is automatically exposed when `make try-eda` finishes. No additional steps required to access the UI. It is exposed over HTTPS, port 9443. ## Onboard SRX Topology @@ -153,14 +138,14 @@ Start with substituting env vars in the the topo onboard files. Change into the ```shell docker run --rm -e INSTANCE_ID=$(echo $INSTANCE_ID) -e EVENT_PASSWORD=$(echo $EVENT_PASSWORD) \ -u $(id -u):$(id -g) \ --v $(pwd)/topo-onboard/clab:/work \ +-v $(pwd)/eda/topo-onboard/clab:/work \ ghcr.io/hellt/envsubst:0.1.0 ``` Then apply the templated onboarding resources: ```shell -kubectl apply -f $(pwd)/topo-onboard/clab +kubectl apply -f $(pwd)/eda/topo-onboard/clab ``` ## Deploy Fabric @@ -168,8 +153,8 @@ kubectl apply -f $(pwd)/topo-onboard/clab Before we deploy the fabric, we need to remove some default allocation pools to keep the UI clean and let attendees create pools as they need them. ```shell -# assuming you are in the ./eda directory -bash cleanup-pools.sh +# assuming you are in the repo root +bash ./eda/cleanup-pools.sh ``` Then we need to apply the fabric resources so that the fabric is provisioned on the srl nodes, because when EDA onboards the nodes it takes control over the config and pushes the config as it is provided in the CRs. @@ -179,14 +164,14 @@ Again, run the substitute env vars script over the fabric resources: ```shell docker run --rm -e INSTANCE_ID=$(echo $INSTANCE_ID) -e EVENT_PASSWORD=$(echo $EVENT_PASSWORD) \ -u $(id -u):$(id -g) \ --v $(pwd)/fabric:/work \ +-v $(pwd)/eda/fabric:/work \ ghcr.io/hellt/envsubst:0.1.0 ``` and apply them: ```shell -kubectl apply -f $(pwd)/fabric +kubectl apply -f $(pwd)/eda/fabric ``` ## Extract the kubeconfig @@ -209,3 +194,25 @@ bash /opt/srexperts/restore-eda.sh ``` This script restores the transaction recorded in `/opt/srexperts/eda-init-tx` by the lab provisioning script. The transaction stored in this file is the last transaction of the deployment/onboarding and represents the starting state of the platform. + +## Copy files + +To copy the files from this repo to a remote system: + +```shell +# RS_DEST=nokia@1.edadev.srexperts.net +# RS_REMOTE_DEST=/home/nokia/eda +RS_DEST=demo1.ohn81 +RS_REMOTE_DEST=/root/eda +rsync -avz --delete eda/fabric ${RS_DEST}:${RS_REMOTE_DEST} +``` + +```shell +# RS_DEST=nokia@1.edadev.srexperts.net +# RS_REMOTE_DEST=/home/nokia/eda +RS_DEST=demo1.ohn81 +RS_REMOTE_DEST=/root/eda +rsync -avz --delete eda/topo-onboard ${RS_DEST}:${RS_REMOTE_DEST} +``` + +will move the `fabric` dir to `/root/eda` on the remote system. diff --git a/eda/fabric/50_bgp-pe-group.yaml b/eda/fabric/50_bgp-pe-group.yaml index b884ead..361fcb4 100644 --- a/eda/fabric/50_bgp-pe-group.yaml +++ b/eda/fabric/50_bgp-pe-group.yaml @@ -1,4 +1,4 @@ -apiVersion: protocols.eda.nokia.com/v1alpha1 +apiVersion: protocols.eda.nokia.com/v1 kind: DefaultBGPGroup metadata: name: bgpgroup-ebgp-pe diff --git a/eda/fabric/70_bgp-pe-peers.yaml b/eda/fabric/70_bgp-pe-peers.yaml index f149834..2d5cb95 100644 --- a/eda/fabric/70_bgp-pe-peers.yaml +++ b/eda/fabric/70_bgp-pe-peers.yaml @@ -1,4 +1,4 @@ -apiVersion: protocols.eda.nokia.com/v1alpha1 +apiVersion: protocols.eda.nokia.com/v1 kind: DefaultBGPPeer metadata: name: uplink-unnumbered-spine11-pe2 @@ -28,7 +28,7 @@ spec: sendCommunityLarge: false sendCommunityStandard: false --- -apiVersion: protocols.eda.nokia.com/v1alpha1 +apiVersion: protocols.eda.nokia.com/v1 kind: DefaultBGPPeer metadata: name: uplink-unnumbered-spine11-pe3 @@ -58,7 +58,7 @@ spec: sendCommunityLarge: false sendCommunityStandard: false --- -apiVersion: protocols.eda.nokia.com/v1alpha1 +apiVersion: protocols.eda.nokia.com/v1 kind: DefaultBGPPeer metadata: name: uplink-unnumbered-spine12-pe2 @@ -88,7 +88,7 @@ spec: sendCommunityLarge: false sendCommunityStandard: false --- -apiVersion: protocols.eda.nokia.com/v1alpha1 +apiVersion: protocols.eda.nokia.com/v1 kind: DefaultBGPPeer metadata: name: uplink-unnumbered-spine12-pe3 diff --git a/eda/fabric/80_vnet.yaml b/eda/fabric/80_vnet.yaml index b7637ec..30407a8 100644 --- a/eda/fabric/80_vnet.yaml +++ b/eda/fabric/80_vnet.yaml @@ -1,4 +1,4 @@ -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: VirtualNetwork metadata: name: vnet201 diff --git a/eda/fabric/90_bridge-domain.yaml b/eda/fabric/90_bridge-domain.yaml index dac7712..c56aa1b 100644 --- a/eda/fabric/90_bridge-domain.yaml +++ b/eda/fabric/90_bridge-domain.yaml @@ -1,4 +1,4 @@ -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: BridgeDomain metadata: name: macvrf1 @@ -6,7 +6,7 @@ metadata: labels: role: hackathon-infra spec: - # TODO uncomment when 25.4 + # TODO revisit this bd config before 25.12 #description: MAC-VRF for connectivity via the GRT of the WAN evi: 1 eviPool: evi-pool diff --git a/eda/fabric/91_vlan.yaml b/eda/fabric/91_vlan.yaml index 09e0f16..4550d35 100644 --- a/eda/fabric/91_vlan.yaml +++ b/eda/fabric/91_vlan.yaml @@ -1,4 +1,4 @@ -apiVersion: services.eda.nokia.com/v1alpha1 +apiVersion: services.eda.nokia.com/v1 kind: VLAN metadata: name: vlan1 diff --git a/eda/topo-onboard/clab/containerlab-integration-crs.yml b/eda/topo-onboard/clab/containerlab-integration-crs.yml index 8194f00..c963eb9 100644 --- a/eda/topo-onboard/clab/containerlab-integration-crs.yml +++ b/eda/topo-onboard/clab/containerlab-integration-crs.yml @@ -2,14 +2,14 @@ apiVersion: artifacts.eda.nokia.com/v1 kind: Artifact metadata: - name: srlinux-ghcr-24.10.4 + name: srlinux-ghcr-24.10.3 namespace: eda-system labels: role: hackathon-infra spec: - filePath: srlinux-24.10.4.zip + filePath: srlinux-24.10.3.zip remoteFileUrl: - fileUrl: https://github.com/nokia/srlinux-yang-models/releases/download/v24.10.4/srlinux-24.10.4-244.zip + fileUrl: https://github.com/nokia/srlinux-yang-models/releases/download/v24.10.3/srlinux-24.10.3-201.zip repo: schemaprofiles # --- INIT --- --- @@ -60,6 +60,9 @@ spec: - GNMI - CLI - NETCONF + - GNOI + - GNSI + - JSON-RPC superuser: true --- # --- NODE-USER --- @@ -117,7 +120,7 @@ spec: apiVersion: core.eda.nokia.com/v1 kind: NodeProfile metadata: - name: srexperts-srlinux-24.10.4 + name: srexperts-srlinux-24.10.3 namespace: eda labels: role: hackathon-infra @@ -125,10 +128,10 @@ spec: port: 57410 annotate: true operatingSystem: srl - version: 24.10.4 + version: 24.10.3 versionPath: .system.information.version - versionMatch: v24\.10\.4.* - yang: https://eda-asvr.eda-system/eda-system/schemaprofiles/srlinux-ghcr-24.10.4/srlinux-24.10.4.zip + versionMatch: v24\.10\.3.* + yang: https://eda-asvr.eda-system/eda-system/schemaprofiles/srlinux-ghcr-24.10.3/srlinux-24.10.3.zip nodeUser: admin onboardingPassword: NokiaSrl1! onboardingUsername: admin @@ -151,10 +154,10 @@ metadata: role: hackathon-infra namespace: eda spec: - nodeProfile: srexperts-srlinux-24.10.4 + nodeProfile: srexperts-srlinux-24.10.3 operatingSystem: srl platform: 7220 IXR-D2L - version: 24.10.4 + version: 24.10.3 productionAddress: ipv4: 10.128.${INSTANCE_ID}.33 ipv6: "" @@ -172,10 +175,10 @@ metadata: role: hackathon-infra namespace: eda spec: - nodeProfile: srexperts-srlinux-24.10.4 + nodeProfile: srexperts-srlinux-24.10.3 operatingSystem: srl platform: 7220 IXR-D2L - version: 24.10.4 + version: 24.10.3 productionAddress: ipv4: 10.128.${INSTANCE_ID}.34 ipv6: "" @@ -193,10 +196,10 @@ metadata: role: hackathon-infra namespace: eda spec: - nodeProfile: srexperts-srlinux-24.10.4 + nodeProfile: srexperts-srlinux-24.10.3 operatingSystem: srl platform: 7220 IXR-D2L - version: 24.10.4 + version: 24.10.3 productionAddress: ipv4: 10.128.${INSTANCE_ID}.35 ipv6: "" @@ -214,10 +217,10 @@ metadata: role: hackathon-infra namespace: eda spec: - nodeProfile: srexperts-srlinux-24.10.4 + nodeProfile: srexperts-srlinux-24.10.3 operatingSystem: srl platform: 7220 IXR-H2 - version: 24.10.4 + version: 24.10.3 productionAddress: ipv4: 10.128.${INSTANCE_ID}.31 ipv6: "" @@ -235,10 +238,10 @@ metadata: role: hackathon-infra namespace: eda spec: - nodeProfile: srexperts-srlinux-24.10.4 + nodeProfile: srexperts-srlinux-24.10.3 operatingSystem: srl platform: 7220 IXR-H2 - version: 24.10.4 + version: 24.10.3 productionAddress: ipv4: 10.128.${INSTANCE_ID}.32 ipv6: "" @@ -741,6 +744,7 @@ spec: ] } + # --- EDA COMMON SECURE GRPC SERVER --- # since EDA removes any prior existing config from the node # we need to bring back the explicit server running on port 57401 @@ -777,6 +781,7 @@ spec: ] } + # --- EDA COMMON SYSLOG SERVER --- # considering we don't have a way (yet) to configure a # common syslog server, this makes sure the SReXperts @@ -815,6 +820,8 @@ spec: } ] } + + # --- EDA SYSTEM DEFAULT IP MTU --- # considering we don't have a way (yet) to configure a # common default ip mtu, this makes sure the SReXperts diff --git a/eda/topo-onboard/restore-srl.sh b/eda/topo-onboard/restore-srl.sh new file mode 100644 index 0000000..acf7de6 --- /dev/null +++ b/eda/topo-onboard/restore-srl.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# for containers with names clab-srexperts-leaf11 clab-srexperts-leaf12 clab-srexperts-leaf13 clab-srexperts-spine11 clab-srexperts-spine12 +# For containers with names clab-srexperts-leaf11, clab-srexperts-leaf12, clab-srexperts-leaf13, clab-srexperts-spine11, and clab-srexperts-spine12, execute the revert command that removes the EDA configuration and restores the initial state of the DC1 nodes. +REVERT_CMD="sr_cli tools system configuration checkpoint clab-initial revert" +NODES=("leaf11" "leaf12" "leaf13" "spine11" "spine12") + +for node in "${NODES[@]}"; do + docker exec -it clab-srexperts-$node ${REVERT_CMD} +done \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b6d02f0..cc6b2fc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,27 +34,27 @@ nav: - nos/srlinux/beginner/b-srl-oc.md - Intermediate: - nos/srlinux/intermediate/nos-srl-activity-12.md - - nos/srlinux/intermediate/20-SRLinux-Basic-Agent.md - nos/srlinux/intermediate/19-SRLinux-Custom-CLI.md - nos/srlinux/intermediate/58-programming-snmp-mibs.md - Advanced: - - nos/srlinux/advanced/nos-srlinux-activity-18.md + - nos/srlinux/advanced/nos-srlinux-activity-18.md + - nos/srlinux/advanced/20-SRLinux-Basic-Agent.md - Network Services Platform (NSP): - nsp/index.md - Beginner: - Acknowledge Alarms: nsp/beginner/60-nsp-alarm-ack.md - Indicator Analytics: nsp/beginner/68-indicator-analytics.md - Baseline Analytics: nsp/beginner/69-nsp-baseline-analytics.md - - Inventory Report using WFM: nsp/beginner/70-nsp-inventory-report-using-workflow.md + - Inventory Reports: nsp/beginner/70-nsp-inventory-report-using-workflow.md - Intermediate: - - Device-specific Infra Config: nsp/intermediate/48-nsp-device-specific-infra-config.md + - Infrastructure Configuration: nsp/intermediate/48-nsp-device-specific-infra-config.md - NE Password Audit/Align: nsp/intermediate/66-nsp-ne-password-audit.md - - NE config snapshot/rollback: nsp/intermediate/71-nsp-ne-config-snapshot-rollback.md - - Port Migration: nsp/intermediate/51-nsp-access-port-migration.md + - NE Config Snapshot/Rollback: nsp/intermediate/71-nsp-ne-config-snapshot-rollback.md + - Access Port Migration: nsp/intermediate/51-nsp-access-port-migration.md - Advanced: - - Golden Security Configuration: nsp/advanced/73-nsp-golden-cfg-security.md + - Security Baseline Configuration: nsp/advanced/73-nsp-golden-cfg-security.md - Integrating NSP w/ NetBox: nsp/advanced/57-nsp-netbox.md - - TLDP to EVPN Migration: nsp/advanced/72-nsp-tldp-to-evpn-migration.md + - Service Migration from TLDP to EVPN: nsp/advanced/72-nsp-tldp-to-evpn-migration.md - Event Driven Automation (EDA): - eda/index.md - Beginner: @@ -84,7 +84,7 @@ site_description: >- repo_name: nokia/SReXperts repo_url: https://github.com/nokia/SReXperts edit_uri: edit/main/docs/ -site_url: "https://hack.srexperts.net/" +site_url: "https://hackathon.srexperts.net/" copyright: Copyright © 2021-2025 Nokia theme: name: material