docs: roadmap for docker image types (vendor profiles)

Design proposal for an image_type discriminator on Docker templates plus
a compute-side profile registry: vendor parameters graduate from
environment markers into schema-gated fields, generic-feature
applicability becomes declared capability data, existing markers stay as
a compatibility fallback. Explicitly not a new node type.

Four profiles already exist to shape it (iol-runner, XRd, SR Linux
prototype, FRR appliance); implementation follows the current PR series.
This commit is contained in:
YueGuobin 2026-09-05 00:46:37 +08:00
parent e318afef86
commit 1ccea916c3
No known key found for this signature in database
2 changed files with 153 additions and 0 deletions

View File

@ -39,6 +39,8 @@ docs/
│ ├── statistics-api.md # Aggregated statistics API for monitoring
│ ├── vnc-websocket-console.md # Browser-based VNC console via WebSocket
│ └── web-wireshark-business-process.md # Web Wireshark (Docker + xpra packet capture)
├── design/ # Design proposals & roadmaps (not yet implemented)
│ └── docker-image-type.md # Docker image types: vendor profile discriminator + registry
├── gns3-copilot/ # AI Copilot feature documentation
│ ├── netmiko_devices.md # Netmiko supported devices (366 types)
│ ├── template-based-configuration-roadmap.md # Future: template-based config with HITL
@ -89,6 +91,13 @@ Cisco CML containerized IOL (e.g. `iol-xe/iol-xe:17-18-02`) as GNS3 Docker route
---
## Design & Roadmaps (`design/`)
### Docker Image Types (`design/docker-image-type.md`)
Proposed `image_type` discriminator on Docker templates plus a compute-side profile registry: vendor parameters graduate from environment markers into schema-gated fields, generic-feature applicability becomes declared capability data, and the existing markers remain as a compatibility fallback. Not a new node type — vendor images are content, not mechanism.
---
## GNS3 AI Copilot (`gns3-copilot/`)
### Implemented Features

View File

@ -0,0 +1,144 @@
# Docker Image Types (Vendor Profiles) — Roadmap
Status: **proposal, not implemented**. This is the agreed direction for the
next iteration of vendor Docker support. Four vendor profiles already
exist across branches and prototypes — iol-runner (this branch), XRd and
the SR Linux prototype (vendor/skip-init family), and the FRR registry
appliance — enough evidence to justify the registry. Implement it as a
follow-up to the current PR series, shaped by all four rather than by
iol-runner alone.
## Problem
All Docker nodes share one template type (`template_type: "docker"`) and
one template schema. Vendor images (iol-runner, SR Linux, XRd, …) are
selected and configured today through **environment markers** — free-form
strings parsed by the compute (`GNS3_IOL_RUNNER`, `GNS3_IOL_MEMORY`,
`GNS3_IOL_STARTUP_CONFIG`, `GNS3_SKIP_INIT`, `GNS3_UNIX_SOCKET_NIO`, …).
Three pains have already surfaced:
1. **Invisible and unvalidated.** The markers do not exist in the API
schema: no OpenAPI documentation, no validation, typo or bad value
silently falls back to a default (`GNS3_IOL_MEMORY=notanumber` → 2048).
2. **The shared-schema dilemma.** Adding a vendor-specific field to the
Docker template schema pollutes every Docker template with a field only
one vendor reads; not adding it pushes everything into environment
strings. The `startup_config` discussion (ended in the
`GNS3_IOL_STARTUP_CONFIG` knob) is the canonical example — the tension
exists because there is no legitimate discriminator dimension.
3. **Generic-feature applicability is implicit.** Which generic Docker
features apply to which image is only documented in code comments:
`mac_address` is meaningless under unix-socket NIO, `/etc/network`
seeding is dead weight for skip-init images, `extra_configs` targets
under persisted volumes get a (correct-but-noisy) shadow warning.
## Non-goal: new node types
A `template_type`/`node_type` per vendor (`"iol"`, `"srlinux"`, …) is
explicitly rejected. `node_type` is a top-level concept: it drives compute
module routing (`/projects/{id}/{node_type}/nodes`), capability
reporting, GUI node types and link handling. N vendor types that are all
Docker underneath would multiply routing and schema surface for zero
mechanism — vendor images are *content*, not mechanism, and GNS3's
appliance/template system is where content belongs.
## Design
### One discriminator field on Docker templates
```json
{
"template_type": "docker",
"image_type": "iol-runner",
"image": "iol-xe/iol-xe:17-18-02"
}
```
`image_type` is optional; absent (or `"generic"`) keeps today's plain
`DockerVM` behavior and marker sniffing. The profiles that exist today,
mapped to their current mechanisms and archetypes:
| Profile | Current mechanism | Archetype |
|---|---|---|
| FRR appliance | plain `DockerVM`: init.sh `/etc/network` + `start_command` (frrinit.sh), console on PID 1 | generic |
| XRd | `VendorDockerVM` skip-init + `GNS3_SHM_SIZE`/`GNS3_DEVICES`, `extra_configs`, udev masking | vendor skip-init |
| SR Linux (prototype) | `VendorDockerVM` skip-init + `docker_exec` console + `GNS3_INTERFACE_NAMES` | vendor skip-init |
| iol-runner | `IOLDockerVM`: unix-socket NIO, per-start config generation, NVRAM startup-config | iol-runner |
Possible first values: `generic`, `iol-runner`, and a value for the
skip-init vendor NOS family once its common shape settles (XRd and SR
Linux may end up sharing it or splitting — that is exactly what the
registry should decide with all four in front of us).
### A compute-side registry
```python
IMAGE_PROFILES = {
"iol-runner": {
"class": IOLDockerVM,
"fields": ("iol_memory", "startup_config"), # schema-gated
"capabilities": {...}, # see below
},
...
}
```
* **Class selection** moves from environment sniffing
(`Docker._select_node_class`) to the field, with the existing markers
kept as a fallback for templates created before the field existed
(zero-migration compatibility).
* **Vendor parameters graduate into schema fields**, gated by pydantic
conditional validation (accepted — and validated — only when
`image_type` matches). This resolves the shared-schema dilemma properly:
the field exists, but only means something for its profile. The
environment knobs remain as the wire-level compatibility entry.
* **Capability declaration** makes generic-feature applicability data
instead of comments:
| Capability | plain Docker | vendor skip-init | iol-runner |
|---|---|---|---|
| `mac_address` honored | yes | yes | **no** (IOL derives MACs from the app id) |
| `/etc/network` seeding | yes | no | no |
| `extra_configs` targets under volumes | shadowed | works (real-path binds) | works |
| console | telnet/http/… | `docker_exec` | PID 1 stdio (telnet) |
| startup config | `extra_configs` injection | image-specific | nvram build (`nvram_import`) |
Consumers: error/warning quality (don't warn about inapplicable
features), the WebUI (vendor-aware template forms — a bonus, not a
driver), and documentation generation.
The existing class hierarchy (`DockerVM``VendorDockerVM`
`IOLDockerVM`) is unchanged — the registry only externalizes selection
and declaration.
## Migration & compatibility
* Old templates (markers only) keep working via the fallback; a one-time
optional converter can rewrite markers → `image_type` + fields.
* The controller-side materialization conventions
(`GNS3_IOL_STARTUP_CONFIG` file → `startup_config_content`, sent once)
carry over unchanged — the field version references the same content
pipeline.
## Roadmap steps
1. Add `image_type` to the Docker template schema (+ DB column +
Alembic migration — see the three-place rule for template fields) and
wire class selection through the registry, markers as fallback.
2. Move iol-runner knobs to gated fields (`iol_memory`,
`startup_config`), deprecating-but-supporting the env forms.
3. Introduce the capability table and use it to silence inapplicable
warnings (`mac_address`, `/etc/network`, extra-config shadowing).
4. Revisit per-vendor *schemas* (a sub-model per profile) only if a
profile grows more than a handful of fields — not before.
## Open questions
* Field name: `image_type` vs `vendor` vs `runner` — decide when the
second profile lands; the value vocabulary should name the *runtime
contract*, not the vendor.
* Should appliances (`.gns3a`) carry `image_type` explicitly, or should
installation keep deriving it from the appliance's environment block?
* Where the gated vendor fields live long-term: flat on the Docker
template (simple, gated) vs nested `{"image_type": ..., "settings":
{...}}` (cleaner, more schema churn).