From 2843b90ccd8fbff7e1a4837653fb9ae203654f78 Mon Sep 17 00:00:00 2001 From: Robert Gildein Date: Tue, 11 Aug 2026 16:11:27 +0200 Subject: [PATCH] feat(agentic): Add Claude skills for local dev and testing Add 3 skills for local dev and testing: 1. netop-check: run lint, unit and gnmic tests with summary output - capable to reformat code if needed 2. netop-setup: configure VM with all tools, k8s cluster and Nokia device with summary output - using colima to create VM, but can use another tools like multipass, ... - can be run without creating VM, for direct use on Linux machine - can omit creating device in containerlab if user provided connection to existing one 3. netop-test: to run manual test - deploy custom CRDs and verify that configuration was properly set via gnmic Signed-off-by: Robert Gildein --- .claude/skills/netop-check/SKILL.md | 105 +++++++++++ .claude/skills/netop-setup/SKILL.md | 249 +++++++++++++++++++++++++ .claude/skills/netop-test/SKILL.md | 279 ++++++++++++++++++++++++++++ README.md | 121 ++++++++++++ 4 files changed, 754 insertions(+) create mode 100644 .claude/skills/netop-check/SKILL.md create mode 100644 .claude/skills/netop-setup/SKILL.md create mode 100644 .claude/skills/netop-test/SKILL.md diff --git a/.claude/skills/netop-check/SKILL.md b/.claude/skills/netop-check/SKILL.md new file mode 100644 index 000000000..8f563d7dc --- /dev/null +++ b/.claude/skills/netop-check/SKILL.md @@ -0,0 +1,105 @@ +--- +name: netop-check +description: Run local development checks for network-operator — lint, unit tests, and gNMI integration tests. Use before committing or opening a PR. All commands run on the host machine (no VM needed). +argument-hint: [lint | test | all] +allowed-tools: [Bash, Read, AskUserQuestion] +--- + +# netop-check + +Runs local development checks: +1. Vet (go vet — fast static analysis) +2. Lint (golangci-lint) +3. Unit tests +4. gNMI functional tests + +All commands run directly on the host machine in the repo root. + +## Current changes + +```bash +git diff HEAD +``` + +## Instructions + +Run the phases below in order, or just the one the user asked for via `$ARGUMENTS`. + +### Step 1: Vet + +```bash +make vet +``` + +`go vet` catches real bugs — incorrect format strings, unreachable code, suspicious struct tags, etc. It's fast and should always pass. + +If vet **fails** → show the errors and stop. These are likely bugs that need manual fixes before proceeding. + +### Step 2: Lint + +```bash +make lint +``` + +If lint **passes** → report success and continue. + +If lint **fails** → show the errors and ask the user which fix to try: + +- `make fmt` — fixes import ordering and formatting (goimports + gofumpt), style only +- `make lint-fix` — runs golangci-lint with `--fix`, auto-fixes some lint issues beyond formatting +- Both — run `make fmt` first, then `make lint-fix` + +Then re-run `make lint` to confirm the remaining errors (if any) need manual fixes. + +> **Note:** Neither command resolves logic or type errors — those need manual fixes. + +### Step 3: Unit tests + +```bash +make test +``` + +This runs all tests excluding `/e2e` and `/lab` subdirectories and produces `cover.out`. + +If tests fail → show the failing test names and error output. + +### Step 4: gNMI integration tests + +```bash +make test-gnmi +``` + +This builds and runs the fake gNMI server from `test/gnmi/` and executes the integration tests against it. Fully standalone — no kind cluster or VM needed. + +If tests fail → show the failing testdata files and the diff between expected and actual state. + +### Summary + +After all phases complete, print a report: + +``` + Local Dev Report + ──────────────────────────────────────────────────────── + Vet: ✓ passed (or ✗ N issues — list them) + Lint: ✓ passed (or ✗ N issues — list them) + (fmt offered: yes/no) + Unit tests: ✓ N passed, 0 failed (or ✗ N failed — list failing tests) + gNMI tests: ✓ N passed, 0 failed (or ✗ N failed — list failing testdata files) + ──────────────────────────────────────────────────────── + Overall: ✓ all checks passed (or ✗ see above) +``` + +For gNMI test failures, show the diff between expected and actual state: +``` + FAIL: testdata/openconfig/banner.txt + Expected: {"openconfig-system:system":{"config":{"login-banner":"..."}}} + Actual: {} +``` + +## References + +- [go vet](https://pkg.go.dev/cmd/vet) — static analysis tool built into Go +- [golangci-lint](https://golangci-lint.run) — aggregated linter runner (custom build used here via `.custom-gcl.yaml`) +- [goimports](https://pkg.go.dev/golang.org/x/tools/cmd/goimports) — fixes import grouping and formatting (`make fmt`) +- [gofumpt](https://github.com/mvdan/gofumpt) — stricter gofmt, run alongside goimports (`make fmt`) +- [gnmic](https://gnmic.openconfig.net) — gNMI CLI client used for validation diff --git a/.claude/skills/netop-setup/SKILL.md b/.claude/skills/netop-setup/SKILL.md new file mode 100644 index 000000000..3b12cf878 --- /dev/null +++ b/.claude/skills/netop-setup/SKILL.md @@ -0,0 +1,249 @@ +--- +name: netop-setup +description: One-time setup of the network-operator test environment. Provisions a colima VM, creates a kind cluster with cert-manager, and deploys a containerlab network device. Use this before the first test session or after a full teardown. Say "no vm" or "skip vm" to skip the VM provisioning step. +argument-hint: [no-vm | skip-vm] +allowed-tools: [Bash, Read, Write, AskUserQuestion] +--- + +# netop-setup + +Sets up the full test environment for network-operator from scratch: +1. Setup VM (profile: `network-operator`) +2. Install tools in VM +3. Kind cluster + cert-manager +4. Containerlab network device + +> **No-VM shortcut:** pass `no-vm`, `skip vm`, `without vm`, or `run without VM` to skip Steps 1 and 2. + +## Environment + +At the start of the session, ask the user which provider they plan to test (if not already known from `$ARGUMENTS`): +- **openconfig / Nokia SRL** → `PROVIDER=openconfig` +- **cisco** → `PROVIDER=cisco` + +Also ask which VM tool they are using (default: colima): +- **colima** → `VM_EXEC="colima exec -p network-operator --"` +- **multipass** → `VM_EXEC="multipass exec network-operator --"` + +These variables are used in every command below: + +``` +PROVIDER=openconfig # or cisco +VM_EXEC="colima exec -p network-operator --" # or multipass exec network-operator -- +``` + +`LOCALBIN` is set persistently in the VM's `~/.bashrc` during Step 2 — no need to prefix it on any `make` command. + +> **No-VM case:** `LOCALBIN` is not set. The Makefile default (`./bin`) applies automatically. + +The VM wrapper for all Step 2+ commands is: +```bash +$VM_EXEC bash -c "" +``` + +> The host home directory is mounted at the same path inside the VM — commands run from the same directory as on the host, so no `cd` is needed. + +> All commands in Steps 2, 3, and 4 use this wrapper. It is not repeated in each step — just substitute `` with the bare command shown. + +## Step 1: Setup VM + +> **Skip Steps 1 and 2** if the user passes `no-vm` or any similar phrasing. + +Check the state of the `network-operator` colima profile: + +```bash +colima list +``` + +- **Running** → check specs match defaults (4 CPU, 8 GB, 60 GB disk). If they differ, warn the user and ask if they want to recreate: + ```bash + colima delete -p network-operator + # then create as below + ``` +- **Stopped** → start it: + ```bash + colima start --profile network-operator + ``` +- **Not listed** → create it: + ```bash + colima start --cpu 4 --memory 8 --disk 60 --network-address --profile network-operator + ``` + +Verify after start: +```bash +colima list +``` + +Ensure `~/.local/bin` exists, is on PATH, and `LOCALBIN` is exported in the VM: + +```bash +mkdir -p ~/.local/bin +grep -qxF 'export LOCALBIN="$HOME/.local/bin"' ~/.bashrc || echo 'export LOCALBIN="$HOME/.local/bin"' >> ~/.bashrc +grep -qxF 'export PATH="$LOCALBIN:$PATH"' ~/.bashrc || echo 'export PATH="$LOCALBIN:$PATH"' >> ~/.bashrc +export LOCALBIN="$HOME/.local/bin" +export PATH="$LOCALBIN:$PATH" +``` + +## Step 2: Install tools in VM + +> **Skip this step** if the user is running without a VM. + +Install required tools if not already present: + +```bash +sudo apt-get update -qq +sudo apt-get install -y make curl jq vim snapd +which yq || sudo snap install yq +which go || sudo snap install go --classic +which kubectl || sudo snap install kubectl --classic +which k || sudo snap alias kubectl k +which gnmic || bash -c "$(curl -sL https://get-gnmic.openconfig.net)" +``` + +## Step 3: Kind cluster + cert-manager + +```bash +make kind +make kind-create +``` + +Wait for node ready: +```bash +kubectl wait --for=condition=Ready node --all --timeout=120s +``` + +Install cert-manager: +```bash +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.yaml +kubectl wait --for=condition=Available deployment --all -n cert-manager --timeout=120s +``` + +Verify: +```bash +kubectl get nodes +kubectl get pods -n cert-manager +``` + +## Step 4: Containerlab device + +Ask the user which device type to use: + +**Option A — Nokia SRL (default, arm64-compatible)** +**Option B — Remote Cisco device (team cloud via SSH port forwarding)** + +### Option A: Nokia SRL + +Check if containerlab is installed: +```bash +containerlab version 2>/dev/null || bash -c "$(curl -sL https://get.containerlab.dev)" +``` + +Write the topology file to `/tmp/srl01.clab.yml`: + +```yaml +name: srlceos01 + +topology: + nodes: + srl: + kind: nokia_srlinux + image: ghcr.io/nokia/srlinux:26.7.1 + startup-config: |- + system name host-name srl + system grpc-server mgmt yang-models openconfig + ports: + - 57022:22 + - 57400:57400 + + links: + - endpoints: ["srl:ethernet-1/1", "srl:ethernet-1/2"] +``` + +Deploy: +```bash +containerlab deploy -d -t /tmp/srl01.clab.yml +``` + +If the container already exists or the user wants to reconfigure: +```bash +containerlab deploy -d --reconfigure -t /tmp/srl01.clab.yml +``` + +Wait until running: +```bash +docker inspect -f '{{.State.Status}}' clab-srlceos01-srl +``` + +Show device IP: +```bash +containerlab inspect -t /tmp/srl01.clab.yml +``` + +The Nokia SRL management IP is typically `172.20.20.2` — confirm and note it for `/netop-test`. + +### Option B: Remote Cisco device + +> **Note:** Local Cisco N9Kv deployment is not possible on Apple Silicon — nested virtualization required for QEMU x86 emulation is not supported. Use a remote device instead (direct access or via SSH port forwarding — that's the user's responsibility). + +Ask the user for the device connection details: +- `CISCO_IP` — IP address reachable from the VM (e.g. `10.0.0.5` or `127.0.0.1` if port-forwarded) +- `CISCO_PORT` — gNMI port (default: `57400`) +- `CISCO_USER` — gNMI username (default: `admin`) +- `CISCO_PASSWORD` — gNMI password + +Verify connectivity from inside the VM: +```bash +nc -z $CISCO_IP $CISCO_PORT && echo "device reachable" || echo "device not reachable — check IP, port, and any required port forwarding" +``` + +> **Localhost warning:** If the user provides `127.0.0.1` or `localhost` as `CISCO_IP`, warn them that this refers to the VM itself, not the Mac host. Detect the Mac host IP as seen from the VM (its default gateway) and use that instead: +> ```bash +> HOST_IP=$(ip route | awk '/default/ {print $3}') +> echo "Use $HOST_IP instead of 127.0.0.1" +> ``` +> Update `CISCO_IP` to `$HOST_IP` before proceeding. + +Note these values for `/netop-test`: +``` +GNMI_TARGET=$CISCO_IP:$CISCO_PORT +GNMI_USER=$CISCO_USER +GNMI_PASSWORD=$CISCO_PASSWORD +``` + +## Summary + +Run the following to show the full state of the dev environment: + +```bash +# Docker version +docker --version + +# Kubernetes cluster version and nodes +kubectl version +kubectl get nodes + +# All pods (wait until ready) +kubectl wait --for=condition=Ready pod --all -A --timeout=120s && kubectl get pods -A + +# Containerlab device status +containerlab inspect -a +``` + +Print a final summary: +- Colima profile: `network-operator` (CPU, memory, disk) +- Docker version +- Kind cluster: Kubernetes version, node count +- cert-manager: all deployments available +- Network device: name, kind, IP/endpoint +- If `PROVIDER=cisco`: `GNMI_TARGET`, `GNMI_USER`, `GNMI_PASSWORD` confirmed and device reachable from VM +- Next step: run `/netop-test` to build and deploy the operator + +## References + +- [colima](https://github.com/abiosoft/colima) — container runtimes on macOS with minimal setup +- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) — Kubernetes in Docker +- [kubectl](https://kubernetes.io/docs/reference/kubectl/) — Kubernetes CLI reference +- [cert-manager](https://cert-manager.io/docs/) — X.509 certificate management for Kubernetes +- [containerlab](https://containerlab.dev/cmd/) — network topology emulation (CLI reference) +- [Nokia SRL containerlab kind](https://containerlab.dev/manual/kinds/nokia_srlinux/) — Nokia SR Linux node configuration +- [gnmic](https://gnmic.openconfig.net) — gNMI CLI client diff --git a/.claude/skills/netop-test/SKILL.md b/.claude/skills/netop-test/SKILL.md new file mode 100644 index 000000000..20daf0d68 --- /dev/null +++ b/.claude/skills/netop-test/SKILL.md @@ -0,0 +1,279 @@ +--- +name: netop-test +description: Build and deploy the network-operator, apply custom resources, and validate configuration via gnmic. Use after /netop-setup to run the dev/test loop against a real containerlab device. Also handles kind cluster and VM cleanup. Say "no vm" or "local" to run commands on the host machine instead. +argument-hint: [ [expected-result.json] | no-vm | local] +allowed-tools: [Bash, Read, Write, AskUserQuestion] +--- + +# netop-test + +Runs the network-operator dev/test loop: +1. Build Docker image and load into kind +2. Deploy (or redeploy) the operator +3. Apply custom resources +4. Validate with gnmic +5. Test report +6. Cleanup (optional) + +Prerequisites: `/netop-setup` has been run — VM, kind cluster, and containerlab device are all running. + +> **No-VM shortcut:** pass `no-vm`, `local`, or any similar phrasing to run all commands directly on the host machine instead of inside the VM. + +## Arguments + +The user can pass optional arguments via `$ARGUMENTS`: + +- **CR file** (`@my-sample.yaml`) — a custom CR YAML to apply instead of picking from `config/samples/`. Read the file, apply it directly. +- **Expected result** (`@my-expected-result.json`) — a JSON file with the expected gnmic state after reconciliation. Use it to compare against the actual `gnmic get` response in Step 4. +- **`no-vm` / `local`** — run all commands on the host machine instead of inside the VM. + +Examples: +``` +/netop-test +/netop-test no-vm +/netop-test @config/samples/v1alpha1_banner.yaml +/netop-test @config/samples/v1alpha1_banner.yaml @test/gnmi/testdata/openconfig/banner.txt +``` + +If an expected result file is provided, use it as the ground truth in Step 5 instead of inferring the expected value from the CR spec. + +### Parsing testdata files (`test/gnmi/testdata/`) + +If the user passes a file from `test/gnmi/testdata/` (e.g. `@test/gnmi/testdata/openconfig/banner.txt`), parse it as follows: + +``` +# +-- / -- + +-- state -- + +``` + +- Everything between `-- / --` and `-- state --` is the CR YAML → apply it in Step 3 +- Everything after `-- state --` is the expected gnmic state JSON → use it as the expected value in Step 5 +- The `deviceRef.name` in the CR YAML refers to `device` by default — replace it with the actual device name (`leaf1`) before applying + +Example (`banner.txt`): +``` +# Banner PreLogin +-- banners/banner -- +apiVersion: networking.metal.ironcore.dev/v1alpha1 +kind: Banner +... +-- state -- +{ + "openconfig-system:system": { + "config": { + "login-banner": "Unauthorized access is prohibited." + } + } +} +``` + +## Environment + +``` +VM_EXEC="colima exec -p network-operator --" # or: multipass exec network-operator -- + # or: empty ("") to run locally +``` + +All commands below are shown as bare commands. Wrap them with `$VM_EXEC bash -c ""` when running in the VM, or run them directly on the host when `no-vm` / `local` is passed. + +> **Why no `LOCALBIN` prefix?** `LOCALBIN` is set in the VM's `~/.bashrc` during `/netop-setup` — all `make` calls pick it up automatically, and tools like `kind` and `kustomize` are on `PATH`. When running locally, the Makefile default (`./bin`) applies. + +## Step 1: Build & load image + +Build the operator image: +```bash +make docker-build IMG=ghcr.io/ironcore-dev/network-operator:latest +``` + +Load the image into the kind cluster: +```bash +kind load docker-image ghcr.io/ironcore-dev/network-operator:latest --name network-operator +``` + +## Step 2: Deploy the operator + +Ask the user: **fresh deploy or redeploy?** + +**Fresh deploy** — operator not yet running in the cluster: + +Ensure kustomize is installed and set the image on the fly (without modifying tracked files): +```bash +make kustomize +cd config/develop && kustomize edit set image controller=ghcr.io/ironcore-dev/network-operator:latest && kustomize build . | kubectl apply -f - && git checkout kustomization.yaml +``` + +> `git checkout kustomization.yaml` reverts the image edit so the file stays clean. +> `config/develop/manager_patch.yaml` sets `--provider=openconfig` — read it first to confirm the provider is correct for the current session. + +**Redeploy** — operator already running, restart with the new image: +```bash +kubectl rollout restart deployment/network-operator-controller-manager -n network-operator-system +kubectl rollout status deployment/network-operator-controller-manager -n network-operator-system --timeout=60s +``` + +Check manager logs for startup errors: +```bash +kubectl logs -n network-operator-system -l control-plane=controller-manager --tail=30 +``` + +## Step 3: Apply custom resources + +Ask the user: **use samples from `config/samples/` or provide a custom YAML path?** + +The `Device` resource must be applied first — other resources depend on it. Copy to a temp file, patch address and credentials for the Nokia SRL device, then apply: +```bash +cp config/samples/v1alpha1_device.yaml /tmp/device.yaml +sed -i 's|address: .*|address: 172.20.20.2:57400|' /tmp/device.yaml +sed -i 's|password: .*|password: NokiaSrl1!|' /tmp/device.yaml +kubectl apply -f /tmp/device.yaml +``` + +If the user is using a different device, ask for the correct address and credentials before patching. + +Verify the device is reconciled: +```bash +kubectl get device -A +``` + +Then apply additional resources: +```bash +kubectl apply -f config/samples/.yaml +``` + +After applying any CR, check reconciliation status: +```bash +kubectl get -A +``` + +Look for `READY=True`. If not ready, check operator logs: +```bash +kubectl logs -n network-operator-system -l control-plane=controller-manager --tail=50 +``` + +### Generic CRD test pattern + +For any CR you want to test: + +1. **Find the sample** in `config/samples/` (e.g. `v1alpha1_banner.yaml`) +2. **Check the CR references the correct device** — `deviceRef.name: leaf1` or label `networking.metal.ironcore.dev/device-name: leaf1` +3. **Apply it:** `kubectl apply -f config/samples/v1alpha1_.yaml` +4. **Verify reconciliation:** `kubectl get -A` — expect `READY=True` +5. **Find the gNMI path** — open `internal/provider/openconfig/.go` and look for the `XPath()` method + - Banner (PreLogin): `openconfig-system:system/config/login-banner` + - DNS: `openconfig-system:system/dns` +6. **Validate with gnmic** (see Step 4) + +## Step 4: Validate with gnmic + +For each CR tested, run a gnmic get using the XPath from the provider source: +```bash +gnmic -a 172.20.20.2 --port 57400 -u admin -p 'NokiaSrl1!' --skip-verify --encoding JSON_IETF get --path '' +``` + +Ask the user if they want to query a different path or device. Substitute accordingly. + +### Optional: Show device capabilities + +If the user asks to see what the device supports, run a gnmic capabilities request: +```bash +gnmic -a 172.20.20.2 --port 57400 -u admin -p 'NokiaSrl1!' --skip-verify capabilities +``` + +This returns the supported YANG models, encodings, and gNMI version — useful for confirming which OpenConfig paths are available on the device before testing. + +### Optional: Query device configuration + +If the user asks to see a specific part of the device configuration, run a gnmic get with the path they provide: +```bash +gnmic -a 172.20.20.2 --port 57400 -u admin -p 'NokiaSrl1!' --skip-verify --encoding JSON_IETF get --path '' +``` + +Examples the user might ask: +- `show me device configuration openconfig-system:system/dns` +- `show me device configuration openconfig-interfaces:interfaces` +- `get openconfig-system:system/config/login-banner` + +Always print the full JSON response without truncation. + +If the user asks to see the running lab topology: +```bash +containerlab inspect -a +``` + +This lists all running containerlab labs, node names, kinds, images, states, and management IP addresses. + +## Step 5: Test report + +After all CRs have been applied and validated, print a structured test report. + +For each CR tested show: +1. **Applied YAML:** `kubectl get -n -o yaml` +2. **gnmic validation:** exact command and full JSON response (always shown regardless of whether an expected file was provided) +3. **Operator logs:** `kubectl logs -n network-operator-system -l control-plane=controller-manager --tail=100 | grep -i '\|error\|warn'` + +**Validation logic:** +- **Expected file provided** (`-- state --` section or JSON file) → compare gnmic response against it field by field +- **No expected file** → infer expected values from the CR spec fields (e.g. `spec.message.inline` for Banner) and validate those fields in the response +- **Always** print the full raw gnmic JSON response regardless — never truncate it + +End with a box-drawing summary table: + +``` + Test Report + + ┌──────────────┬──────────────┬───────────┬───────┬─────────────────────────────────────────┬─────────────────┐ + │ CR Name │ Kind │ Namespace │ Ready │ gNMI Path │ Result │ + ├──────────────┼──────────────┼───────────┼───────┼─────────────────────────────────────────┼─────────────────┤ + │ banner │ Banner │ default │ True │ openconfig-system:system/config/... │ ✓ value matches │ + └──────────────┴──────────────┴───────────┴───────┴─────────────────────────────────────────┴─────────────────┘ +``` + +If a CR maps to multiple gNMI paths (e.g. ManagementAccess has gRPC and SSH), add one row per path. + +Mark result as: +- `✓ value matches` — gnmic response matches expected/inferred value +- `✗ mismatch` — differs (show diff inline below table) +- `✗ not found` — gnmic returned empty or error + +Below the table, always show the full gnmic JSON response for each row: +``` + gnmic get openconfig-system:system/config/login-banner + ────────────────────────────────────────────────────── + { + "openconfig-system:system": { + "config": { + "login-banner": "###################################################\n# WARNING: ..." + } + } + } +``` + +## Step 6: Cleanup + +**Always ask before any destructive action.** + +Delete the kind cluster: +```bash +kind delete cluster --name network-operator +``` + +Stop the VM (keeps data): +```bash +colima stop --profile network-operator +``` + +Delete the VM (destroys all data — only if user explicitly confirms): +```bash +colima delete -p network-operator +``` + +## References + +- [kustomize](https://kubectl.docs.kubernetes.io/references/kustomize/) — Kubernetes configuration management +- [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) — Kubernetes in Docker +- [kubectl](https://kubernetes.io/docs/reference/kubectl/) — Kubernetes CLI reference +- [gnmic](https://gnmic.openconfig.net) — gNMI CLI client +- [OpenConfig YANG doc](https://openconfig.net/projects/models/schemadocs/) — OpenConfig YANG schemas diff --git a/README.md b/README.md index 7f360df88..66f79f762 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,127 @@ Users can just run kubectl apply -f to install the project kubectl apply -f https://raw.githubusercontent.com//network-operator//dist/install.yaml ``` +## Claude Code Skills + +This project includes [Claude Code](https://claude.ai/code) skills for interactive development workflows. Skills are located in `.claude/skills/` and invoked via slash commands. + +### `/netop-setup` + +Set up the full test environment (colima VM, kind cluster, cert-manager, containerlab device): + +``` +/netop-setup +``` + +Say `no vm` or `skip vm` to skip VM provisioning if it's already running. Supports colima and multipass. + +**Example — Nokia SRL:** + +``` +/netop-setup +``` + +``` + Colima VM network-operator — arm64, 4 CPU, 8 GB, 60 GB, running + Kind cluster network-operator — Kubernetes v1.36.1, node Ready + cert-manager v1.18.2 — all deployments available + Nokia SRL — clab-srlceos01-srl running at 172.20.20.2 + + Next step: run /netop-test. +``` + +**Example — Cisco device accessible on `127.0.0.1:57400`:** + +``` +/netop-setup cisco device accessible on 127.0.0.1:57400 with user admin and password admin +``` + +``` + Colima VM network-operator — arm64, 4 CPU, 8 GB, 60 GB, running + Kind cluster network-operator — Kubernetes v1.36.1, node Ready + cert-manager v1.18.2 — all deployments available + Cisco device — reachable from VM at 192.168.5.2:57400 (Mac host IP as seen from VM — use this instead of 127.0.0.1) + + Next step: run /netop-test with GNMI_TARGET=192.168.5.2:57400. +``` + +### `/netop-test` + +Build, deploy and test the operator against a real containerlab device: + +``` +/netop-test +``` + +You can pass CR files and expected results directly: + +``` +/netop-test @config/samples/v1alpha1_banner.yaml +/netop-test @test/gnmi/testdata/openconfig/banner.txt +/netop-test @my-cr.yaml @my-expected.json +``` + +- **`config/samples/`** — ready-made sample CRs for all supported resource types +- **`test/gnmi/testdata/`** — testdata files containing both the CR YAML and expected gnmic state in one file (parsed automatically) +- **Custom files** — pass any CR YAML and optionally a JSON file with the expected gnmic state + +You can also ask the skill to inspect the environment or show device capabilities in natural language: + +``` +/netop-test show me the device topology +/netop-test show me device capabilities +/netop-test show me device configuration openconfig-system:system/dns +``` + +- `show me the device topology` → runs `containerlab inspect -a` to list all running labs and their node IPs +- `show me device capabilities` → runs `gnmic capabilities` to show supported YANG models, encodings, and gNMI version +- `show me device configuration ` → runs `gnmic get --path ` and prints the full JSON response + +**Example output:** + +``` + Test Report + + ┌──────────────┬──────────────┬───────────┬───────┬──────────────────────────────────────────────┬─────────────────┐ + │ CR Name │ Kind │ Namespace │ Ready │ gNMI Path │ Result │ + ├──────────────┼──────────────┼───────────┼───────┼──────────────────────────────────────────────┼─────────────────┤ + │ banner │ Banner │ default │ True │ openconfig-system:system/config/login-banner │ ✓ value matches │ + └──────────────┴──────────────┴───────────┴───────┴──────────────────────────────────────────────┴─────────────────┘ + + gnmic get openconfig-system:system/config/login-banner + ────────────────────────────────────────────────────── + { + "openconfig-system:system": { + "config": { + "login-banner": "###################################################\n# WARNING: Unauthorized access is prohibited. #\n###################################################\n" + } + } + } +``` + +### `/netop-check` + +Run local checks before committing or opening a PR: + +``` +/netop-check +``` + +Runs `go vet`, `golangci-lint`, unit tests (`make test`), and gNMI integration tests (`make test-gnmi`). If lint fails, offers to run `make fmt` or `make lint-fix` to auto-fix issues. Prints a summary report at the end. + +**Example output:** + +``` + Local Dev Report + ──────────────────────────────────────────────────────── + Vet: ✓ passed + Lint: ✓ passed + Unit tests: ✓ 15 packages passed, 0 failed + gNMI tests: ✓ N passed, 0 failed + ──────────────────────────────────────────────────────── + Overall: ✓ all checks passed +``` + ## Support, Feedback, Contributing This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/ironcore-dev/network-operator/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).