docker: inject config files into containers via extra_configs

Add an `extra_configs` field (list of {target, content}) to the docker
node/template/appliance schemas. For each entry GNS3 writes `content` to a
file in the node working directory and bind-mounts it read-only at `target`
inside the container.

This lets a NOS appliance seed its startup config without rebuilding the
image: XRd points XR_FIRST_BOOT_CONFIG at an injected /firstboot.cfg, FRR at
/etc/frr/frr.conf, etc. The bind is a single-file mount applied at create
time, so it works for both the generic init.sh path and vendor nodes that
skip init.sh (console_type=docker_exec). Entries are only injected when
present, so ordinary nodes are unaffected.

The content can't go through `environment` (it is line-delimited, one var per
line), hence a dedicated field -- the same plumbing shape as extra_volumes.
This commit is contained in:
YueGuobin committed 2026-08-13 23:33:34 +08:00
1 parent 2bee34031c
commit 08e37a4509
7 files changed
+98 -3

No files matched your search

+2 -1
View File
@@ -18,7 +18,7 @@ from pydantic import BaseModel, Field
from typing import Optional, List
from uuid import UUID
from ..common import NodeStatus, CustomAdapter, ConsoleType, AuxType
from ..common import NodeStatus, CustomAdapter, ConsoleType, AuxType, ExtraConfig
class DockerBase(BaseModel):
@@ -43,6 +43,7 @@ class DockerBase(BaseModel):
environment: Optional[str] = Field(None, description="Docker environment variables")
extra_hosts: Optional[str] = Field(None, description="Docker extra hosts (added to /etc/hosts)")
extra_volumes: Optional[List[str]] = Field(None, description="Additional directories to make persistent")
extra_configs: Optional[List[ExtraConfig]] = Field(None, description="Configuration files injected into the container (bind-mounted read-only)")
memory: Optional[int] = Field(None, ge=0, description="Maximum amount of memory the container can use in MB")
cpus: Optional[float] = Field(None, ge=0, description="Maximum amount of CPU resources the container can use")
custom_adapters: Optional[List[CustomAdapter]] = Field(None, description="Custom adapters")