From d113fbe77eb028ace7080b09c04cf23e2dd52f06 Mon Sep 17 00:00:00 2001 From: Mark90 Date: Thu, 2 Jul 2026 10:27:10 +0200 Subject: [PATCH 1/7] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index de0f2db..2da31ef 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ lint.sh clab-* *.clab.yml.bak .env + +# Artifacts from the e2e tests +screenshots/ From ddcbef31abfef54cd4c3ab5b437088e3f6505a3b Mon Sep 17 00:00:00 2001 From: Mark90 Date: Thu, 2 Jul 2026 11:15:30 +0200 Subject: [PATCH 2/7] Add .env.workshop --- .env.workshop | 1 + 1 file changed, 1 insertion(+) create mode 100644 .env.workshop diff --git a/.env.workshop b/.env.workshop new file mode 100644 index 0000000..6c5d77c --- /dev/null +++ b/.env.workshop @@ -0,0 +1 @@ +export COMPOSE_PROFILES=lso From af7e9cd67e924e889817a42bb851edb004e34660 Mon Sep 17 00:00:00 2001 From: Mark90 Date: Thu, 2 Jul 2026 12:00:38 +0200 Subject: [PATCH 3/7] Fix lso/Dockerfile build failing on missing ANSIBLE_COLLECTIONS_PATH --- docker-compose.yml | 1 - docker/lso/Dockerfile | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f987d0c..dbc6eb4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -211,7 +211,6 @@ services: lso: container_name: orchestrator-lso - #image: orchestrator-lso profiles: - lso build: diff --git a/docker/lso/Dockerfile b/docker/lso/Dockerfile index bebe68b..0814b05 100644 --- a/docker/lso/Dockerfile +++ b/docker/lso/Dockerfile @@ -8,7 +8,8 @@ RUN pip install orchestrator-lso=="3.0.0" RUN pip install pynetbox ansible -RUN mkdir -p $ANSIBLE_COLLECTIONS_PATH +# TODO Check with Karel if this is needed. It was causing the build to fail, commenting out seems to work fine. +# RUN mkdir -p $ANSIBLE_COLLECTIONS_PATH RUN ansible-galaxy collection install nokia.srlinux From 505d7155bf55911cf3615220c990ecf3eccccdf9 Mon Sep 17 00:00:00 2001 From: Mark90 Date: Thu, 2 Jul 2026 14:41:17 +0200 Subject: [PATCH 4/7] Fixes for LSO --- .env.workshop | 1 + README.md | 2 +- ansible/plays_and_roles/create_node.yaml | 2 +- docker-compose.yml | 2 +- docker/lso/Dockerfile | 6 ++++-- docker/lso/lso.env | 1 + 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.env.workshop b/.env.workshop index 6c5d77c..06c241e 100644 --- a/.env.workshop +++ b/.env.workshop @@ -1 +1,2 @@ export COMPOSE_PROFILES=lso +export LSO_ENABLED=True diff --git a/README.md b/README.md index 50fb33a..8dbd72a 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ This will start the `orchestrator`, `orchestrator-ui`, `netbox`, `federation`, ` To include LSO, run the following command instead: ``` -COMPOSE_PROFILES=lso docker compose up +COMPOSE_PROFILES=lso LSO_ENABLED=True docker compose up ``` This will build the Docker image for LSO locally, and make the orchestrator use the included Ansible playbooks. diff --git a/ansible/plays_and_roles/create_node.yaml b/ansible/plays_and_roles/create_node.yaml index 4be4da6..7cb0191 100644 --- a/ansible/plays_and_roles/create_node.yaml +++ b/ansible/plays_and_roles/create_node.yaml @@ -7,7 +7,7 @@ ansible_user: admin ansible_password: NokiaSrl1! netbox_url: "http://netbox:8080" - netbox_token: "e744057d755255a31818bf74df2350c26eeabe54" + netbox_token: "nbt_sDx3hakFeTCZ.lnGwrK42a7z1IelVaigWXqaAB0GKSpbOSZKTrLdb" debug: false tasks: - name: Dump subscripion diff --git a/docker-compose.yml b/docker-compose.yml index dbc6eb4..395704e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -169,7 +169,7 @@ services: - path: ./docker/overrides/orchestrator/orchestrator.env required: false environment: - LSO_ENABLED: ${COMPOSE_PROFILES:+True} + LSO_ENABLED: ${LSO_ENABLED:-False} ports: - "8080:8080" - "5678:5678" #Enable Python debugger diff --git a/docker/lso/Dockerfile b/docker/lso/Dockerfile index 0814b05..94796c2 100644 --- a/docker/lso/Dockerfile +++ b/docker/lso/Dockerfile @@ -1,5 +1,8 @@ FROM python:3.13.13-alpine +# Keep in sync with lso/lso.env +ENV ANSIBLE_COLLECTIONS_PATH=/app/demo/ansible/ansible_collections + WORKDIR /app RUN apk add --update --no-cache gcc libc-dev libffi-dev @@ -8,8 +11,7 @@ RUN pip install orchestrator-lso=="3.0.0" RUN pip install pynetbox ansible -# TODO Check with Karel if this is needed. It was causing the build to fail, commenting out seems to work fine. -# RUN mkdir -p $ANSIBLE_COLLECTIONS_PATH +RUN mkdir -p $ANSIBLE_COLLECTIONS_PATH RUN ansible-galaxy collection install nokia.srlinux diff --git a/docker/lso/lso.env b/docker/lso/lso.env index 6e417b2..7a06deb 100644 --- a/docker/lso/lso.env +++ b/docker/lso/lso.env @@ -2,6 +2,7 @@ # Ansible configuration ANSIBLE_PLAYBOOKS_ROOT_DIR="/app/demo/ansible/playbooks" +# Keep in sync with lso/Dockerfile ANSIBLE_COLLECTIONS_PATH="/app/demo/ansible/ansible_collections" ANSIBLE_HOST_KEY_CHECKING: "False" From 88de91e1a639af4ba350b4a723218fcf2d75c5cf Mon Sep 17 00:00:00 2001 From: Peter Boers Date: Thu, 2 Jul 2026 15:43:05 +0200 Subject: [PATCH 5/7] Added startup config to the SRL and added working instructions for MacOS --- README.md | 57 ++++++++++++++++++++++++++++ clab/configs/srl-jsonrpc.partial.cli | 2 + clab/srlinux01.clab.yaml | 2 + 3 files changed, 61 insertions(+) create mode 100644 clab/configs/srl-jsonrpc.partial.cli diff --git a/README.md b/README.md index 8dbd72a..51f2e17 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,63 @@ Example workflow orchestrator implementation based on the ## Quickstart +### Docker runtime on Apple Silicon (colima + virtiofs) + +!!! note + + This section is **only** needed on **ARM / Apple Silicon (M-series) Macs**. On + Linux and Intel machines the stock Docker install works and you can skip ahead + to [Start application](#start-application). + +The containerlab SR Linux nodes (`clab/srlinux01.clab.yaml`) don't run under a +default macOS Docker setup. They need a Docker VM that mounts host paths with +**virtiofs** and has enough memory. Two hard requirements, both learned the hard +way: + +- **`virtiofs` mounts, not `sshfs`.** SR Linux generates a TLS keypair at boot and + `chown`s it. `sshfs` (colima's legacy mount type) forbids `chown` even as root, + so the keygen fails, `sr_linux_mgr` crash-loops, and no management server + (JSON-RPC / gNMI / gRPC) ever comes online. +- **≥ 8 GB VM memory.** Each SR Linux node reserves ~2 GB. On a smaller VM the + kernel OOM-killer repeatedly kills `sr_mgmt_server` and the nodes never settle. + +Install [colima](https://github.com/abiosoft/colima) and the Docker CLI, then +create the VM with the right settings: + +```bash +brew install colima docker + +# vm-type vz + virtiofs is the Apple Silicon fast/reliable path. +# Sizes: 8 GB RAM / 4 CPUs comfortably runs the 3-node lab + the compose stack. +colima start --vm-type vz --mount-type virtiofs --memory 8 --cpu 4 +``` + +!!! danger "Do not run Docker Desktop at the same time as colima" + + Both register a `docker` CLI context and fight over the `/var/run/docker.sock` + symlink and host ports, giving you a broken, non-deterministic Docker setup. + Quit Docker Desktop (and disable "Start at login") before using colima. + +!!! warning "`mountType` / `vmType` are fixed at VM creation" + + The `--mount-type`/`--vm-type` flags are silently ignored on an existing VM. + If your colima VM was created with `sshfs`, recreate it (this destroys the + VM's containers, images and volumes): + + ```bash + colima delete && colima start --vm-type vz --mount-type virtiofs --memory 8 --cpu 4 + ``` + + Memory and CPU, by contrast, *can* be changed on a plain restart: + `colima stop && colima start --memory 8 --cpu 4`. + +Verify the VM before continuing: + +```bash +colima status | grep mountType # -> mountType: virtiofs +colima ssh -- free -h # Mem total should be ~8 GB +``` + ### Start application Make sure you have docker installed and run: diff --git a/clab/configs/srl-jsonrpc.partial.cli b/clab/configs/srl-jsonrpc.partial.cli new file mode 100644 index 0000000..a41d8a1 --- /dev/null +++ b/clab/configs/srl-jsonrpc.partial.cli @@ -0,0 +1,2 @@ +set / system json-rpc-server admin-state enable +set / system json-rpc-server network-instance mgmt http admin-state enable diff --git a/clab/srlinux01.clab.yaml b/clab/srlinux01.clab.yaml index 5c7f4b2..57aed0b 100644 --- a/clab/srlinux01.clab.yaml +++ b/clab/srlinux01.clab.yaml @@ -8,6 +8,8 @@ topology: srl: type: ixrd2 image: ghcr.io/nokia/srlinux:25.7.1 + # Enable JSON-RPC (HTTP) at boot so the orchestrator can reach every srl node. + startup-config: configs/srl-jsonrpc.partial.cli # cvx: # type: cumulus_cvx # image: networkop/cx:4.3.0 From 93adedb765acb64b83bc127340d2ecd8c59472a9 Mon Sep 17 00:00:00 2001 From: Peter Boers Date: Thu, 2 Jul 2026 15:57:26 +0200 Subject: [PATCH 6/7] Added ARM instructions --- README.md | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 51f2e17..9bad22b 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,10 @@ Example workflow orchestrator implementation based on the ### Docker runtime on Apple Silicon (colima + virtiofs) -!!! note - - This section is **only** needed on **ARM / Apple Silicon (M-series) Macs**. On - Linux and Intel machines the stock Docker install works and you can skip ahead - to [Start application](#start-application). +> [!NOTE] +> This section is **only** needed on **ARM / Apple Silicon (M-series) Macs**. On +> Linux and Intel machines the stock Docker install works and you can skip ahead +> to [Start application](#start-application). The containerlab SR Linux nodes (`clab/srlinux01.clab.yaml`) don't run under a default macOS Docker setup. They need a Docker VM that mounts host paths with @@ -107,24 +106,24 @@ brew install colima docker colima start --vm-type vz --mount-type virtiofs --memory 8 --cpu 4 ``` -!!! danger "Do not run Docker Desktop at the same time as colima" - - Both register a `docker` CLI context and fight over the `/var/run/docker.sock` - symlink and host ports, giving you a broken, non-deterministic Docker setup. - Quit Docker Desktop (and disable "Start at login") before using colima. - -!!! warning "`mountType` / `vmType` are fixed at VM creation" - - The `--mount-type`/`--vm-type` flags are silently ignored on an existing VM. - If your colima VM was created with `sshfs`, recreate it (this destroys the - VM's containers, images and volumes): - - ```bash - colima delete && colima start --vm-type vz --mount-type virtiofs --memory 8 --cpu 4 - ``` - - Memory and CPU, by contrast, *can* be changed on a plain restart: - `colima stop && colima start --memory 8 --cpu 4`. +> [!CAUTION] +> **Do not run Docker Desktop at the same time as colima.** Both register a +> `docker` CLI context and fight over the `/var/run/docker.sock` symlink and host +> ports, giving you a broken, non-deterministic Docker setup. Quit Docker Desktop +> (and disable "Start at login") before using colima. + +> [!WARNING] +> `mountType` and `vmType` can **only** be set when the VM is first created — the +> `--mount-type`/`--vm-type` flags are silently ignored on an existing VM. If your +> colima VM was created with `sshfs`, recreate it (this destroys the VM's +> containers, images and volumes): +> +> ```bash +> colima delete && colima start --vm-type vz --mount-type virtiofs --memory 8 --cpu 4 +> ``` +> +> Memory and CPU, by contrast, *can* be changed on a plain restart: +> `colima stop && colima start --memory 8 --cpu 4`. Verify the VM before continuing: From 7868afb50e82330de040fdb0fc3a0eedae2fa70e Mon Sep 17 00:00:00 2001 From: Mark90 Date: Thu, 2 Jul 2026 15:59:23 +0200 Subject: [PATCH 7/7] Update readme wording and typos --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9bad22b..ef34636 100644 --- a/README.md +++ b/README.md @@ -478,7 +478,7 @@ are defined: - SAPBlock - VirtualCircuitBlock -Usually, the top-level product block if a product is named after the +Usually, the top-level product block of a product is named after the product, but this is not true for the top-level product block of the L2VPN product. The more generic name `VirtualCIrcuitBlock` allows the reuse of this product block by other services like Internet Access and @@ -687,7 +687,7 @@ class Port(PortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): ``` As can be seen in the above example, the inactive product type -definition is subclassed from SubScriptionModel, and the following +definition is subclassed from SubscriptionModel, and the following definitions are subclassed from the previous one. This product has one fixed input called speed and one port product block (see below about naming). Notice that the port product block matches the lifecycle of the @@ -797,9 +797,8 @@ optional to allow the creation of an empty product block instance. All resource types that are used to hold the user input for the subscription is stored using resource types that are not optional anymore in the provisioning lifecycle state. All resource types used to store -information that is generated while provisioning the subscription is -stored using resource types that are optional while provisioning but are -not optional anymore for the active lifecycle state. Resource types that +information for the provisioning lifecycle state are optional, but they aren't +optional for the active lifecycle state. Resource types that are still optional in the active state are used to store non-mandatory information. @@ -847,7 +846,7 @@ not fail. Sometimes there are resource types that depend on information stored on other product blocks, even on linked product blocks that do not belong -to the same subscription. This kind of types need to be calculated at +to the same subscription. This allows for types to be calculated at run time so that they include the most recent information. Consider the following example of a, stripped down version, of a port and node product block, and a title for the port block that is generated @@ -861,7 +860,8 @@ class PortBlock(PortBlockProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]) port_name: str node: NodeBlock - @serializable_property + @computed_field + @property def title(self) -> str: return f"{self.port_name} on {self.node.node_name}" @@ -869,11 +869,11 @@ class Port(PortProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]): port: PortBlock ``` -A `@serializable_property` has been added that will dynamically render +A `@computed_field` has been added that will dynamically render the title of the port product block. Even after a modify workflow was run to change the node name on the node subscription, the title of the port block will always be up to date. The title can be referenced as any -other resource type using subscription.port.title. This is not a random +other resource type using `subscription.port.title`. This is not a fictional example, the title of a product block is used by the orchestrator GUI while displaying detailed subscription information.