definitions:
  models.ApplyLabResponse:
    properties:
      addedLinks:
        items:
          type: string
        type: array
      addedNodes:
        items:
          type: string
        type: array
      deletedEndpoints:
        items:
          type: string
        type: array
      deletedNodes:
        items:
          type: string
        type: array
      deployedLab:
        type: boolean
      dryRun:
        type: boolean
      labName:
        type: string
      nodeChangeReasons:
        additionalProperties:
          type: string
        type: object
      recreatedNodes:
        items:
          type: string
        type: array
      restartedNodes:
        items:
          type: string
        type: array
      runtimePlan:
        allOf:
        - $ref: '#/definitions/models.LabRuntimePlan'
        description: RuntimePlan is the remote resource plan of a dry run on a lab
          runtime (c9s).
      startedNodes:
        items:
          type: string
        type: array
    type: object
  models.C9sLabHost:
    properties:
      cluster:
        description: Cluster is the cluster name of that context; "in-cluster" for
          the Pod's ServiceAccount.
        example: c9s
        type: string
      context:
        description: |-
          Context is the kubeconfig context the server uses; empty with the in-cluster
          ServiceAccount.
        example: c9s-provisioner
        type: string
      exposeType:
        description: ExposeType is the Service type of lab nodes (CLAB_C9S_EXPOSE_TYPE).
        enum:
        - None
        - ClusterIP
        - Headless
        - LoadBalancer
        example: None
        type: string
      imagePullSecret:
        description: |-
          ImagePullSecret is the name of the image pull secret device Pods reference
          (CLAB_C9S_IMAGE_PULL_SECRET); empty when unset.
        example: regcred
        type: string
      labQuota:
        description: LabQuota reports whether every lab namespace gets a ResourceQuota
          (CLAB_KUBE_LAB_QUOTA).
        example: false
        type: boolean
      metrics:
        description: |-
          Metrics reports whether the cluster serves the resource metrics API (metrics.k8s.io)
          node stats come from.
        example: true
        type: boolean
      namespacePattern:
        description: |-
          NamespacePattern is the namespace of the signed-in user's labs, with {lab} left in
          (CLAB_KUBE_NAMESPACE_TEMPLATE). Names too long for a namespace are cut and get a hash.
        example: c9s-alice-{lab}
        type: string
      noTopologyCR:
        description: |-
          NoTopologyCR reports whether labs deploy without clabernetes' Topology resource
          (containerlab's --no-topology-cr). The server always deploys with one: false.
        example: false
        type: boolean
      persistence:
        description: |-
          Persistence reports whether node storage outlives Pod replacement and destroy
          (CLAB_C9S_PERSISTENCE).
        example: true
        type: boolean
      sharedNamespacePattern:
        description: SharedNamespacePattern is the namespace of labs in the shared
          workspace, with {lab} left in.
        example: c9s-shared-{lab}
        type: string
    type: object
  models.CACreateRequest:
    properties:
      commonName:
        description: Defaults to "containerlab.dev"
        example: ca.example.com
        type: string
      country:
        description: Defaults to "Internet"
        example: US
        type: string
      expiry:
        description: Duration string, defaults to "87600h" (10 years)
        example: 8760h
        type: string
      locality:
        description: Defaults to "Server"
        example: City
        type: string
      name:
        description: Defaults to "ca" if empty
        example: my-root-ca
        type: string
      orgUnit:
        description: Defaults to "Containerlab Tools"
        example: IT
        type: string
      organization:
        description: Defaults to "Containerlab"
        example: MyOrg
        type: string
    type: object
  models.CPUMetrics:
    properties:
      loadAvg1:
        description: 1-minute load average
        type: number
      loadAvg5:
        description: 5-minute load average
        type: number
      loadAvg15:
        description: 15-minute load average
        type: number
      numCPU:
        description: Number of CPUs/cores
        type: integer
      processPercent:
        description: This process's CPU usage
        type: number
      usagePercent:
        description: Overall CPU usage percentage
        type: number
    type: object
  models.CaptureCloseAllResponse:
    properties:
      closed:
        type: integer
      message:
        type: string
    type: object
  models.CaptureInterfaceInfo:
    properties:
      alias:
        description: Alias is the topology's name for the interface when the node
          kind maps it.
        example: ethernet-1/1
        type: string
      interface:
        description: Interface is the interface name in the node; capture output names
          it <node>:<interface>.
        example: e1-1
        type: string
      node:
        description: Node is the node name as the topology spells it.
        example: srl1
        type: string
      peerInterface:
        description: PeerInterface is the peer's interface as the topology wrote it.
        example: e1-1
        type: string
      peerNode:
        description: PeerNode is the node at the other end of the link, "host" for
          a host endpoint.
        example: srl2
        type: string
    type: object
  models.CaptureLabHost:
    properties:
      edgeshark:
        allOf:
        - $ref: '#/definitions/models.EdgesharkLabHost'
        description: Edgeshark is Edgeshark on the server host; only set for Docker
          and Podman.
      wiresharkImage:
        description: |-
          WiresharkImage is the container image of a Wireshark VNC session
          (CAPTURE_WIRESHARK_DOCKER_IMAGE).
        example: ghcr.io/srl-labs/wireshark-vnc-docker:latest
        type: string
      wiresharkPullPolicy:
        description: |-
          WiresharkPullPolicy is when the server pulls that image before a session
          (CAPTURE_WIRESHARK_PULL_POLICY).
        enum:
        - always
        - missing
        - never
        example: always
        type: string
      wiresharkVnc:
        description: |-
          WiresharkVnc reports whether the server runs Wireshark VNC sessions (Wireshark in a
          browser window) for the user's labs; on c9s only while Docker answers on the server
          host.
        example: true
        type: boolean
    type: object
  models.CapturePacketflixRequest:
    properties:
      remoteHostname:
        type: string
      targets:
        items:
          $ref: '#/definitions/models.CaptureTarget'
        minItems: 1
        type: array
    required:
    - targets
    type: object
  models.CapturePacketflixResponse:
    properties:
      captures:
        items:
          $ref: '#/definitions/models.CapturePacketflixURI'
        type: array
    type: object
  models.CapturePacketflixURI:
    properties:
      containerName:
        type: string
      interfaceNames:
        items:
          type: string
        type: array
      packetflixUri:
        type: string
    type: object
  models.CaptureTarget:
    properties:
      containerName:
        type: string
      interfaceName:
        type: string
      nodeNamespace:
        description: |-
          NodeNamespace marks InterfaceName as the port's name inside the node's
          network namespace. It is captured there as-is, instead of being resolved
          through its alias to the host-side end of a stitched link, so a node's
          links and its own interfaces (e.g. eth0) can share one capture stream.
        type: boolean
    required:
    - containerName
    - interfaceName
    type: object
  models.CaptureWiresharkVncCreateResponse:
    properties:
      sessions:
        items:
          $ref: '#/definitions/models.CaptureWiresharkVncSession'
        type: array
    type: object
  models.CaptureWiresharkVncReadyResponse:
    properties:
      ready:
        type: boolean
      url:
        type: string
    type: object
  models.CaptureWiresharkVncRequest:
    properties:
      targets:
        items:
          $ref: '#/definitions/models.CaptureTarget'
        minItems: 1
        type: array
      theme:
        type: string
    required:
    - targets
    type: object
  models.CaptureWiresharkVncSession:
    properties:
      containerName:
        type: string
      createdAt:
        type: string
      expiresAt:
        type: string
      interfaceNames:
        items:
          type: string
        type: array
      labName:
        type: string
      sessionId:
        type: string
      showVolumeTip:
        type: boolean
      vncPath:
        type: string
    type: object
  models.CertResponse:
    properties:
      certPath:
        description: e.g., "my-root-ca/my-root-ca.pem" or "my-root-ca/node1.example.com.pem"
        type: string
      csrPath:
        description: e.g., "my-root-ca/my-root-ca.csr" or "my-root-ca/node1.example.com.csr"
        type: string
      keyPath:
        description: e.g., "my-root-ca/my-root-ca.key" or "my-root-ca/node1.example.com.key"
        type: string
      message:
        type: string
    type: object
  models.CertSignRequest:
    properties:
      caName:
        description: Name of the CA cert/key files (without .pem/.key) previously
          generated
        example: my-root-ca
        type: string
      commonName:
        description: Defaults to Name if empty
        example: node1.example.com
        type: string
      country:
        description: Defaults to "Internet"
        example: US
        type: string
      hosts:
        description: SANs (DNS names or IPs), comma-separated in clab, array here
        items:
          type: string
        type: array
      keySize:
        description: Defaults to 2048
        example: 4096
        type: integer
      locality:
        description: Defaults to "Server"
        example: City
        type: string
      name:
        description: Required
        example: node1.example.com
        type: string
      orgUnit:
        description: Defaults to "Containerlab Tools"
        example: Nodes
        type: string
      organization:
        description: Defaults to "Containerlab"
        example: MyOrg
        type: string
    required:
    - caName
    - hosts
    - name
    type: object
  models.ClabContainerInfo:
    properties:
      absLabPath:
        description: Absolute path to topology file
        type: string
      container:
        description: Container is the node's primary device container in the Pod.
        example: node-srl1-6b1f
        type: string
      container_id:
        description: Docker container ID (short)
        type: string
      exposed_ports:
        description: ExposedPorts are the node ports published through the node's
          Service.
        items:
          $ref: '#/definitions/models.ClabExposedPort'
        type: array
      group:
        description: Group assigned in topology (Might not always be present)
        type: string
      image:
        description: Container image used
        type: string
      ipv4_address:
        description: Management IPv4 Address/Mask
        type: string
      ipv6_address:
        description: Management IPv6 Address/Mask
        type: string
      kind:
        description: e.g., "linux", "nokia_srlinux"
        type: string
      lab_name:
        description: Name of the lab this node belongs to (redundant with map key
          but present)
        type: string
      labPath:
        description: Path to the topology file used (relative)
        type: string
      load_balancer_address:
        description: LoadBalancerAddress is the address of the LoadBalancer Service
          that exposes the node.
        example: 203.0.113.10
        type: string
      mgmt_network:
        description: |-
          MgmtNetwork is the management network the node is attached to; with
          several management networks (mgmt list in the topology) it tells them apart.
        example: clab
        type: string
      name:
        description: Name of the container node (e.g., "lab01-client1")
        type: string
      namespace:
        description: Namespace is the Kubernetes namespace of the lab.
        example: c9s-alice-lab01
        type: string
      node_uid:
        description: NodeUID is the UID of the clabernetes Node resource.
        type: string
      nodeName:
        description: Topology node name from containerlab labels
        type: string
      owner:
        description: OS user from clab inspect output (Used for authorization)
        type: string
      pod:
        description: Pod is the Pod that runs the node.
        example: lab01-srl1-5c9d8f7b6-x2x7k
        type: string
      ports:
        description: Published ports, as in `clab inspect --format json`
        items:
          $ref: '#/definitions/models.ClabPortBinding'
        type: array
      rootNodeName:
        description: |-
          RootNodeName is the topology node a sub-container belongs to, e.g. the
          node of a distributed SR-SIM's CPM and card containers. Empty otherwise.
        example: sr1
        type: string
      state:
        description: e.g., "running"
        type: string
      status:
        description: e.g., "Up 18 hours"
        type: string
    type: object
  models.ClabExecInternalResult:
    properties:
      cmd:
        description: The command and its arguments as executed
        items:
          type: string
        type: array
      return-code:
        description: Exit code of the command inside the container
        type: integer
      stderr:
        description: Standard error of the command
        type: string
      stdout:
        description: Standard output of the command
        type: string
    type: object
  models.ClabExposedPort:
    properties:
      expose_port:
        example: 22
        type: integer
      port:
        example: 22
        type: integer
      protocol:
        example: tcp
        type: string
    type: object
  models.ClabInspectOutput:
    additionalProperties:
      items:
        $ref: '#/definitions/models.ClabContainerInfo'
      type: array
    type: object
  models.ClabPortBinding:
    properties:
      host_ip:
        example: 0.0.0.0
        type: string
      host_port:
        example: 8080
        type: integer
      port:
        example: 80
        type: integer
      protocol:
        example: tcp
        type: string
    type: object
  models.CustomIconInfo:
    properties:
      dataUri:
        type: string
      format:
        example: svg
        type: string
      name:
        type: string
      source:
        example: global
        type: string
    type: object
  models.CustomNodeDefaultRequest:
    properties:
      name:
        type: string
    required:
    - name
    type: object
  models.CustomNodeTemplate:
    additionalProperties: true
    type: object
  models.CustomNodesReplaceRequest:
    properties:
      customNodes:
        items:
          $ref: '#/definitions/models.CustomNodeTemplate'
        type: array
    type: object
  models.CustomNodesResponse:
    properties:
      customNodes:
        items:
          $ref: '#/definitions/models.CustomNodeTemplate'
        type: array
      defaultNode:
        type: string
    type: object
  models.DeployRequest:
    properties:
      topologyContent:
        description: "Option 1: Direct Topology Content.\nProvide the full containerlab
          topology YAML as a json string.\nIf this is provided, 'topologySourceUrl'
          MUST be empty.\n{\n\t\"topologyContent\": {\n\t  \"name\": \"your-lab-name\",\n\t
          \ \"topology\": {\n\t\t\"kinds\": {\n\t\t  \"nokia_srlinux\": {\n\t\t\t\"type\":
          \"ixrd3\",\n\t\t\t\"image\": \"ghcr.io/nokia/srlinux\"\n\t\t  }\n\t\t},\n\t\t\"nodes\":
          {\n\t\t  \"srl1\": {\n\t\t\t\"kind\": \"nokia_srlinux\"\n\t\t  },\n\t\t
          \ \"srl2\": {\n\t\t\t\"kind\": \"nokia_srlinux\"\n\t\t  }\n\t\t},\n\t\t\"links\":
          [\n\t\t  {\n\t\t\t\"endpoints\": [\n\t\t\t  \"srl1:e1-1\",\n\t\t\t  \"srl2:e1-1\"\n\t\t\t]\n\t\t
          \ }\n\t\t]\n\t  }\n\t}\n  }"
        type: object
      topologySourceUrl:
        description: |-
          Option 2: Remote Topology Source URL.
          Provide a URL to a Git repository, a specific .clab.yml file in Git (github/gitlab), or a raw HTTP(S) URL.
          If this is provided, 'topologyContent' MUST be empty.
        type: string
    type: object
  models.DisableTxOffloadRequest:
    properties:
      containerName:
        example: clab-my-lab-srl1
        type: string
    required:
    - containerName
    type: object
  models.DiskMetrics:
    properties:
      freeDisk:
        description: Free disk space in bytes
        type: integer
      path:
        description: Mount path (usually "/")
        type: string
      totalDisk:
        description: Total disk space in bytes
        type: integer
      usagePercent:
        description: Disk usage percentage
        type: number
      usedDisk:
        description: Used disk space in bytes
        type: integer
    type: object
  models.DrawioGenerateRequest:
    properties:
      layout:
        example: horizontal
        type: string
      theme:
        example: nokia_modern
        type: string
    type: object
  models.DrawioGenerateResponse:
    properties:
      content:
        type: string
      fileName:
        type: string
      layout:
        type: string
      message:
        type: string
      output:
        type: string
    type: object
  models.EdgeSharkStatusResponse:
    properties:
      packetflixPort:
        type: integer
      running:
        type: boolean
      runtime:
        type: string
      version:
        type: string
    type: object
  models.EdgesharkLabHost:
    properties:
      extraEnvVars:
        description: |-
          ExtraEnvVars names the variables the Edgeshark containers get
          (CAPTURE_EDGESHARK_EXTRA_ENV_VARS), sorted; their values are not reported.
        example:
        - HTTP_PROXY
        - NO_PROXY
        items:
          type: string
        type: array
      packetflixPort:
        description: |-
          PacketflixPort is the port of Edgeshark's packetflix endpoint on the server host
          (CAPTURE_PACKETFLIX_PORT).
        example: 5001
        type: integer
    type: object
  models.ErrorResponse:
    properties:
      error:
        example: Invalid credentials or user not in allowed group
        type: string
    type: object
  models.EventAttributes:
    properties:
      clab-node-kind:
        description: Node kind (e.g., nokia_srlinux, linux)
        example: nokia_srlinux
        type: string
      clab-node-name:
        description: Node name within the lab
        example: srl1
        type: string
      clab-node-type:
        description: Node type
        example: ixrd3
        type: string
      containerlab:
        description: Alternative lab name field (containerlab label)
        example: mylab
        type: string
      exitCode:
        description: Exit code (for stop/die events)
        example: "0"
        type: string
      image:
        description: Container image
        example: ghcr.io/nokia/srlinux:latest
        type: string
      lab:
        description: Lab name this event belongs to
        example: mylab
        type: string
      name:
        description: Container name
        example: clab-mylab-srl1
        type: string
    type: object
  models.EventResponse:
    properties:
      action:
        description: Event action (e.g., "start", "stop", "die", "stats")
        example: start
        type: string
      attributes:
        allOf:
        - $ref: '#/definitions/models.EventAttributes'
        description: Event attributes containing details about the event
      time:
        description: Unix timestamp when the event occurred
        example: 1706918400
        type: integer
      type:
        description: Type of event (e.g., "container", "interface-stats")
        example: container
        type: string
    type: object
  models.ExecRequest:
    properties:
      command:
        example: ip addr show eth1
        type: string
    required:
    - command
    type: object
  models.ExecResponse:
    additionalProperties:
      items:
        $ref: '#/definitions/models.ClabExecInternalResult'
      type: array
    type: object
  models.FclingCommandRequest:
    properties:
      command:
        example: bgp-peers
        type: string
    required:
    - command
    type: object
  models.FclingCommandResponse:
    properties:
      command:
        type: string
      output:
        type: string
    type: object
  models.FclingEngineStartRequest:
    properties:
      gnmiPort:
        description: |-
          GnmiPort is a new port for the lab's nodes, used for its reports too and kept for the
          next start. An engine on another port is replaced; its history stays. Without it, the
          lab's port stays.
        example: 57410
        type: integer
    type: object
  models.FclingEngineStatus:
    properties:
      containerName:
        example: clab-lab01-fcling
        type: string
      error:
        description: Error is the end of the engine's log, when it failed.
        type: string
      gnmiPort:
        description: GnmiPort is the port the engine reaches the lab's nodes on, or
          will when it starts.
        example: 57400
        type: integer
      image:
        example: ghcr.io/srl-labs/fcling:0.9.0
        type: string
      startedAt:
        example: "2026-11-05T14:08:47Z"
        type: string
      state:
        description: |-
          State is stopped without an engine, starting until it answers, ready then, and failed
          once its container has exited.
        enum:
        - stopped
        - starting
        - ready
        - failed
        example: ready
        type: string
    type: object
  models.GenerateNodeTier:
    properties:
      count:
        description: Number of nodes in this tier
        example: 4
        minimum: 1
        type: integer
      kind:
        description: Node kind (defaults to 'srl'/'nokia_srlinux' if omitted)
        example: nokia_srlinux
        type: string
      type:
        description: Node type within the kind
        example: ixrd3
        type: string
    required:
    - count
    type: object
  models.GenerateRequest:
    properties:
      defaultKind:
        example: nokia_srlinux
        type: string
      deploy:
        example: true
        type: boolean
      groupPrefix:
        example: clos-tier
        type: string
      images:
        additionalProperties:
          type: string
        example:
          nokia_srlinux: ghcr.io/nokia/srlinux:latest
        type: object
      ipv4Subnet:
        example: 172.20.20.0/24
        type: string
      ipv6Subnet:
        example: 2001:172:20:20::/64
        type: string
      licenses:
        additionalProperties:
          type: string
        example:
          nokia_srlinux: /opt/licenses/srl.lic
        type: object
      managementNetwork:
        example: clos-mgmt
        type: string
      maxWorkers:
        example: 4
        type: integer
      name:
        example: 3-tier-clos
        type: string
      nodePrefix:
        example: clos-node
        type: string
      outputFile:
        example: clos.yml
        type: string
      tiers:
        items:
          $ref: '#/definitions/models.GenerateNodeTier'
        minItems: 1
        type: array
    required:
    - name
    - tiers
    type: object
  models.GenerateResponse:
    properties:
      deployOutput:
        description: |-
          The output from the deploy command (only if Deploy=true). JSON object keyed by lab name.
          Use swaggertype:"object" to represent json.RawMessage in Swagger.
        type: object
      message:
        description: Message indicating success or failure.
        type: string
      savedFilePath:
        description: Path where the file was saved (if Deploy=true, it's the path
          in the user's managed lab directory; if Deploy=false, it's the OutputFile
          path if provided).
        type: string
      topologyYaml:
        description: The generated topology YAML (only if Deploy=false and OutputFile
          is empty).
        type: string
    type: object
  models.GenericSuccessResponse:
    properties:
      message:
        type: string
    type: object
  models.GoTTYShareRequest:
    properties:
      password:
        example: secret
        type: string
      port:
        example: 8080
        type: integer
      shell:
        example: bash
        type: string
      username:
        example: admin
        type: string
    type: object
  models.GraphExportRequest:
    properties:
      direction:
        description: 'Direction of the mermaid flowchart: TD, TB, BT, RL or LR (default
          TD).'
        example: TD
        type: string
    type: object
  models.GraphExportResponse:
    properties:
      content:
        type: string
      direction:
        example: TD
        type: string
      fileName:
        example: lab01.clab.mermaid
        type: string
      format:
        enum:
        - mermaid
        - dot
        example: mermaid
        type: string
      output:
        type: string
    type: object
  models.HealthResponse:
    properties:
      features:
        description: |-
          Features lists optional API features this server supports, so clients can
          hide what older servers do not provide.
        example:
        - validate
        - exec-filters
        items:
          type: string
        type: array
      namespaceMode:
        description: |-
          NamespaceMode is how c9s labs get namespaces: per-lab (one namespace per lab of each
          user). It is only set for c9s.
        enum:
        - per-lab
        - fixed
        example: per-lab
        type: string
      runtime:
        description: 'Runtime is the lab runtime the server runs labs with: docker,
          podman or c9s.'
        enum:
        - docker
        - podman
        - c9s
        example: docker
        type: string
      startTime:
        description: When the server started
        type: string
      status:
        description: '"healthy" or other status indicators'
        type: string
      uptime:
        description: Human-readable uptime
        type: string
      version:
        description: API server version
        type: string
    type: object
  models.HostScriptDescription:
    properties:
      content:
        description: The start of the script.
        type: string
      foreign:
        description: |-
          Foreign means the user may not have written this: another user's file or lab, or a
          shared folder.
        type: boolean
      kind:
        description: file or inline
        example: file
        type: string
      owner:
        type: string
      resolvedPath:
        type: string
      sha256:
        type: string
      size:
        type: integer
      truncated:
        type: boolean
    type: object
  models.HostScriptEvent:
    properties:
      error:
        type: string
      result:
        $ref: '#/definitions/models.HostScriptResult'
      stream:
        description: stdout or stderr
        type: string
      text:
        type: string
      type:
        description: output, exit or error
        example: output
        type: string
    type: object
  models.HostScriptResult:
    properties:
      cancelled:
        type: boolean
      durationMs:
        type: integer
      exitCode:
        description: ExitCode is null when a signal stopped the script.
        type: integer
      timedOut:
        type: boolean
    type: object
  models.HostScriptRunRequest:
    properties:
      expectedSha256:
        description: |-
          ExpectedSha256 is the hash of the description the user agreed to. Anything else
          is refused with 409.
        type: string
      script:
        type: string
      scriptPath:
        type: string
      timeoutSeconds:
        description: TimeoutSeconds stops the script after this long; at most, and
          by default, one day.
        type: number
    type: object
  models.HostScriptSourceRequest:
    properties:
      script:
        type: string
      scriptPath:
        type: string
    type: object
  models.IconListResponse:
    properties:
      icons:
        items:
          $ref: '#/definitions/models.CustomIconInfo'
        type: array
    type: object
  models.IconReconcileRequest:
    properties:
      usedIcons:
        items:
          type: string
        type: array
    type: object
  models.IconUploadRequest:
    properties:
      contentType:
        example: image/svg+xml
        type: string
      dataBase64:
        type: string
      fileName:
        example: my-router.svg
        type: string
    required:
    - dataBase64
    - fileName
    type: object
  models.IconUploadResponse:
    properties:
      iconName:
        example: my-router
        type: string
      success:
        example: true
        type: boolean
    type: object
  models.ImportTopologyFromURLRequest:
    properties:
      topologySourceUrl:
        type: string
    required:
    - topologySourceUrl
    type: object
  models.ImportTopologyFromURLResponse:
    properties:
      fileName:
        type: string
      labName:
        type: string
      success:
        type: boolean
      topology:
        $ref: '#/definitions/models.TopologyEntry'
    type: object
  models.InterfaceInfo:
    properties:
      alias:
        description: Interface alias (e.g., "ethernet-1/1", "" if none)
        type: string
      ifindex:
        description: Interface index
        type: integer
      mac:
        description: MAC Address
        type: string
      mtu:
        description: MTU size
        type: integer
      name:
        description: Interface name (e.g., "eth0", "e1-1")
        type: string
      state:
        description: Interface state (e.g., "up", "down", "unknown")
        type: string
      type:
        description: Interface type (e.g., "veth", "device", "dummy")
        type: string
    type: object
  models.LabHostResponse:
    properties:
      c9s:
        allOf:
        - $ref: '#/definitions/models.C9sLabHost'
        description: C9s describes the Kubernetes cluster and deploy defaults; only
          set for c9s.
      capture:
        allOf:
        - $ref: '#/definitions/models.CaptureLabHost'
        description: |-
          Capture is how the server captures packets of the user's labs: Wireshark VNC and, with
          Docker and Podman, Edgeshark.
      defaultTimeout:
        description: |-
          DefaultTimeout is containerlab's timeout of a deploy, redeploy, apply or destroy that
          passes no `timeout`, as a Go duration: 10m on c9s, 5m with Docker and Podman.
        example: 10m
        type: string
      runtime:
        description: 'Runtime is the lab runtime: docker, podman or c9s.'
        enum:
        - docker
        - podman
        - c9s
        example: c9s
        type: string
    type: object
  models.LabLink:
    properties:
      a:
        $ref: '#/definitions/models.LinkEndpoint'
      b:
        $ref: '#/definitions/models.LinkEndpoint'
      type:
        description: |-
          Link type: "veth" for veth pairs, "macvlan" for macvlan interfaces whose
          B endpoint is the parent interface.
        example: veth
        type: string
    type: object
  models.LabRuntimePlan:
    properties:
      changes:
        items:
          $ref: '#/definitions/models.LabRuntimePlanChange'
        type: array
      namespace:
        example: c9s-alice-lab01
        type: string
    type: object
  models.LabRuntimePlanChange:
    properties:
      action:
        example: recreate
        type: string
      kind:
        example: Node
        type: string
      name:
        example: srl1
        type: string
      namespace:
        type: string
    type: object
  models.LabStatsSample:
    properties:
      intervalSeconds:
        description: IntervalSeconds is the time between samples.
        example: 2
        type: number
      nodes:
        items:
          $ref: '#/definitions/models.NodeStats'
        type: array
      time:
        type: string
      type:
        description: Type is always "stats".
        example: stats
        type: string
    type: object
  models.LinkEndpoint:
    properties:
      alias:
        description: Interface alias (e.g. "ethernet-1/1").
        example: ethernet-1/1
        type: string
      container:
        description: Container name, set when Namespace is "node".
        example: clab-mylab-srl1
        type: string
      ifindex:
        description: Interface index inside its namespace.
        example: 12
        type: integer
      interface:
        description: Interface name, empty when the interface could not be looked
          up.
        example: e1-1
        type: string
      mac:
        example: aa:c1:ab:00:00:01
        type: string
      master:
        description: Device the interface is enslaved to, such as a bridge.
        example: br-clab
        type: string
      mtu:
        example: 9500
        type: integer
      namespace:
        description: 'Namespace the interface lives in: "node", "host" or "external".'
        example: node
        type: string
      node:
        description: Topology node name, set when Namespace is "node".
        example: srl1
        type: string
      state:
        example: up
        type: string
    type: object
  models.LoginRequest:
    properties:
      password:
        type: string
      sessionDuration:
        example: 24h
        type: string
      username:
        type: string
    required:
    - password
    - username
    type: object
  models.LoginResponse:
    properties:
      token:
        example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzA2OTIyMDAwfQ.abc123
        type: string
    type: object
  models.LogsResponse:
    properties:
      containerName:
        type: string
      logs:
        type: string
    type: object
  models.MemMetrics:
    properties:
      availableMem:
        description: Available memory in bytes
        type: integer
      processMemMB:
        description: This process's memory in MB
        type: number
      processMemPct:
        description: This process's memory percentage
        type: number
      totalMem:
        description: Total physical memory in bytes
        type: integer
      usagePercent:
        description: Memory usage percentage
        type: number
      usedMem:
        description: Used physical memory in bytes
        type: integer
    type: object
  models.Metrics:
    properties:
      cpu:
        allOf:
        - $ref: '#/definitions/models.CPUMetrics'
        description: CPU usage metrics
      disk:
        allOf:
        - $ref: '#/definitions/models.DiskMetrics'
        description: Disk usage metrics
      mem:
        allOf:
        - $ref: '#/definitions/models.MemMetrics'
        description: Memory usage metrics
    type: object
  models.MetricsResponse:
    properties:
      metrics:
        allOf:
        - $ref: '#/definitions/models.Metrics'
        description: Detailed system metrics
      serverInfo:
        allOf:
        - $ref: '#/definitions/models.ServerInfo'
        description: Basic server information
    type: object
  models.NetemInterfaceInfo:
    properties:
      corruption:
        description: Percentage (might be missing in older clab versions)
        type: number
      delay:
        description: Duration string or empty
        type: string
      interface:
        description: Interface name
        type: string
      jitter:
        description: Duration string or empty
        type: string
      packet_loss:
        description: Percentage
        type: number
      rate:
        description: Kbit/s
        type: integer
    type: object
  models.NetemResetRequest:
    properties:
      containerName:
        description: Container name to reset impairments on (e.g., "clab-my-lab-srl1").
        example: clab-my-lab-srl1
        type: string
      interface:
        description: Interface name or interface alias to reset impairments on (e.g.,
          "eth1" or "mgmt0").
        example: eth1
        type: string
      labName:
        description: Lab name of the topology node to reset impairments on. Used with
          nodeName instead of containerName.
        example: my-lab
        type: string
      nodeName:
        description: Topology node name to reset impairments on. Used with labName
          instead of containerName.
        example: srl1
        type: string
    required:
    - interface
    type: object
  models.NetemSetRequest:
    properties:
      containerName:
        description: Container name to apply impairments on (e.g., "clab-my-lab-srl1").
        example: clab-my-lab-srl1
        type: string
      corruption:
        description: Percentage (0.0 to 100.0)
        example: 0.1
        type: number
      delay:
        description: Duration string (e.g., "100ms", "1s")
        example: 50ms
        type: string
      interface:
        description: Interface name or interface alias to apply impairments on (e.g.,
          "eth1" or "mgmt0").
        example: eth1
        type: string
      jitter:
        description: Duration string, requires Delay
        example: 5ms
        type: string
      labName:
        description: Lab name of the topology node to apply impairments on. Used with
          nodeName instead of containerName.
        example: my-lab
        type: string
      loss:
        description: Percentage (0.0 to 100.0)
        example: 10.5
        type: number
      nodeName:
        description: Topology node name to apply impairments on. Used with labName
          instead of containerName.
        example: srl1
        type: string
      rate:
        description: Kbit/s (non-negative integer)
        example: 1000
        type: integer
    required:
    - interface
    type: object
  models.NetemShowResponse:
    additionalProperties:
      items:
        $ref: '#/definitions/models.NetemInterfaceInfo'
      type: array
    type: object
  models.NodeBrowserPort:
    properties:
      containerPort:
        type: integer
      description:
        type: string
      hostIp:
        type: string
      hostPort:
        type: integer
      protocol:
        type: string
      proxyPath:
        description: |-
          ProxyPath is set on a lab runtime (c9s), where nodes have no host ports: the
          server proxies HTTP to the node's port under this path, with the caller's token.
        example: /api/v1/labs/lab01/nodes/srl1/ports/80/proxy/
        type: string
    type: object
  models.NodeBrowserPortsResponse:
    properties:
      containerName:
        type: string
      nodeName:
        type: string
      ports:
        items:
          $ref: '#/definitions/models.NodeBrowserPort'
        type: array
    type: object
  models.NodeInterfaceInfo:
    properties:
      interfaces:
        items:
          $ref: '#/definitions/models.InterfaceInfo'
        type: array
      name:
        description: Name of the container node
        type: string
    type: object
  models.NodeStats:
    properties:
      cpuCount:
        description: CPUCount is the number of CPUs the node can use, when known.
        example: 8
        type: integer
      cpuPercent:
        description: |-
          CPUPercent is the CPU usage since the previous sample, where 100 is one busy CPU.
          It is missing in the first sample of a node.
        example: 12.5
        type: number
      memoryBytes:
        example: 536870912
        type: integer
      memoryLimitBytes:
        example: 8589934592
        type: integer
      name:
        description: Name is the container name.
        example: clab-my-lab-srl1
        type: string
      nodeName:
        description: NodeName is the node name in the topology.
        example: srl1
        type: string
      pids:
        example: 42
        type: integer
    type: object
  models.PasswordChangeRequest:
    properties:
      currentPassword:
        description: Required if not superuser
        type: string
      newPassword:
        type: string
    required:
    - newPassword
    type: object
  models.RenderedTopologyResponse:
    properties:
      content:
        description: Content is the rendered topology YAML.
        example: 'name: lab01'
        type: string
      error:
        description: Error is containerlab's error when it rejects the rendered YAML.
        type: string
      labName:
        description: LabName is the rendered top-level name with Git name variables
          expanded.
        example: lab01
        type: string
      path:
        description: Path is the requested workspace-relative topology path.
        example: lab01/lab01.clab.gotmpl
        type: string
      varsFiles:
        description: |-
          VarsFiles lists the variable files used for rendering relative to the
          topology file's directory, including files containerlab discovered next to it.
        example:
        - lab01.clab_vars.yml
        items:
          type: string
        type: array
    type: object
  models.RuntimeImageActionResponse:
    properties:
      image:
        type: string
      message:
        type: string
      output:
        type: string
      success:
        type: boolean
    type: object
  models.RuntimeImagePullRequest:
    properties:
      image:
        type: string
    required:
    - image
    type: object
  models.RuntimeImageSummary:
    properties:
      createdAt:
        type: string
      id:
        type: string
      repoDigests:
        items:
          type: string
        type: array
      repoTags:
        items:
          type: string
        type: array
      shortId:
        type: string
      size:
        type: string
      virtualSize:
        type: string
    type: object
  models.RuntimeImagesResponse:
    properties:
      images:
        items:
          $ref: '#/definitions/models.RuntimeImageSummary'
        type: array
      runtime:
        type: string
    type: object
  models.SSHAccessRequest:
    properties:
      duration:
        description: How long the access should be valid for (e.g., "1h", "30m")
        type: string
      sshUsername:
        description: Optional override for container's SSH user
        type: string
    type: object
  models.SSHAccessResponse:
    properties:
      command:
        description: Example SSH command
        type: string
      expiration:
        description: When this access expires
        type: string
      host:
        description: API server's hostname or IP
        type: string
      port:
        description: Allocated port on API server
        type: integer
      username:
        description: Username to use for SSH
        type: string
    type: object
  models.SSHSessionInfo:
    properties:
      created:
        description: When this access was created
        type: string
      expiration:
        description: When this access expires
        type: string
      labName:
        description: Lab name
        type: string
      nodeName:
        description: Node name
        type: string
      port:
        description: Allocated port on API server
        type: integer
      username:
        description: SSH username
        type: string
    type: object
  models.SSHXShareRequest:
    properties:
      enableReaders:
        description: EnableReaders also creates a read-only access link.
        example: true
        type: boolean
    type: object
  models.SaveConfigResponse:
    properties:
      copyDir:
        description: |-
          CopyDir is the <copy>/<lab dir> directory the configs were copied to when
          copy was requested: workspace-relative, @shared/... or absolute.
        example: lab1/backups/clab-lab1
        type: string
      message:
        description: Message indicating overall success.
        type: string
      output:
        description: Detailed output from the 'clab save' command (often from stderr).
        type: string
    type: object
  models.ServerInfo:
    properties:
      startTime:
        description: When the server started
        type: string
      uptime:
        description: Human-readable uptime
        type: string
      version:
        description: API server version
        type: string
    type: object
  models.ShareToolResponse:
    properties:
      link:
        type: string
      message:
        type: string
      output:
        type: string
      readOnlyLink:
        description: ReadOnlyLink is the SSHX read-only access link when readers are
          enabled.
        type: string
      shell:
        description: Shell is the effective GoTTY shell (attach/reattach only).
        type: string
      username:
        description: Username is the effective GoTTY login name (attach/reattach only).
        type: string
    type: object
  models.SimpleSuccessResponse:
    properties:
      success:
        example: true
        type: boolean
    type: object
  models.SnapshotNodeResult:
    properties:
      durationMs:
        example: 45000
        type: integer
      error:
        type: string
      node:
        example: r1
        type: string
      path:
        description: Path is the snapshot file, workspace-relative (or @shared/...)
          when inside a workspace root.
        example: lab1/snapshots/r1.tar
        type: string
      reason:
        description: Reason explains skipped nodes.
        example: not a vrnetlab node (kind=nokia_srlinux, image=ghcr.io/nokia/srlinux)
        type: string
      sizeBytes:
        example: 104857600
        type: integer
      status:
        description: Status is "success", "failed" or "skipped".
        enum:
        - success
        - failed
        - skipped
        example: success
        type: string
    type: object
  models.SnapshotSaveRequest:
    properties:
      nodes:
        description: Nodes limits the snapshot to these topology node names (all nodes
          when empty).
        example:
        - r1
        - r2
        items:
          type: string
        type: array
      outputDir:
        description: |-
          OutputDir is a path relative to the topology directory, or an absolute path,
          inside the user's workspace (or the shared root for shared labs). Defaults to "snapshots".
        example: snapshots
        type: string
      timeout:
        description: Timeout is the per-node wait as a Go duration (default 5m, maximum
          30m).
        example: 5m
        type: string
    type: object
  models.SnapshotSaveResponse:
    properties:
      outputDir:
        description: OutputDir is workspace-relative (or @shared/...) when inside
          a workspace root.
        example: lab1/snapshots
        type: string
      results:
        items:
          $ref: '#/definitions/models.SnapshotNodeResult'
        type: array
      summary:
        example: 2 succeeded, 0 failed, 1 skipped
        type: string
    type: object
  models.TailscaleDevice:
    properties:
      authUrl:
        description: AuthURL is the login URL to open while the device waits for authentication.
        example: https://login.tailscale.com/a/0123456789ab
        type: string
      backendState:
        description: BackendState is the tailscaled state, e.g. NeedsLogin or Running.
        example: NeedsLogin
        type: string
      containerName:
        example: clab-mylab-ts
        type: string
      dnsName:
        example: clab-mylab.tailnet-1234.ts.net
        type: string
      error:
        description: Error reports why the tailnet state could not be read.
        type: string
      forwards:
        description: Forwards lists the tailnet ports the SSO proxy forwards to nodes
          (/ts ports).
        items:
          $ref: '#/definitions/models.TailscaleForward'
        type: array
      hostName:
        example: clab-mylab
        type: string
      nodeName:
        example: srl1
        type: string
      online:
        type: boolean
      role:
        description: |-
          Role is "proxy" for the SSO proxy (mgmt.tailscale.auth-mode: sso), "sidecar"
          for the auth-key sidecar of nodeName, or "node" for a node of the tailscale kind.
        example: proxy
        type: string
      state:
        example: running
        type: string
      tailscaleIps:
        items:
          type: string
        type: array
    type: object
  models.TailscaleForward:
    properties:
      listenPort:
        example: 2201
        type: integer
      nodeName:
        example: srl1
        type: string
      target:
        example: 172.20.20.2:22
        type: string
    type: object
  models.TailscaleStatusResponse:
    properties:
      devices:
        items:
          $ref: '#/definitions/models.TailscaleDevice'
        type: array
      labName:
        example: mylab
        type: string
    type: object
  models.TerminalProtocol:
    enum:
    - ssh
    - shell
    - telnet
    type: string
    x-enum-varnames:
    - TerminalProtocolSSH
    - TerminalProtocolShell
    - TerminalProtocolTelnet
  models.TerminalSessionInfo:
    properties:
      attached:
        description: Attached reports whether a client is connected to the session's
          stream.
        type: boolean
      createdAt:
        type: string
      error:
        type: string
      exitCode:
        type: integer
      expiresAt:
        type: string
      labName:
        type: string
      lastActivity:
        type: string
      nodeName:
        type: string
      protocol:
        $ref: '#/definitions/models.TerminalProtocol'
      resumable:
        description: Resumable reports whether the session outlives a disconnected
          stream.
        type: boolean
      sessionId:
        type: string
      state:
        type: string
      username:
        type: string
    type: object
  models.TerminalSessionRequest:
    properties:
      cols:
        description: Cols is the requested terminal width in characters.
        type: integer
      protocol:
        allOf:
        - $ref: '#/definitions/models.TerminalProtocol'
        description: 'Protocol selects the terminal transport: ssh, shell, or telnet.'
      resumable:
        description: |-
          Resumable keeps the session running when its stream disconnects, so the
          client can attach again. Without it the session ends with its stream.
        type: boolean
      rows:
        description: Rows is the requested terminal height in characters.
        type: integer
      sshUsername:
        description: SSHUsername optionally overrides the SSH username for protocol=ssh.
        type: string
      telnetPort:
        description: TelnetPort optionally overrides the telnet destination port for
          protocol=telnet.
        type: integer
    required:
    - protocol
    type: object
  models.TopologyDocEventResponse:
    properties:
      action:
        example: change
        type: string
      documentKind:
        example: annotations
        type: string
      labName:
        example: mylab
        type: string
      path:
        example: mylab.clab.yml.annotations.json
        type: string
      revision:
        example: yaml=123-456;annotations=78-910
        type: string
      type:
        example: topology-doc
        type: string
    type: object
  models.TopologyEntry:
    properties:
      absolutePath:
        description: Exact source path for matching runtime lab paths; file operations
          use yamlFileName.
        type: string
      annotationsFileName:
        description: Sidecar path relative to the managed workspace root.
        type: string
      deploymentState:
        description: undeployed (runtime state is derived from events stream)
        type: string
      hasAnnotations:
        type: boolean
      labName:
        type: string
      yamlFileName:
        description: Topology path relative to the managed workspace root.
        type: string
    type: object
  models.TopologyFileRenameRequest:
    properties:
      newPath:
        example: configs/startup.bak.cfg
        type: string
      oldPath:
        example: configs/startup.cfg
        type: string
    required:
    - newPath
    - oldPath
    type: object
  models.UserCreateRequest:
    properties:
      displayName:
        type: string
      groups:
        items:
          type: string
        type: array
      isSuperuser:
        type: boolean
      password:
        type: string
      shell:
        description: Default to /bin/bash if empty
        type: string
      username:
        type: string
    required:
    - password
    - username
    type: object
  models.UserDetails:
    properties:
      displayName:
        description: Full name from GECOS field
        type: string
      gid:
        type: string
      groups:
        items:
          type: string
        type: array
      homeDir:
        type: string
      isApiUser:
        type: boolean
      isSuperuser:
        type: boolean
      shell:
        type: string
      uid:
        type: string
      username:
        type: string
    type: object
  models.UserUpdateRequest:
    properties:
      displayName:
        type: string
      groups:
        items:
          type: string
        type: array
      isSuperuser:
        type: boolean
      shell:
        type: string
    type: object
  models.ValidateTopologyResponse:
    properties:
      error:
        description: Error is containerlab's validation error when Valid is false.
        type: string
      labName:
        example: lab01
        type: string
      links:
        example: 1
        type: integer
      nodes:
        example: 2
        type: integer
      path:
        example: /home/alice/.clab/lab01/lab01.clab.yml
        type: string
      valid:
        example: true
        type: boolean
    type: object
  models.VersionCheckResponse:
    properties:
      checkResult:
        description: Raw output string from 'clab version check'.
        example: "\U0001F389 A newer containerlab version (0.62.2) is available!\nRelease
          notes: https://containerlab.dev/rn/0.62/#0622\nRun 'sudo clab version upgrade'
          or see https://containerlab.dev/install/ for installation options."
        type: string
    type: object
  models.VersionResponse:
    properties:
      versionInfo:
        description: Raw output string from 'clab version'.
        example: |-
          version: 0.50.0
          commit: 1234abcd
          date: 2024-01-15T10:00:00Z
          github: https://github.com/srl-labs/containerlab
          release notes: https://containerlab.dev/rn/0.50/
        type: string
    type: object
  models.VethCreateRequest:
    properties:
      aEndpoint:
        description: |-
          Endpoint A definition. Format: <node-name>:<interface-name> OR <kind>:<node-name>:<interface-name>
          Example: "clab-demo-node1:eth1" or "bridge:br-1:br-eth1" or "host:veth-eth1"
        example: clab-demo-node1:eth1
        type: string
      bEndpoint:
        description: |-
          Endpoint B definition. Format: <node-name>:<interface-name> OR <kind>:<node-name>:<interface-name>
          Example: "clab-demo-node2:eth1" or "ovs-bridge:ovsbr-1:br-eth1"
        example: clab-demo-node2:eth1
        type: string
      mtu:
        description: MTU for the vEth pair. Defaults to 9500 if omitted.
        example: 1500
        type: integer
    required:
    - aEndpoint
    - bEndpoint
    type: object
  models.VxlanCreateRequest:
    properties:
      dev:
        description: 'Optional: Linux device to use for the tunnel source. Auto-detected
          if omitted.'
        example: eth0
        type: string
      id:
        description: VxLAN Network Identifier (VNI). Defaults to 10 if omitted.
        example: 100
        type: integer
      link:
        description: Name of the existing interface in the root namespace to bridge
          traffic with.
        example: srl_e1-1
        type: string
      mtu:
        description: 'Optional: MTU for the VxLAN interface. Auto-calculated if omitted.'
        example: 1400
        type: integer
      port:
        description: UDP port number for the VxLAN tunnel. Defaults to 14789 if omitted.
        example: 4789
        type: integer
      remote:
        description: Remote VTEP IP address.
        example: 10.0.0.20
        type: string
    required:
    - link
    - remote
    type: object
  models.WorkspaceDirectoryRequest:
    properties:
      path:
        example: lab1/configs
        type: string
    required:
    - path
    type: object
  models.WorkspaceFileEntry:
    properties:
      hasChildren:
        type: boolean
      kind:
        description: file or directory
        type: string
      modifiedAt:
        type: string
      name:
        type: string
      path:
        type: string
      size:
        type: integer
    type: object
  models.WorkspaceFileEventResponse:
    properties:
      action:
        example: delete
        type: string
      kind:
        example: file
        type: string
      parentPath:
        example: lab1/configs
        type: string
      path:
        example: lab1/configs/startup.cfg
        type: string
      type:
        example: workspace-file
        type: string
    type: object
  models.WorkspaceFileRenameRequest:
    properties:
      newPath:
        example: lab1/configs/startup.bak.cfg
        type: string
      oldPath:
        example: lab1/configs/startup.cfg
        type: string
    required:
    - newPath
    - oldPath
    type: object
info:
  contact:
    name: Containerlab API Server maintainers
    url: https://github.com/srl-labs/clab-api-server/issues
  description: |-
    REST API for authenticated Linux users to manage Containerlab deployments, topology files, node access, captures, and host networking tools.

    Most endpoints under /api/v1 require a JWT from POST /login. Send it as: Authorization: Bearer <token>.
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  title: Containerlab API Server
  version: "1.0"
paths:
  /api/v1/capture/wireshark-vnc-sessions:
    delete:
      description: Terminates all capture VNC sessions owned by the authenticated
        user. Superusers terminate all sessions.
      produces:
      - application/json
      responses:
        "200":
          description: Capture sessions terminated
          schema:
            $ref: '#/definitions/models.CaptureCloseAllResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete all Wireshark VNC sessions
      tags:
      - Capture
  /api/v1/capture/wireshark-vnc-sessions/{sessionId}:
    delete:
      description: Terminates a capture VNC session and stops the corresponding Wireshark
        container.
      parameters:
      - description: Capture session ID
        in: path
        name: sessionId
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Capture session terminated
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete Wireshark VNC session
      tags:
      - Capture
  /api/v1/capture/wireshark-vnc-sessions/{sessionId}/ready:
    get:
      description: Returns whether a capture VNC session is ready and its proxied
        URL path.
      parameters:
      - description: Capture session ID
        in: path
        name: sessionId
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Readiness state
          schema:
            $ref: '#/definitions/models.CaptureWiresharkVncReadyResponse'
        "400":
          description: Invalid request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get Wireshark VNC session readiness
      tags:
      - Capture
  /api/v1/capture/wireshark-vnc-sessions/{sessionId}/vnc/{proxyPath}:
    get:
      description: Proxies noVNC HTTP assets for a capture session. WebSocket upgrades
        on this path are used by noVNC but are not represented in Swagger.
      parameters:
      - description: Capture session ID
        in: path
        name: sessionId
        required: true
        type: string
      - description: Proxy subpath under the noVNC root
        in: path
        name: proxyPath
        required: true
        type: string
      produces:
      - text/html
      responses:
        "200":
          description: Proxied noVNC asset response
          schema:
            type: string
        "400":
          description: Invalid request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "502":
          description: VNC proxy upstream error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Proxy Wireshark VNC assets
      tags:
      - Capture
  /api/v1/events:
    get:
      description: |-
        Streams containerlab events in real time as NDJSON (one JSON object per line).

        **Notes**
        - The response stays open until the client disconnects.

        **Examples**
        NDJSON (one JSON object per line):
        ```json
        {"time":1706918400,"type":"container","action":"start","attributes":{"name":"clab-mylab-srl1","lab":"mylab","clab-node-name":"srl1","clab-node-kind":"nokia_srlinux"}}
        {"time":1706918405,"type":"container","action":"start","attributes":{"name":"clab-mylab-srl2","lab":"mylab","clab-node-name":"srl2","clab-node-kind":"nokia_srlinux"}}
        ```


        Interface stats (interfaceStats=true):
        ```json
        {"time":1706918410,"type":"interface-stats","action":"stats","attributes":{"name":"clab-mylab-srl1","lab":"mylab","interface":"e1-1","rx_bytes":123456,"tx_bytes":654321}}
        ```
      parameters:
      - default: false
        description: Include initial snapshot events when the stream starts.
        in: query
        name: initialState
        type: boolean
      - default: false
        description: Include interface stats events.
        in: query
        name: interfaceStats
        type: boolean
      - default: 10s
        description: Interval for interface stats collection (e.g., 10s). Requires
          interfaceStats=true.
        in: query
        name: interfaceStatsInterval
        type: string
      produces:
      - application/x-ndjson
      responses:
        "200":
          description: Event stream - NDJSON (one JSON object per line)
          schema:
            $ref: '#/definitions/models.EventResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stream containerlab events
      tags:
      - Events
  /api/v1/generate:
    post:
      consumes:
      - application/json
      description: |-
        Generates a containerlab topology from CLOS definitions and can optionally deploy it for the authenticated user.

        **Notes**
        - Deployment is denied if a lab with the target name already exists.
        - The `images` and `licenses` fields map node kind to image or license path (e.g., {"nokia_srlinux":"ghcr.io/..."}).
        - When `deploy=true`, the topology is saved to the user's managed lab directory and `outputFile` is ignored.
        - When `deploy=false` and `outputFile` is empty, YAML is returned in the response.
        - When `deploy=false` and `outputFile` is set, the file is saved to that path on the server (requires API server write permissions).
      parameters:
      - description: Topology generation parameters. The 'images' field maps kind
          to image path.
        in: body
        name: generate_request
        required: true
        schema:
          $ref: '#/definitions/models.GenerateRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Generation successful (YAML or deploy output)
          schema:
            $ref: '#/definitions/models.GenerateResponse'
        "400":
          description: Invalid input parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Conflict (Lab already exists and Deploy=true)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error or clab execution failed
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Generate containerlab topology
      tags:
      - Topology Generation
  /api/v1/health/metrics:
    get:
      description: Returns detailed CPU, memory, and disk metrics for the API server.
        Requires authentication.
      produces:
      - application/json
      responses:
        "200":
          description: System metrics
          schema:
            $ref: '#/definitions/models.MetricsResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error gathering metrics
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get system metrics
      tags:
      - Health
  /api/v1/images:
    delete:
      parameters:
      - description: Image reference or ID
        in: query
        name: reference
        required: true
        type: string
      - description: Force image removal
        in: query
        name: force
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.RuntimeImageActionResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Remove a runtime image
      tags:
      - Images
    get:
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.RuntimeImagesResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List runtime images
      tags:
      - Images
  /api/v1/images/pull:
    post:
      consumes:
      - application/json
      parameters:
      - description: Image reference
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.RuntimeImagePullRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.RuntimeImageActionResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Pull a runtime image
      tags:
      - Images
  /api/v1/lab-host:
    get:
      description: |-
        Returns the runtime the server runs labs with and, on c9s, the Kubernetes cluster and deploy defaults the signed-in user's labs get.

        **Notes**
        - `c9s` is only set when `runtime` is `c9s`. It names the kubeconfig context and cluster (`in-cluster` with the Pod's ServiceAccount) but never the cluster's address, credentials or file paths.
        - `namespacePattern` is the server's namespace template rendered for the signed-in user, with `{lab}` left in. `sharedNamespacePattern` is the namespace of labs in the shared workspace.
        - `metrics` reports whether the cluster serves `metrics.k8s.io`, which node stats need.
        - `defaultTimeout` is containerlab's timeout of a deploy, redeploy, apply or destroy without `timeout` (with every runtime).
        - `capture` is how the server captures packets, with every runtime: whether it runs Wireshark VNC sessions (`wiresharkVnc`; on c9s only while Docker answers on the server host), their image and pull policy and, with Docker and Podman, Edgeshark's packetflix port and the names (not values) of its extra environment variables.
        - `c9s.noTopologyCR` is false: the server deploys every lab with clabernetes' Topology resource.
        - The server must list `lab-host-info` in the `features` of `/health`.
      produces:
      - application/json
      responses:
        "200":
          description: Lab runtime and, on c9s, the cluster and deploy defaults
          schema:
            $ref: '#/definitions/models.LabHostResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get the lab host
      tags:
      - Health
  /api/v1/labs:
    get:
      description: |-
        Returns details for all running labs.

        **Notes**
        - Regular users see their own labs and labs in CLAB_SHARED_LABS_ROOT. Superusers see all labs.
      produces:
      - application/json
      responses:
        "200":
          description: All labs
          schema:
            $ref: '#/definitions/models.ClabInspectOutput'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List labs
      tags:
      - Labs
    post:
      consumes:
      - application/json
      description: |-
        Deploys a containerlab topology.

        **Notes**
        - The request body must include either `topologyContent` or `topologySourceUrl` (not both).
      parameters:
      - description: Deployment Source
        in: body
        name: deploy_request
        required: true
        schema:
          $ref: '#/definitions/models.DeployRequest'
      - description: Override lab name when deploying from a URL (optional)
        in: query
        name: labNameOverride
        type: string
      - description: Allow overwriting an existing lab IF owned by the user
        in: query
        name: reconfigure
        type: boolean
      - description: Limit concurrent workers
        in: query
        name: maxWorkers
        type: integer
      - description: Custom Go template file for topology data export
        in: query
        name: exportTemplate
        type: string
      - description: Comma-separated list of node names to deploy
        in: query
        name: nodeFilter
        type: string
      - description: Skip post-deploy actions
        in: query
        name: skipPostDeploy
        type: boolean
      - description: Skip setting extended ACLs on lab directory
        in: query
        name: skipLabdirAcl
        type: boolean
      - description: Override the management network name (like --network); not allowed
          with multiple management networks
        in: query
        name: network
        type: string
      - description: Override the management network IPv4 subnet (like --ipv4-subnet)
        in: query
        name: ipv4Subnet
        type: string
      - description: Override the management network IPv6 subnet (like --ipv6-subnet)
        in: query
        name: ipv6Subnet
        type: string
      - description: Restore nodes from <node>.tar snapshots in this directory (like
          --restore-all); relative to the topology directory or absolute, inside the
          workspace
        in: query
        name: restoreAll
        type: string
      - collectionFormat: multi
        description: Restore one node from a snapshot file as node=path (like --restore);
          repeatable, overrides restoreAll
        in: query
        items:
          type: string
        name: restore
        type: array
      - description: containerlab timeout like --timeout, a Go duration such as 10m
          or 1h; at most 2h. Defaults to 10m on c9s and 5m with Docker and Podman
        in: query
        name: timeout
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Deployed lab details
          schema:
            $ref: '#/definitions/models.ClabInspectOutput'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Conflict
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Deploy lab
      tags:
      - Labs
  /api/v1/labs/{labName}:
    delete:
      description: |-
        Destroys a lab by name after verifying access to an owned or shared lab, or superuser access.

        **Notes**
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
      parameters:
      - description: Name of the lab to destroy
        in: path
        name: labName
        required: true
        type: string
      - description: Remove containerlab lab artifacts after destroy
        in: query
        name: cleanup
        type: boolean
      - description: Purge topology parent directory below the personal or shared
          workspace root
        in: query
        name: purgeLabDir
        type: boolean
      - description: Attempt graceful shutdown
        in: query
        name: graceful
        type: boolean
      - description: Override graceful shutdown timeout when graceful=true (for example
          5s or 2m)
        in: query
        name: gracefulTimeout
        type: string
      - description: Keep the management network
        in: query
        name: keepMgmtNet
        type: boolean
      - description: Destroy only specific nodes
        in: query
        name: nodeFilter
        type: string
      - description: Template variables file (like --vars) relative to the lab's topology
          file directory
        in: query
        name: varsPath
        type: string
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      - description: containerlab timeout like --timeout, a Go duration such as 10m
          or 1h; at most 2h. Defaults to 10m on c9s and 5m with Docker and Podman
        in: query
        name: timeout
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Lab destroyed successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or vars file not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Destroy lab
      tags:
      - Labs
    get:
      description: |-
        Returns details for a specific running lab.

        **Notes**
        - `details=true` returns what `containerlab inspect --details` prints for the lab instead: a JSON object `{ "<labName>": [ runtime container objects ] }` with fields such as `Names`, `ID`, `ShortID`, `Image`, `State`, `Status`, `Labels`, `Pid`, `NetworkName`, `NetworkSettings`, `Mounts` and `Ports`. Internal helper containers are excluded.
      parameters:
      - description: Name of the lab to inspect
        in: path
        name: labName
        required: true
        type: string
      - description: Return runtime container details like containerlab inspect --details
        in: query
        name: details
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: Lab containers, or the details object when details=true
          schema:
            items:
              $ref: '#/definitions/models.ClabContainerInfo'
            type: array
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Inspect lab
      tags:
      - Labs
    put:
      description: |-
        Redeploys a lab by name.

        **Notes**
        - This operation destroys the lab and then deploys it again.
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
      parameters:
      - description: Name of the lab to redeploy
        in: path
        name: labName
        required: true
        type: string
      - description: Remove containerlab lab artifacts during destroy phase
        in: query
        name: cleanup
        type: boolean
      - description: Attempt graceful shutdown
        in: query
        name: graceful
        type: boolean
      - description: Override graceful shutdown timeout when graceful=true (for example
          5s or 2m)
        in: query
        name: gracefulTimeout
        type: string
      - description: Keep the management network
        in: query
        name: keepMgmtNet
        type: boolean
      - description: Limit concurrent workers
        in: query
        name: maxWorkers
        type: integer
      - description: Custom Go template file for topology data export
        in: query
        name: exportTemplate
        type: string
      - description: Skip post-deploy actions
        in: query
        name: skipPostDeploy
        type: boolean
      - description: Skip setting extended ACLs on lab directory
        in: query
        name: skipLabdirAcl
        type: boolean
      - description: Template variables file (like --vars) relative to the lab's topology
          file directory, used for the destroy and deploy phases
        in: query
        name: varsPath
        type: string
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      - description: Override the management network name (like --network); not allowed
          with multiple management networks
        in: query
        name: network
        type: string
      - description: Override the management network IPv4 subnet (like --ipv4-subnet)
        in: query
        name: ipv4Subnet
        type: string
      - description: Override the management network IPv6 subnet (like --ipv6-subnet)
        in: query
        name: ipv6Subnet
        type: string
      - description: containerlab timeout like --timeout, a Go duration such as 10m
          or 1h; at most 2h. Defaults to 10m on c9s and 5m with Docker and Podman
        in: query
        name: timeout
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Redeployed lab details
          schema:
            $ref: '#/definitions/models.ClabInspectOutput'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or vars file not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Redeploy lab
      tags:
      - Labs
  /api/v1/labs/{labName}/apply:
    post:
      description: |-
        Applies an on-disk topology from the authenticated user's lab directory. If the lab is not running, containerlab apply deploys it; otherwise it reconciles supported topology changes in place.

        **Notes**
        - `path` defaults to the running lab topology path when the lab exists, otherwise `<labName>.clab.yml`.
        - `dryRun=true` returns the apply plan without changing the lab.
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative or legacy lab-relative topology path (defaults
          to running topology path or <labName>.clab.yml)
        in: query
        name: path
        type: string
      - description: Show apply actions without applying them
        in: query
        name: dryRun
        type: boolean
      - description: Limit concurrent workers for new nodes
        in: query
        name: maxWorkers
        type: integer
      - description: Custom Go template file for topology data export
        in: query
        name: exportTemplate
        type: string
      - description: Skip post-deploy actions for added nodes
        in: query
        name: skipPostDeploy
        type: boolean
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      - description: containerlab timeout like --timeout, a Go duration such as 10m
          or 1h; at most 2h. Defaults to 10m on c9s and 5m with Docker and Podman
        in: query
        name: timeout
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Apply result
          schema:
            $ref: '#/definitions/models.ApplyLabResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or topology file not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Conflict
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Apply on-disk topology for lab
      tags:
      - Labs
  /api/v1/labs/{labName}/capture/interfaces:
    get:
      description: Lists the lab link interfaces of the lab's running nodes that packet
        capture accepts, with the far end of each link. The management interface is
        not capturable. With Docker and Podman the links come from the topology file
        the lab was deployed from; on c9s this runs as the signed-in user.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Capturable interfaces, ordered by node and interface
          schema:
            items:
              $ref: '#/definitions/models.CaptureInterfaceInfo'
            type: array
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden by Kubernetes RBAC
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Docker or Podman lab whose topology file is gone
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List capturable interfaces
      tags:
      - Capture
  /api/v1/labs/{labName}/capture/packetflix:
    post:
      consumes:
      - application/json
      description: Builds packetflix URI(s) for the provided lab interface targets
        (non-VNC capture mode).
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Packetflix capture request
        in: body
        name: capture_request
        required: true
        schema:
          $ref: '#/definitions/models.CapturePacketflixRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Packetflix capture URI payload
          schema:
            $ref: '#/definitions/models.CapturePacketflixResponse'
        "400":
          description: Invalid request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or container not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "503":
          description: EdgeShark not running
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Build packetflix capture URI
      tags:
      - Capture
  /api/v1/labs/{labName}/capture/stream:
    get:
      description: 'Captures lab link interfaces of a lab without Edgeshark: on c9s
        as the signed-in user through clabwire, with Docker and Podman through packet
        sockets in the nodes'' network namespaces. It streams one pcapng section as
        it is produced: chunked, flushed per block. The section has one interface
        per target, named <node>:<interface>, before any packet; packets are in timestamp
        order. The stream ends when the duration passed, the packet limit was reached,
        or the client disconnects, which stops the capture in the lab. Errors before
        the first byte are JSON; later ones end the stream. On c9s, captures longer
        than clabwire''s 1 h limit are chained by containerlab without duplicates.'
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - collectionFormat: multi
        description: Interface to capture, <node>:<interface> (the interface name
          or its alias); repeat for several
        in: query
        items:
          type: string
        name: target
        required: true
        type: array
      - description: 'Capture duration (Go duration, e.g. 30s); default: until the
          client disconnects'
        in: query
        name: duration
        type: string
      - description: Stop after this many packets across all targets
        in: query
        name: packetLimit
        type: integer
      - description: Bytes kept per packet, 64 to 1048576 (default 262144)
        in: query
        name: snapLength
        type: integer
      - description: '1: send Content-Disposition: attachment; filename=<lab>-<timestamp>.pcapng'
        enum:
        - "1"
        in: query
        name: download
        type: string
      produces:
      - application/x-pcapng
      - application/json
      responses:
        "200":
          description: pcapng stream
          schema:
            type: file
        "400":
          description: Invalid target, duration or limit
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden by Kubernetes RBAC
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: A target node is not running, or a Docker or Podman lab's topology
            file is gone
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stream a packet capture
      tags:
      - Capture
  /api/v1/labs/{labName}/capture/wireshark-vnc-sessions:
    post:
      consumes:
      - application/json
      description: Creates one or more Wireshark noVNC capture sessions for the specified
        lab interface targets, one per container. With Docker and Podman the sessions
        capture through Edgeshark. With lab runtime c9s, containerName is the node's
        inspect name (<lab>-<node>) and interfaceName a capturable interface (or its
        alias); the server captures the session's interfaces as the signed-in user,
        in one pcapng stream, and writes it into a named pipe the session's Wireshark
        reads, without Edgeshark. That needs Docker on the server host (otherwise
        501, and /health leaves out wireshark-vnc) and a Wireshark VNC image with
        the CLABWIRE_CAPTURE_PIPE mode of wireshark-vnc-docker. The capture ends with
        the session; when it fails, the session's container stops and its ready and
        VNC routes answer 500 with the reason.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Wireshark VNC capture request
        in: body
        name: capture_request
        required: true
        schema:
          $ref: '#/definitions/models.CaptureWiresharkVncRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Created capture sessions
          schema:
            $ref: '#/definitions/models.CaptureWiresharkVncCreateResponse'
        "400":
          description: Invalid request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or container not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: A target node is not running (c9s)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: No Docker on the server host (c9s)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "503":
          description: EdgeShark not running
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create Wireshark VNC capture session(s)
      tags:
      - Capture
  /api/v1/labs/{labName}/deploy:
    post:
      description: |-
        Deploys an on-disk topology from the authenticated user's lab directory.

        **Notes**
        - `path` defaults to `<labName>.clab.yml` when omitted.
        - `varsPath` selects the template variables file like `--vars`, relative to the topology file's directory and inside the same workspace; when omitted, containerlab uses `<topology name without extension>_vars.{yaml,yml,json}` next to the topology.
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative or legacy lab-relative topology path (defaults
          to <labName>.clab.yml)
        in: query
        name: path
        type: string
      - description: Template variables file relative to the topology file's directory
          (like --vars)
        in: query
        name: varsPath
        type: string
      - description: Allow overwriting an existing lab
        in: query
        name: reconfigure
        type: boolean
      - description: Limit concurrent workers
        in: query
        name: maxWorkers
        type: integer
      - description: Custom Go template file for topology data export
        in: query
        name: exportTemplate
        type: string
      - description: Comma-separated list of node names to deploy
        in: query
        name: nodeFilter
        type: string
      - description: Skip post-deploy actions
        in: query
        name: skipPostDeploy
        type: boolean
      - description: Skip setting extended ACLs on lab directory
        in: query
        name: skipLabdirAcl
        type: boolean
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      - description: Override the management network name (like --network); not allowed
          with multiple management networks
        in: query
        name: network
        type: string
      - description: Override the management network IPv4 subnet (like --ipv4-subnet)
        in: query
        name: ipv4Subnet
        type: string
      - description: Override the management network IPv6 subnet (like --ipv6-subnet)
        in: query
        name: ipv6Subnet
        type: string
      - description: Restore nodes from <node>.tar snapshots in this directory (like
          --restore-all); relative to the topology directory or absolute, inside the
          workspace
        in: query
        name: restoreAll
        type: string
      - collectionFormat: multi
        description: Restore one node from a snapshot file as node=path (like --restore);
          repeatable, overrides restoreAll
        in: query
        items:
          type: string
        name: restore
        type: array
      - description: containerlab timeout like --timeout, a Go duration such as 10m
          or 1h; at most 2h. Defaults to 10m on c9s and 5m with Docker and Podman
        in: query
        name: timeout
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Deployed lab details
          schema:
            $ref: '#/definitions/models.ClabInspectOutput'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Topology or vars file not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Conflict
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Deploy on-disk topology for lab
      tags:
      - Labs
  /api/v1/labs/{labName}/exec:
    post:
      consumes:
      - application/json
      description: |-
        Executes a command on nodes within a lab.

        **Notes**
        - `nodes` (comma-separated topology node names) and `label` (repeatable `key=value`, like `containerlab exec --label`) combine with AND and always stay within the lab.
        - `nodeFilter` cannot be combined with `nodes` or `label`.
        - With `nodes` or `label`, a filter that matches no container returns 404.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - description: Execute only on this specific container
        in: query
        name: nodeFilter
        type: string
      - description: Comma-separated topology node names to execute on
        in: query
        name: nodes
        type: string
      - collectionFormat: multi
        description: Label filter in key=value form; repeat for several labels
        in: query
        items:
          type: string
        name: label
        type: array
      - description: Command to execute
        in: body
        name: exec_request
        required: true
        schema:
          $ref: '#/definitions/models.ExecRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Execution result
          schema:
            $ref: '#/definitions/models.ExecResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found or no node matches the filters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Execute command in lab
      tags:
      - Labs
  /api/v1/labs/{labName}/fcli:
    post:
      consumes:
      - application/json
      deprecated: true
      description: 'Deprecated: use POST /api/v1/labs/{labName}/fcling. Runs the same
        fcling report.'
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: fcling command request
        in: body
        name: fcli_request
        required: true
        schema:
          $ref: '#/definitions/models.FclingCommandRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.FclingCommandResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Run fcling report (old path)
      tags:
      - Labs - Tools
  /api/v1/labs/{labName}/fcling:
    post:
      consumes:
      - application/json
      description: Runs an fcling report once against the selected lab topology and
        returns its output.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: fcling command request
        in: body
        name: fcling_request
        required: true
        schema:
          $ref: '#/definitions/models.FclingCommandRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.FclingCommandResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Run fcling report
      tags:
      - Labs - Tools
  /api/v1/labs/{labName}/fcling/api/{proxyPath}:
    delete:
      consumes:
      - application/json
      description: 'Passes a request to the HTTP API of the lab''s running fcling
        engine, with the engine''s own token, and streams its answer. Only these reach
        it. GET: status, reports, reports/{name}, checks, incidents, acks, history,
        drift, configs, configs/diff, baselines, lenses, lenses/{name}, topology,
        events. POST: acks, baselines. DELETE: acks, baselines/{name}. Anything else
        is refused with 403. A lab without a running engine answers 409.'
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Path below the engine's /api, e.g. reports/bgp-peers
        in: path
        name: proxyPath
        required: true
        type: string
      produces:
      - application/json
      - text/event-stream
      responses:
        "200":
          description: The engine's answer
          schema:
            type: object
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Not part of the fabric API
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: The engine is not running
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "502":
          description: The engine is not reachable
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Proxy fcling engine API
      tags:
      - Labs - Tools
    get:
      consumes:
      - application/json
      description: 'Passes a request to the HTTP API of the lab''s running fcling
        engine, with the engine''s own token, and streams its answer. Only these reach
        it. GET: status, reports, reports/{name}, checks, incidents, acks, history,
        drift, configs, configs/diff, baselines, lenses, lenses/{name}, topology,
        events. POST: acks, baselines. DELETE: acks, baselines/{name}. Anything else
        is refused with 403. A lab without a running engine answers 409.'
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Path below the engine's /api, e.g. reports/bgp-peers
        in: path
        name: proxyPath
        required: true
        type: string
      produces:
      - application/json
      - text/event-stream
      responses:
        "200":
          description: The engine's answer
          schema:
            type: object
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Not part of the fabric API
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: The engine is not running
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "502":
          description: The engine is not reachable
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Proxy fcling engine API
      tags:
      - Labs - Tools
    post:
      consumes:
      - application/json
      description: 'Passes a request to the HTTP API of the lab''s running fcling
        engine, with the engine''s own token, and streams its answer. Only these reach
        it. GET: status, reports, reports/{name}, checks, incidents, acks, history,
        drift, configs, configs/diff, baselines, lenses, lenses/{name}, topology,
        events. POST: acks, baselines. DELETE: acks, baselines/{name}. Anything else
        is refused with 403. A lab without a running engine answers 409.'
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Path below the engine's /api, e.g. reports/bgp-peers
        in: path
        name: proxyPath
        required: true
        type: string
      produces:
      - application/json
      - text/event-stream
      responses:
        "200":
          description: The engine's answer
          schema:
            type: object
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Not part of the fabric API
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: The engine is not running
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "502":
          description: The engine is not reachable
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Proxy fcling engine API
      tags:
      - Labs - Tools
  /api/v1/labs/{labName}/fcling/engine:
    delete:
      description: Stops the lab's fcling engine. Its history is kept for the next
        start, and goes when the lab is destroyed.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.FclingEngineStatus'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stop fcling engine
      tags:
      - Labs - Tools
    get:
      description: 'Tells how the lab''s fcling engine is doing: `stopped` without
        one, `starting` until it answers, `ready` then, `failed` once its container
        has exited, with the end of its log.'
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.FclingEngineStatus'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get fcling engine status
      tags:
      - Labs - Tools
    post:
      consumes:
      - application/json
      description: 'Starts the lab''s fcling engine, which streams its SR Linux nodes
        and keeps a history of what changes. An engine that runs is left alone, unless
        the request gives it another gNMI port: then it is replaced, and keeps its
        history. A port given is also used for the lab''s reports and kept for the
        next start. The first start can take a while, since it pulls the image; poll
        the status until it says `ready`.'
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: How to start the engine
        in: body
        name: fcling_engine_request
        schema:
          $ref: '#/definitions/models.FclingEngineStartRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.FclingEngineStatus'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the configured lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Start fcling engine
      tags:
      - Labs - Tools
  /api/v1/labs/{labName}/gotty/{action}:
    post:
      consumes:
      - application/json
      description: |-
        Executes GoTTY share action (attach, detach, reattach) for a lab.

        **Notes**
        - The optional body applies to attach/reattach only and is ignored for detach. A body `port` wins over the `port` query.
        - `username` and `password` must be given together (defaults admin/admin); `shell` defaults to bash.
        - username: `^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$`; password: `^[A-Za-z0-9._@%+=,!-]{1,64}$`, not starting with `-`; shell: `^/?[A-Za-z0-9_][A-Za-z0-9_./-]{0,63}$` without `..`.
        - The response reports the effective `username` and `shell`; the password is never returned.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Action (attach|detach|reattach)
        in: path
        name: action
        required: true
        type: string
      - description: GoTTY port (attach/reattach only)
        in: query
        name: port
        type: integer
      - description: GoTTY options (attach/reattach only)
        in: body
        name: gotty_request
        schema:
          $ref: '#/definitions/models.GoTTYShareRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.ShareToolResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: GoTTY share action
      tags:
      - Labs - Sharing
  /api/v1/labs/{labName}/graph/dot:
    post:
      consumes:
      - application/json
      description: |-
        Generates a Graphviz dot graph from a lab topology like `containerlab graph --dot` and returns the file content.

        **Notes**
        - `path` defaults to the running lab topology path when the lab exists, otherwise `<labName>.clab.yml`. The lab does not need to be deployed.
        - The file is written to `<labDir>/graph/<topology name>.dot`.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative or legacy lab-relative topology path (defaults
          to running topology path or <labName>.clab.yml)
        in: query
        name: path
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GraphExportResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Generate dot graph
      tags:
      - Labs - Graph
  /api/v1/labs/{labName}/graph/drawio:
    post:
      consumes:
      - application/json
      description: Generates a draw.io diagram from a lab topology and returns the
        generated XML content.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Draw.io generation options
        in: body
        name: drawio_request
        schema:
          $ref: '#/definitions/models.DrawioGenerateRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.DrawioGenerateResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Generate draw.io graph
      tags:
      - Labs - Graph
  /api/v1/labs/{labName}/graph/mermaid:
    post:
      consumes:
      - application/json
      description: |-
        Generates a mermaid flowchart from a lab topology like `containerlab graph --mermaid` and returns the file content.

        **Notes**
        - `path` defaults to the running lab topology path when the lab exists, otherwise `<labName>.clab.yml`. The lab does not need to be deployed.
        - `direction` is one of TD, TB, BT, RL, LR (case-insensitive, default TD).
        - The file is written to `<labDir>/graph/<topology name>.mermaid`.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative or legacy lab-relative topology path (defaults
          to running topology path or <labName>.clab.yml)
        in: query
        name: path
        type: string
      - description: Mermaid options
        in: body
        name: graph_request
        schema:
          $ref: '#/definitions/models.GraphExportRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GraphExportResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Generate mermaid graph
      tags:
      - Labs - Graph
  /api/v1/labs/{labName}/host-script/describe:
    post:
      consumes:
      - application/json
      description: Says what a script is right now, as the signed-in user can read
        it, for the confirmation before it runs. Needs API_HOST_SCRIPTS=true; not
        available with lab runtime c9s.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Topology file of a lab that is not deployed, from the topology
          listing
        in: query
        name: path
        type: string
      - description: The script
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.HostScriptSourceRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.HostScriptDescription'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: The account cannot run scripts or read this one
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or script not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Turned off, or a lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Describe a script button's script
      tags:
      - Labs
  /api/v1/labs/{labName}/host-script/stream:
    post:
      consumes:
      - application/json
      description: 'Runs a script with bash on this host, from the lab''s topology
        folder, as the signed-in user, and answers with NDJSON events: output as it
        comes, then the exit. Blank lines keep the connection open. Closing the connection
        stops the script and what it started. Needs API_HOST_SCRIPTS=true; not available
        with lab runtime c9s.'
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Topology file of a lab that is not deployed, from the topology
          listing
        in: query
        name: path
        type: string
      - description: The script
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.HostScriptRunRequest'
      produces:
      - application/x-ndjson
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.HostScriptEvent'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: The account cannot run scripts or read this one
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or script not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: The script is not the one that was confirmed
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "429":
          description: Too many running scripts
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Turned off, or a lab runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Run a script button's script
      tags:
      - Labs
  /api/v1/labs/{labName}/interfaces:
    get:
      description: |-
        Returns interface details for nodes in a lab.

        With the lab runtime c9s the interfaces of the running nodes come from containerlab's c9s runtime, as the signed-in user: the lab link interfaces (with their aliases), eth0 and lo, with MAC, index, MTU, type and state; nodes are named <lab>-<node>.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - description: Filter interfaces for a specific node
        in: query
        name: node
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Interface details
          schema:
            items:
              $ref: '#/definitions/models.NodeInterfaceInfo'
            type: array
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List lab interfaces
      tags:
      - Labs
  /api/v1/labs/{labName}/links:
    get:
      description: |-
        Returns the links of a running lab as they currently exist in the kernel, including links created or removed after deployment.

        **Notes**
        - Each veth pair is listed once. Endpoint A is always in a lab node; endpoint B is in a lab node, the host namespace (e.g. a management or lab bridge port) or an external namespace.
        - macvlan interfaces are listed with their parent interface as endpoint B.
        - To follow changes, re-query when /api/v1/events reports interface create or delete events for the lab.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - description: Only return links with an endpoint on this node
        in: query
        name: node
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Lab links
          schema:
            items:
              $ref: '#/definitions/models.LabLink'
            type: array
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List lab links
      tags:
      - Labs
  /api/v1/labs/{labName}/nodes/{nodeName}/browser-ports:
    get:
      description: Returns exposed host ports for a node suitable for opening in a
        browser.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Node Name
        in: path
        name: nodeName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.NodeBrowserPortsResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get node browser ports
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/nodes/{nodeName}/logs:
    get:
      description: |-
        Returns logs for a lab node.

        **Notes**
        - When `follow=true`, the response streams as NDJSON (one JSON object per line) until the client disconnects or after 12 hours.
        - Streamed lines carry `stream` (`stdout` or `stderr`). A blank line is sent every 25 seconds while the node is quiet, so clients can tell a quiet node from a lost connection.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - description: Full name of the container (node)
        in: path
        name: nodeName
        required: true
        type: string
      - default: all
        description: Number of lines to show from the end of logs (default all). Use
          an integer or 'all'.
        in: query
        name: tail
        type: string
      - description: 'Follow log output (stream logs as NDJSON). Note: In Swagger
          UI, streaming may not display correctly.'
        in: query
        name: follow
        type: boolean
      produces:
      - application/json
      - application/x-ndjson
      responses:
        "200":
          description: Container logs (follow=false). When follow=true, response is
            NDJSON stream of LogLine objects.
          schema:
            $ref: '#/definitions/models.LogsResponse'
        "400":
          description: Invalid input (lab name, node filter, etc.)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (not owner of the lab)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or node not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get node logs
      tags:
      - Logs
  /api/v1/labs/{labName}/nodes/{nodeName}/pause:
    post:
      description: Pauses a running node in a lab.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Node Name
        in: path
        name: nodeName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Pause node
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/nodes/{nodeName}/ports/{port}/proxy/{proxyPath}:
    get:
      description: |-
        Proxies an HTTP request (including WebSocket upgrades) to a TCP port of a lab node, through a Kubernetes port-forward opened as the caller.

        **Notes**
        - Only available with a lab runtime (`runtime` `c9s` on `/health`); other runtimes answer 501 and publish host ports instead.
        - `browser-ports` lists the ports with their `proxyPath`.
        - The request is sent to the node without the `Authorization` header.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Node name
        in: path
        name: nodeName
        required: true
        type: string
      - description: Node TCP port
        in: path
        name: port
        required: true
        type: integer
      - description: Path on the node
        in: path
        name: proxyPath
        required: true
        type: string
      responses:
        "200":
          description: Response of the node
          schema:
            type: string
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "501":
          description: Not supported by the runtime
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "502":
          description: Node port not reachable
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Proxy HTTP to a node port
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/nodes/{nodeName}/restart:
    post:
      description: Restarts a node in a lab while preserving containerlab dataplane
        links.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Node Name
        in: path
        name: nodeName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Restart node
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/nodes/{nodeName}/ssh:
    post:
      consumes:
      - application/json
      description: |-
        Creates temporary SSH access to a lab node and returns connection details for an external SSH client.
        This endpoint does not create a browser terminal session. For browser terminals, use `/api/v1/labs/{labName}/nodes/{nodeName}/terminal-sessions` with `protocol=ssh`.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Full container name of the node (e.g., clab-my-lab-srl1)
        in: path
        name: nodeName
        required: true
        type: string
      - description: SSH access parameters
        in: body
        name: sshRequest
        schema:
          $ref: '#/definitions/models.SSHAccessRequest'
      produces:
      - application/json
      responses:
        "200":
          description: SSH connection details
          schema:
            $ref: '#/definitions/models.SSHAccessResponse'
        "400":
          description: Invalid request parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (not owner of the lab)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or node not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Request temporary SSH access details
      tags:
      - SSH Access
  /api/v1/labs/{labName}/nodes/{nodeName}/start:
    post:
      description: Starts a stopped node in a lab.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Node Name
        in: path
        name: nodeName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Start node
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/nodes/{nodeName}/stop:
    post:
      description: Stops a running node in a lab.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Node Name
        in: path
        name: nodeName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stop node
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/nodes/{nodeName}/terminal-sessions:
    post:
      consumes:
      - application/json
      description: |-
        Creates a constrained interactive terminal session for an owned lab node using one of the supported protocols: `ssh`, `shell`, or `telnet`.

        **Protocol behavior**
        - `ssh`: launches the server-side `ssh` client in a PTY directly to the node management IP and streams that terminal over WebSocket.
        - `shell`: launches a PTY-backed `docker|podman exec -it <container> <server-selected-command>` session.
        - `telnet`: launches a PTY-backed `docker|podman exec -it <container> telnet 127.0.0.1 <port>` session.

        **Security notes**
        - The backend chooses the launch command for every protocol. Clients choose only the protocol and terminal size.
        - Access is limited to owned nodes unless the caller is a configured superuser.

        **Resuming**
        - Set `resumable` to keep the session running when its stream disconnects, so the client can attach again and see the output it missed. The server must list `terminal-resume` in the `features` of `/health`.
        - Without `resumable`, the session ends as soon as its stream disconnects.

        **Relationship to `/api/v1/labs/{labName}/nodes/{nodeName}/ssh`**
        - This endpoint creates the interactive browser terminal session.
        - The separate `/ssh` endpoint returns temporary SSH access details for an external SSH client and is not required for browser terminals.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Full container name of the node (e.g., clab-my-lab-srl1)
        in: path
        name: nodeName
        required: true
        type: string
      - description: Terminal session creation parameters
        in: body
        name: terminal_request
        required: true
        schema:
          $ref: '#/definitions/models.TerminalSessionRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Created terminal session
          schema:
            $ref: '#/definitions/models.TerminalSessionInfo'
        "400":
          description: Invalid request parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or node not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "429":
          description: Too many active terminal sessions
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create browser terminal session
      tags:
      - Terminal Sessions
  /api/v1/labs/{labName}/nodes/{nodeName}/unpause:
    post:
      description: Unpauses a paused node in a lab.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Node Name
        in: path
        name: nodeName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Unpause node
      tags:
      - Labs - Nodes
  /api/v1/labs/{labName}/restart:
    post:
      description: |-
        Restarts all nodes in a deployed lab while preserving containerlab dataplane links.

        **Notes**
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
        - `nodeFilter` limits the action to the listed topology nodes; unknown nodes return 404.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: 'Comma-separated topology node names to act on (default: all
          nodes)'
        in: query
        name: nodeFilter
        type: string
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Restart lab nodes
      tags:
      - Labs
  /api/v1/labs/{labName}/save:
    post:
      description: |-
        Saves the running configuration for nodes in a lab.

        **Notes**
        - `copy` works like `containerlab save --copy`: each saved config is also copied to `<copy>/<lab dir>/<node>/<file>-YYMMDD_HHMMSS.<ext>` with a `<file>` symlink to the newest copy. The path is relative to the topology directory (or absolute) and must stay inside the user's workspace, or the shared root for shared labs.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - description: Save config only for specific nodes
        in: query
        name: nodeFilter
        type: string
      - description: Also copy saved configs into this directory (relative to the
          topology directory or absolute)
        in: query
        name: copy
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Configuration saved
          schema:
            $ref: '#/definitions/models.SaveConfigResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Save lab configuration
      tags:
      - Labs
  /api/v1/labs/{labName}/snapshots:
    post:
      consumes:
      - application/json
      description: |-
        Saves VM snapshots of vrnetlab-based nodes, like `containerlab tools snapshot save`. Each snapshot is written to `<outputDir>/<node>.tar`; non-vrnetlab nodes are skipped.

        **Notes**
        - `outputDir` is relative to the lab's topology directory (or absolute) and must stay inside the user's workspace, or the shared root for shared labs. Defaults to `snapshots`.
        - `timeout` is the per-node wait as a Go duration (default `5m`, maximum `30m`).
        - Nodes run concurrently. The response is 200 even when nodes fail; read each result's `status` (`success`, `failed`, `skipped`).
        - The lab is locked for other lifecycle operations while snapshots run.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - description: Snapshot options
        in: body
        name: snapshot_request
        schema:
          $ref: '#/definitions/models.SnapshotSaveRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Per-node snapshot results
          schema:
            $ref: '#/definitions/models.SnapshotSaveResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or node not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Lab busy with another operation
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Save VM snapshots
      tags:
      - Labs
  /api/v1/labs/{labName}/sshx/{action}:
    post:
      consumes:
      - application/json
      description: |-
        Executes SSHX share action (attach, detach, reattach) for a lab.

        **Notes**
        - The optional body applies to attach/reattach only and is ignored for detach.
        - `enableReaders=true` also creates a read-only access link, returned as `readOnlyLink`.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: Action (attach|detach|reattach)
        in: path
        name: action
        required: true
        type: string
      - description: SSHX options (attach/reattach only)
        in: body
        name: sshx_request
        schema:
          $ref: '#/definitions/models.SSHXShareRequest'
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.ShareToolResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: SSHX share action
      tags:
      - Labs - Sharing
  /api/v1/labs/{labName}/start:
    post:
      description: |-
        Starts all nodes in a deployed lab while preserving containerlab dataplane links.

        **Notes**
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
        - `nodeFilter` limits the action to the listed topology nodes; unknown nodes return 404.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: 'Comma-separated topology node names to act on (default: all
          nodes)'
        in: query
        name: nodeFilter
        type: string
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Start lab nodes
      tags:
      - Labs
  /api/v1/labs/{labName}/stats:
    get:
      description: |-
        Streams the CPU, memory and process count of every running node of a lab as NDJSON, one `stats` object per interval.

        **Notes**
        - `cpuPercent` is the usage since the previous sample, where 100 is one busy CPU; the first sample of a node has none.
        - Memory usage leaves out page cache that can be reclaimed, like `docker stats`.
        - Nodes that start or stop while streaming appear or disappear within 10 seconds.
        - The stream ends when the client disconnects or after 12 hours.
      parameters:
      - description: Name of the lab
        in: path
        name: labName
        required: true
        type: string
      - default: 2s
        description: Time between samples, from 1s to 20s.
        in: query
        name: interval
        type: string
      produces:
      - application/x-ndjson
      responses:
        "200":
          description: NDJSON stream of samples
          schema:
            $ref: '#/definitions/models.LabStatsSample'
        "400":
          description: Invalid lab name or interval
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stream lab node resource usage
      tags:
      - Labs
  /api/v1/labs/{labName}/stop:
    post:
      description: |-
        Stops all nodes in a deployed lab while preserving containerlab dataplane links.

        **Notes**
        - `stream=true` returns `application/x-ndjson` lifecycle events.
        - `includeLogs=true` includes captured lifecycle logs in the JSON response.
        - `nodeFilter` limits the action to the listed topology nodes; unknown nodes return 404.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      - description: 'Comma-separated topology node names to act on (default: all
          nodes)'
        in: query
        name: nodeFilter
        type: string
      - description: Stream lifecycle output as NDJSON events
        in: query
        name: stream
        type: boolean
      - description: Include captured lifecycle logs in the JSON response
        in: query
        name: includeLogs
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stop lab nodes
      tags:
      - Labs
  /api/v1/labs/{labName}/tailscale:
    get:
      description: |-
        Reports the Tailscale devices containerlab runs for a lab: the SSO proxy (`mgmt.tailscale.auth-mode: sso`), the auth-key sidecars of nodes, and nodes of the `tailscale` kind.

        These are internal helper containers that are not listed as lab nodes. While the SSO proxy waits for authentication, `authUrl` holds the login URL to open; `forwards` lists the tailnet ports it forwards to nodes.
      parameters:
      - description: Lab Name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: OK
          schema:
            $ref: '#/definitions/models.TailscaleStatusResponse'
        "400":
          description: Bad Request
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Not Found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal Server Error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get lab Tailscale status
      tags:
      - Labs
  /api/v1/labs/{labName}/topology/annotations:
    get:
      description: Returns annotations for the specified lab. For deployed labs, the
        running annotations path is preferred and local files are used as fallback.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - text/plain
      responses:
        "200":
          description: Annotations content
          schema:
            type: string
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: File not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get lab annotations
      tags:
      - Labs
    put:
      consumes:
      - text/plain
      description: Updates annotations for the specified lab. For deployed labs, writes
        to the running annotations path when present and otherwise writes to local
        files.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Annotations content
        in: body
        name: content
        required: true
        schema:
          type: string
      produces:
      - application/json
      responses:
        "200":
          description: Write success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Update lab annotations
      tags:
      - Labs
  /api/v1/labs/{labName}/topology/events:
    get:
      description: |-
        Streams topology YAML/annotations change events for a single lab topology document pair as NDJSON.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative or legacy lab-relative topology YAML or annotations
          path
        in: query
        name: path
        required: true
        type: string
      produces:
      - application/x-ndjson
      responses:
        "200":
          description: Topology document event stream
          schema:
            $ref: '#/definitions/models.TopologyDocEventResponse'
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stream topology document events
      tags:
      - Labs
  /api/v1/labs/{labName}/topology/file:
    delete:
      description: |-
        Deletes a file inside the specified lab directory using a scoped relative path.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative path from the topology listing, or legacy
          lab-relative path
        in: query
        name: path
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Delete success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete lab topology file
      tags:
      - Labs
    get:
      description: |-
        Reads a file from within the specified lab directory using a scoped relative path.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative path from the topology listing, or legacy
          lab-relative path
        in: query
        name: path
        required: true
        type: string
      produces:
      - text/plain
      responses:
        "200":
          description: File content
          schema:
            type: string
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: File not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Read lab topology file
      tags:
      - Labs
    head:
      description: |-
        Checks whether a file exists inside the specified lab directory.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative path from the topology listing, or legacy
          lab-relative path
        in: query
        name: path
        required: true
        type: string
      responses:
        "200":
          description: File exists
        "400":
          description: Invalid path
        "401":
          description: Unauthorized
        "404":
          description: File not found
        "500":
          description: Internal server error
      security:
      - BearerAuth: []
      summary: Check lab topology file existence
      tags:
      - Labs
    put:
      consumes:
      - text/plain
      description: |-
        Writes a file inside the specified lab directory using a scoped relative path.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative path from the topology listing, or legacy
          lab-relative path
        in: query
        name: path
        required: true
        type: string
      - description: File content
        in: body
        name: content
        required: true
        schema:
          type: string
      produces:
      - application/json
      responses:
        "200":
          description: Write success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Write lab topology file
      tags:
      - Labs
  /api/v1/labs/{labName}/topology/file/rename:
    post:
      consumes:
      - application/json
      description: |-
        Renames or moves a file inside the specified lab directory using scoped relative paths.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Old and new relative file paths
        in: body
        name: rename_request
        required: true
        schema:
          $ref: '#/definitions/models.TopologyFileRenameRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Rename success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Rename lab topology file
      tags:
      - Labs
  /api/v1/labs/{labName}/topology/rendered:
    get:
      description: |-
        Renders a topology file the way containerlab does before deploying it: Go template execution with variables from `<topology name without extension>_vars.{yaml,yml,json}` or `varsPath`, `clab_templates/*.gotmpl` subtemplates, and `${VAR:=default}` environment expansion. Nothing is deployed and no lab state changes.

        **Notes**
        - `path` resolves like the topology file endpoints. `varsPath` is relative to the topology file's directory (like `containerlab --vars` run from there) and must stay inside the topology's workspace.
        - `varsFiles` lists the variable files used, relative to the topology file's directory.
        - A topology that renders but is rejected by containerlab returns 200 with the rendered content and `error` set.
        - Template parse or execution errors return 422.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative path from the topology listing, or legacy
          lab-relative path
        in: query
        name: path
        required: true
        type: string
      - description: Template variables file relative to the topology file's directory
          (like --vars); defaults to containerlab's vars file discovery
        in: query
        name: varsPath
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Rendered topology
          schema:
            $ref: '#/definitions/models.RenderedTopologyResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Topology or vars file not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "422":
          description: Topology template could not be rendered
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Render lab topology file
      tags:
      - Labs
  /api/v1/labs/{labName}/topology/yaml:
    get:
      description: Returns the topology YAML for the specified lab. For deployed labs,
        the running topology source path is preferred and local files are used as
        fallback.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - text/plain
      responses:
        "200":
          description: Topology YAML content
          schema:
            type: string
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: File not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get lab topology YAML
      tags:
      - Labs
    put:
      consumes:
      - text/plain
      description: Updates the topology YAML for the specified lab. For deployed labs,
        writes to the running topology source when present and otherwise writes to
        local files.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Topology YAML content
        in: body
        name: content
        required: true
        schema:
          type: string
      produces:
      - application/json
      responses:
        "200":
          description: Write success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Update lab topology YAML
      tags:
      - Labs
  /api/v1/labs/{labName}/ui/icons:
    get:
      description: Returns the custom TopoViewer icons available for a lab, merging
        lab-local .clab-icons with the global ~/.clab/icons library. Lab-local icons
        take precedence.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Merged lab icon list
          schema:
            $ref: '#/definitions/models.IconListResponse'
        "400":
          description: Invalid lab name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List lab custom icons
      tags:
      - UI
  /api/v1/labs/{labName}/ui/icons/reconcile:
    post:
      consumes:
      - application/json
      description: Copies used custom icons from the global ~/.clab/icons library
        into the lab-local .clab-icons directory and removes unused lab-local custom
        icons.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Used custom icon names
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.IconReconcileRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Reconcile success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Reconcile lab custom icons
      tags:
      - UI
  /api/v1/labs/{labName}/validate:
    post:
      description: |-
        Parses and validates an on-disk topology like `containerlab validate`, without deploying it or changing any lab state.

        **Notes**
        - `path` defaults to the running lab topology path when the lab exists, otherwise `<labName>.clab.yml`.
        - A topology containerlab rejects returns 200 with `valid=false` and the validation error.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Lab name
        in: path
        name: labName
        required: true
        type: string
      - description: Workspace-relative or legacy lab-relative topology path (defaults
          to running topology path or <labName>.clab.yml)
        in: query
        name: path
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Validation result
          schema:
            $ref: '#/definitions/models.ValidateTopologyResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Lab or topology file not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Validate on-disk topology for lab
      tags:
      - Labs
  /api/v1/labs/archive:
    post:
      consumes:
      - multipart/form-data
      description: Deploys a containerlab topology provided as a .zip or .tar.gz archive.
      parameters:
      - description: Lab archive (.zip or .tar.gz)
        in: formData
        name: labArchive
        required: true
        type: file
      - description: Name for the lab
        in: query
        name: labName
        required: true
        type: string
      - description: Allow overwriting an existing lab
        in: query
        name: reconfigure
        type: boolean
      - description: Limit concurrent workers
        in: query
        name: maxWorkers
        type: integer
      - description: Custom Go template file for topology data export
        in: query
        name: exportTemplate
        type: string
      - description: Comma-separated list of node names to deploy
        in: query
        name: nodeFilter
        type: string
      - description: Skip post-deploy actions
        in: query
        name: skipPostDeploy
        type: boolean
      - description: Skip setting extended ACLs on lab directory
        in: query
        name: skipLabdirAcl
        type: boolean
      - description: Override the management network name (like --network); not allowed
          with multiple management networks
        in: query
        name: network
        type: string
      - description: Override the management network IPv4 subnet (like --ipv4-subnet)
        in: query
        name: ipv4Subnet
        type: string
      - description: Override the management network IPv6 subnet (like --ipv6-subnet)
        in: query
        name: ipv6Subnet
        type: string
      - description: Restore nodes from <node>.tar snapshots in this directory (like
          --restore-all); relative to the topology directory or absolute, inside the
          workspace
        in: query
        name: restoreAll
        type: string
      - collectionFormat: multi
        description: Restore one node from a snapshot file as node=path (like --restore);
          repeatable, overrides restoreAll
        in: query
        items:
          type: string
        name: restore
        type: array
      - description: containerlab timeout like --timeout, a Go duration such as 10m
          or 1h; at most 2h. Defaults to 10m on c9s and 5m with Docker and Podman
        in: query
        name: timeout
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Deployed lab details
          schema:
            $ref: '#/definitions/models.ClabInspectOutput'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Conflict
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Deploy lab from archive
      tags:
      - Labs
  /api/v1/labs/topology/files:
    get:
      description: |-
        Recursively discovers editable *.clab.yml, *.clab.yaml and *.clab.gotmpl files in the authenticated user's lab workspace. YAML and annotation paths are relative to the workspace root. Hidden directories, dependency caches, containerlab runtime directories, and symbolic links are excluded.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      produces:
      - application/json
      responses:
        "200":
          description: Topology entries
          schema:
            items:
              $ref: '#/definitions/models.TopologyEntry'
            type: array
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List editable lab topology files
      tags:
      - Labs
  /api/v1/labs/topology/import-from-url:
    post:
      consumes:
      - application/json
      description: Clones a supported Git repository URL and registers it as an undeployed
        lab.
      parameters:
      - description: Topology source URL
        in: body
        name: import_request
        required: true
        schema:
          $ref: '#/definitions/models.ImportTopologyFromURLRequest'
      - description: Override imported lab name
        in: query
        name: labNameOverride
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Import result
          schema:
            $ref: '#/definitions/models.ImportTopologyFromURLResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Lab already exists
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Import topology repository as undeployed lab
      tags:
      - Labs
  /api/v1/labs/workspace/directory:
    post:
      consumes:
      - application/json
      description: |-
        Creates a directory inside the authenticated user's editable lab workspace root.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Directory path
        in: body
        name: directory_request
        required: true
        schema:
          $ref: '#/definitions/models.WorkspaceDirectoryRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Directory create success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create lab workspace directory
      tags:
      - Labs
  /api/v1/labs/workspace/events:
    get:
      description: |-
        Streams create/change/delete/rename events inside the authenticated user's editable lab workspace root as NDJSON.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      produces:
      - application/x-ndjson
      responses:
        "200":
          description: Workspace file event stream
          schema:
            $ref: '#/definitions/models.WorkspaceFileEventResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stream lab workspace file events
      tags:
      - Labs
  /api/v1/labs/workspace/file:
    delete:
      description: |-
        Deletes a file or directory inside the authenticated user's editable lab workspace root. Directories with children require recursive=true.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Relative file path inside the workspace root
        in: query
        name: path
        required: true
        type: string
      - description: Delete non-empty directories recursively
        in: query
        name: recursive
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: Delete success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete lab workspace file
      tags:
      - Labs
    get:
      description: |-
        Reads a text or binary file from the authenticated user's editable lab workspace root.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Relative file path inside the workspace root
        in: query
        name: path
        required: true
        type: string
      produces:
      - text/plain
      responses:
        "200":
          description: File content
          schema:
            type: string
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: File not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Read lab workspace file
      tags:
      - Labs
    put:
      consumes:
      - text/plain
      description: |-
        Writes a file inside the authenticated user's editable lab workspace root.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Relative file path inside the workspace root
        in: query
        name: path
        required: true
        type: string
      - description: File content
        in: body
        name: content
        required: true
        schema:
          type: string
      produces:
      - application/json
      responses:
        "200":
          description: Write success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Write lab workspace file
      tags:
      - Labs
  /api/v1/labs/workspace/file/rename:
    post:
      consumes:
      - application/json
      description: |-
        Renames or moves a file inside the authenticated user's editable lab workspace root.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Old and new relative file paths
        in: body
        name: rename_request
        required: true
        schema:
          $ref: '#/definitions/models.WorkspaceFileRenameRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Rename success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Rename lab workspace file
      tags:
      - Labs
  /api/v1/labs/workspace/tree:
    get:
      description: |-
        Lists files and folders inside the authenticated user's editable lab workspace root.
        Shared workspace paths start with @shared/ when CLAB_SHARED_LABS_ROOT is configured; all authenticated API users can access them.
      parameters:
      - description: Relative directory path inside the workspace root
        in: query
        name: path
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Workspace entries
          schema:
            items:
              $ref: '#/definitions/models.WorkspaceFileEntry'
            type: array
        "400":
          description: Invalid path
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Directory not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List lab workspace files
      tags:
      - Labs
  /api/v1/ssh/sessions:
    get:
      description: |-
        Returns active SSH sessions.

        **Notes**
        - Regular users see only their sessions.
        - Superusers can include all sessions via the `all` query parameter.
      parameters:
      - description: 'If true and user is superuser, shows sessions for all users
          (default: false)'
        in: query
        name: all
        type: boolean
      produces:
      - application/json
      responses:
        "200":
          description: List of active SSH sessions
          schema:
            items:
              $ref: '#/definitions/models.SSHSessionInfo'
            type: array
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (non-superuser attempting to list all sessions)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List SSH sessions
      tags:
      - SSH Access
  /api/v1/ssh/sessions/{port}:
    delete:
      description: Terminates a specific SSH session by port.
      parameters:
      - description: SSH session port to terminate
        in: path
        name: port
        required: true
        type: integer
      produces:
      - application/json
      responses:
        "200":
          description: Session terminated successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid port parameter
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (not owner of the session)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Terminate SSH session
      tags:
      - SSH Access
  /api/v1/terminal-sessions/{sessionId}:
    delete:
      description: Terminates a terminal session owned by the caller (or any session
        for a superuser).
      parameters:
      - description: Terminal session ID
        in: path
        name: sessionId
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Terminal session terminated
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Terminate terminal session
      tags:
      - Terminal Sessions
    get:
      description: Returns metadata and lifecycle state for a terminal session.
      parameters:
      - description: Terminal session ID
        in: path
        name: sessionId
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Terminal session metadata
          schema:
            $ref: '#/definitions/models.TerminalSessionInfo'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get terminal session
      tags:
      - Terminal Sessions
  /api/v1/terminal-sessions/{sessionId}/stream:
    get:
      description: |-
        Upgrades the request to a WebSocket connection for terminal input, output, resize, and close events.

        **Protocol notes**
        - Connect with a WebSocket client to this endpoint after creating a terminal session.
        - Client messages are JSON objects with `type` set to `input`, `resize`, or `close`.
        - Server messages are JSON objects with `type` set to `ready`, `output`, or `exit`.

        **Reconnecting**
        - A session created with `resumable` keeps running when the connection drops (`ready.resumable` is true). Connect again to continue: the first `output` message replays the session's recent output (`ready.replay` is true then).
        - Any other session ends when its connection closes.
        - Only one client is attached at a time. A new connection takes the session over, and the previous one is closed with code 4001.
        - Send `close` to end the session. A resumable session without a client ends after the server's terminal idle timeout (default 30 minutes).
      parameters:
      - description: Terminal session ID
        in: path
        name: sessionId
        required: true
        type: string
      produces:
      - application/json
      responses:
        "101":
          description: Switching Protocols to WebSocket
          schema:
            type: string
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Session not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "410":
          description: Session already exited
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Stream terminal session
      tags:
      - Terminal Sessions
  /api/v1/tools/certs/ca:
    post:
      consumes:
      - application/json
      description: |-
        Creates a CA certificate and private key. Requires superuser privileges.

        **Notes**
        - Files are stored in the user's `~/.clab/certs/<ca_name>/` directory on the server.
      parameters:
      - description: CA Generation Parameters
        in: body
        name: ca_request
        required: true
        schema:
          $ref: '#/definitions/models.CACreateRequest'
      produces:
      - application/json
      responses:
        "200":
          description: CA created successfully
          schema:
            $ref: '#/definitions/models.CertResponse'
        "400":
          description: Invalid input parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error (filesystem, clab execution)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create certificate authority (CA)
      tags:
      - Tools - Certificates
  /api/v1/tools/certs/sign:
    post:
      consumes:
      - application/json
      description: |-
        Creates a certificate/key and signs it with a previously generated CA. Requires superuser privileges.

        **Notes**
        - Files are stored in the user's `~/.clab/certs/<ca_name>/` directory.
      parameters:
      - description: Certificate Signing Parameters
        in: body
        name: sign_request
        required: true
        schema:
          $ref: '#/definitions/models.CertSignRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Certificate signed successfully
          schema:
            $ref: '#/definitions/models.CertResponse'
        "400":
          description: Invalid input parameters (name, hosts, CA name, etc.)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Specified CA not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error (filesystem, clab execution)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Sign certificate
      tags:
      - Tools - Certificates
  /api/v1/tools/disable-tx-offload:
    post:
      consumes:
      - application/json
      description: Disables TX checksum offload on the eth0 interface of a container.
        Requires superuser privileges.
      parameters:
      - description: Container Name
        in: body
        name: tx_request
        required: true
        schema:
          $ref: '#/definitions/models.DisableTxOffloadRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Offload disabled successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Container not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error or clab execution failed
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Disable TX checksum offload
      tags:
      - Tools
  /api/v1/tools/edgeshark/install:
    post:
      description: Installs and starts EdgeShark services on the host runtime using
        compose.
      produces:
      - application/json
      responses:
        "200":
          description: EdgeShark installed
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Superuser privileges required
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Install EdgeShark
      tags:
      - Capture
  /api/v1/tools/edgeshark/status:
    get:
      description: Returns whether EdgeShark is reachable and its runtime details.
      produces:
      - application/json
      responses:
        "200":
          description: EdgeShark status
          schema:
            $ref: '#/definitions/models.EdgeSharkStatusResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get EdgeShark status
      tags:
      - Capture
  /api/v1/tools/edgeshark/uninstall:
    post:
      description: Stops and removes EdgeShark services managed by compose.
      produces:
      - application/json
      responses:
        "200":
          description: EdgeShark uninstalled
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Superuser privileges required
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Uninstall EdgeShark
      tags:
      - Capture
  /api/v1/tools/netem/reset:
    post:
      consumes:
      - application/json
      description: |-
        Resets (removes) netem impairments from a specific interface of a containerlab node owned by the authenticated user. Superusers may operate on any node.

        Target the node either by `containerName`, or by `labName` and topology `nodeName`.
      parameters:
      - description: Netem Reset Parameters
        in: body
        name: netem_reset_request
        required: true
        schema:
          $ref: '#/definitions/models.NetemResetRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Impairments reset successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid input parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Node or interface not found, or node not owned by user
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Reset link impairments (netem)
      tags:
      - Tools - Netem
  /api/v1/tools/netem/set:
    post:
      consumes:
      - application/json
      description: |-
        Sets netem impairments (delay, jitter, loss, rate limiting, corruption) on a specific interface of a containerlab node owned by the authenticated user. Superusers may operate on any node.

        Target the node either by `containerName`, or by `labName` and topology `nodeName`. Interfaces of stitched links (e.g. vxlan-stitch) are impaired on their host-side interface.
      parameters:
      - description: Netem Set Parameters
        in: body
        name: netem_set_request
        required: true
        schema:
          $ref: '#/definitions/models.NetemSetRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Impairments set successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid input parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Node or interface not found, or node not owned by user
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Set link impairments (netem)
      tags:
      - Tools - Netem
  /api/v1/tools/netem/show:
    get:
      description: |-
        Lists netem impairments for a containerlab node owned by the authenticated user. Superusers may inspect any node.

        Target the node either by `containerName`, or by `labName` and topology `nodeName`. With `labName` alone, impairments of every deployed node of the lab are returned, keyed by node name.
      parameters:
      - description: Container name
        in: query
        name: containerName
        type: string
      - description: Lab name (with nodeName, or alone to show all nodes)
        in: query
        name: labName
        type: string
      - description: Topology node name (requires labName)
        in: query
        name: nodeName
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Netem impairments
          schema:
            $ref: '#/definitions/models.NetemShowResponse'
        "400":
          description: Invalid input parameters
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Node not found, or node not owned by user
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Show link impairments (netem)
      tags:
      - Tools - Netem
  /api/v1/tools/veth:
    post:
      consumes:
      - application/json
      description: Creates a virtual Ethernet (vEth) pair between two endpoints (container,
        host, bridge, or ovs-bridge). Requires superuser privileges.
      parameters:
      - description: vEth Creation Parameters
        in: body
        name: veth_request
        required: true
        schema:
          $ref: '#/definitions/models.VethCreateRequest'
      produces:
      - application/json
      responses:
        "200":
          description: vEth pair created successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid input parameters (endpoints, MTU)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error (clab execution failed)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create vEth pair
      tags:
      - Tools - vEth
  /api/v1/tools/vxlan:
    delete:
      description: 'Deletes VxLAN tunnel interfaces that match the provided prefix
        (default: `vx-`). Requires superuser privileges.'
      parameters:
      - default: vx-
        description: Prefix of VxLAN interfaces to delete
        in: query
        name: prefix
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: VxLAN tunnels deleted successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid prefix format
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error (clab execution failed)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete VxLAN tunnels by prefix
      tags:
      - Tools - VxLAN
    post:
      consumes:
      - application/json
      description: Creates a VxLAN tunnel interface and sets up tc rules for traffic
        redirection. Requires superuser privileges.
      parameters:
      - description: VxLAN Creation Parameters
        in: body
        name: vxlan_request
        required: true
        schema:
          $ref: '#/definitions/models.VxlanCreateRequest'
      produces:
      - application/json
      responses:
        "200":
          description: VxLAN tunnel created successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid input parameters (remote, link, id, port, etc.)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized (JWT)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error (clab execution failed)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create VxLAN tunnel
      tags:
      - Tools - VxLAN
  /api/v1/ui/custom-nodes:
    get:
      description: Returns the authenticated user's persisted TopoViewer custom node
        templates. If none have been saved yet, seeded defaults matching VS Code are
        returned.
      produces:
      - application/json
      responses:
        "200":
          description: Custom node templates
          schema:
            $ref: '#/definitions/models.CustomNodesResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List custom node templates
      tags:
      - UI
    post:
      consumes:
      - application/json
      description: Creates or updates a single TopoViewer custom node template for
        the authenticated user.
      parameters:
      - description: Custom node template payload
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.CustomNodeTemplate'
      produces:
      - application/json
      responses:
        "200":
          description: Updated custom node templates
          schema:
            $ref: '#/definitions/models.CustomNodesResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Save custom node template
      tags:
      - UI
    put:
      consumes:
      - application/json
      description: Replaces the authenticated user's full TopoViewer custom node template
        collection.
      parameters:
      - description: Replacement custom node template collection
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.CustomNodesReplaceRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Updated custom node templates
          schema:
            $ref: '#/definitions/models.CustomNodesResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Replace custom node templates
      tags:
      - UI
  /api/v1/ui/custom-nodes/{name}:
    delete:
      description: Deletes a single TopoViewer custom node template for the authenticated
        user.
      parameters:
      - description: Custom node name
        in: path
        name: name
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Updated custom node templates
          schema:
            $ref: '#/definitions/models.CustomNodesResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete custom node template
      tags:
      - UI
  /api/v1/ui/custom-nodes/default:
    post:
      consumes:
      - application/json
      description: Sets the default TopoViewer custom node template for the authenticated
        user.
      parameters:
      - description: Default custom node selection
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.CustomNodeDefaultRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Updated custom node templates
          schema:
            $ref: '#/definitions/models.CustomNodesResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Custom node not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Set default custom node template
      tags:
      - UI
  /api/v1/ui/icons:
    get:
      description: Returns the authenticated user's global custom TopoViewer icon
        library from ~/.clab/icons.
      produces:
      - application/json
      responses:
        "200":
          description: Global custom icons
          schema:
            $ref: '#/definitions/models.IconListResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List global custom icons
      tags:
      - UI
    post:
      consumes:
      - application/json
      description: Uploads a new global custom TopoViewer icon into ~/.clab/icons
        for the authenticated user.
      parameters:
      - description: Custom icon upload payload
        in: body
        name: request
        required: true
        schema:
          $ref: '#/definitions/models.IconUploadRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Upload success
          schema:
            $ref: '#/definitions/models.IconUploadResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: Rejected due to built-in icon name conflict
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Upload global custom icon
      tags:
      - UI
  /api/v1/ui/icons/{iconName}:
    delete:
      description: Deletes a global custom TopoViewer icon from ~/.clab/icons for
        the authenticated user.
      parameters:
      - description: Custom icon name
        in: path
        name: iconName
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: Delete success
          schema:
            $ref: '#/definitions/models.SimpleSuccessResponse'
        "400":
          description: Invalid icon name
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: Icon not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete global custom icon
      tags:
      - UI
  /api/v1/users:
    get:
      description: Returns a list of system users. Requires superuser privileges.
      produces:
      - application/json
      responses:
        "200":
          description: List of user details
          schema:
            items:
              $ref: '#/definitions/models.UserDetails'
            type: array
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: List users
      tags:
      - Users
    post:
      consumes:
      - application/json
      description: Creates a new system user. Requires superuser privileges.
      parameters:
      - description: User creation details
        in: body
        name: user
        required: true
        schema:
          $ref: '#/definitions/models.UserCreateRequest'
      produces:
      - application/json
      responses:
        "201":
          description: User created successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid request body
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "409":
          description: User already exists
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Create user
      tags:
      - Users
  /api/v1/users/{username}:
    delete:
      description: Deletes a user from the system. Requires superuser privileges.
      parameters:
      - description: Username to delete
        in: path
        name: username
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: User deleted successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (User is not a superuser)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: User not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Delete user
      tags:
      - Users
    get:
      description: Returns details for a specific user. Requires superuser privileges
        or the user's own account.
      parameters:
      - description: Username to get details for
        in: path
        name: username
        required: true
        type: string
      produces:
      - application/json
      responses:
        "200":
          description: User details
          schema:
            $ref: '#/definitions/models.UserDetails'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (Not superuser or not the user's own account)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: User not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get user details
      tags:
      - Users
    put:
      consumes:
      - application/json
      description: Updates an existing user. Regular users may update only their own
        profile fields. Group and superuser status changes require superuser privileges.
      parameters:
      - description: Username to update
        in: path
        name: username
        required: true
        type: string
      - description: User details to update
        in: body
        name: user
        required: true
        schema:
          $ref: '#/definitions/models.UserUpdateRequest'
      produces:
      - application/json
      responses:
        "200":
          description: User updated successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid request body
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (Not superuser or not the user's own account)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: User not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Update user
      tags:
      - Users
  /api/v1/users/{username}/password:
    put:
      consumes:
      - application/json
      description: Changes a user's password. Requires superuser privileges or the
        user's own account.
      parameters:
      - description: Username to change password for
        in: path
        name: username
        required: true
        type: string
      - description: Password change details
        in: body
        name: passwordChange
        required: true
        schema:
          $ref: '#/definitions/models.PasswordChangeRequest'
      produces:
      - application/json
      responses:
        "200":
          description: Password changed successfully
          schema:
            $ref: '#/definitions/models.GenericSuccessResponse'
        "400":
          description: Invalid request body
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Unauthorized or incorrect current password
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "403":
          description: Forbidden (Not superuser or not the user's own account)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "404":
          description: User not found
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Change user password
      tags:
      - Users
  /api/v1/version:
    get:
      description: Returns version information for the containerlab library in use.
      produces:
      - application/json
      responses:
        "200":
          description: Containerlab version details
          schema:
            $ref: '#/definitions/models.VersionResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Get containerlab version
      tags:
      - Version
  /api/v1/version/check:
    get:
      description: Checks whether a newer containerlab release is available.
      produces:
      - application/json
      responses:
        "200":
          description: Result of the version check
          schema:
            $ref: '#/definitions/models.VersionCheckResponse'
        "401":
          description: Unauthorized
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      security:
      - BearerAuth: []
      summary: Check containerlab updates
      tags:
      - Version
  /health:
    get:
      description: |-
        Returns basic health status for the API server.

        **Notes**
        - `features` lists optional API capabilities (for example `exec-filters` or `snapshot-save`) so clients can detect what this server supports. Features the configured runtime cannot serve are left out.
        - `runtime` is the lab runtime the server runs labs with: `docker`, `podman` or `c9s` (Kubernetes through clabernetes).
        - `namespaceMode` is set for `c9s`: `per-lab`, every lab of every user in its own namespace.
      produces:
      - application/json
      responses:
        "200":
          description: Basic health information
          schema:
            $ref: '#/definitions/models.HealthResponse'
      summary: Get API server health
      tags:
      - Health
  /login:
    post:
      consumes:
      - application/json
      description: Authenticates a user and returns a JWT token.
      parameters:
      - description: User Credentials
        in: body
        name: credentials
        required: true
        schema:
          $ref: '#/definitions/models.LoginRequest'
      produces:
      - application/json
      responses:
        "200":
          description: JWT token
          schema:
            $ref: '#/definitions/models.LoginResponse'
        "400":
          description: Invalid input
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "401":
          description: Invalid credentials
          schema:
            $ref: '#/definitions/models.ErrorResponse'
        "500":
          description: Internal server error (PAM config?)
          schema:
            $ref: '#/definitions/models.ErrorResponse'
      summary: Log in
      tags:
      - Auth
schemes:
- http
- https
securityDefinitions:
  BearerAuth:
    description: 'Type "Bearer" followed by a space and JWT token. Example: "Bearer
      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."'
    in: header
    name: Authorization
    type: apiKey
swagger: "2.0"
