diff --git a/docs/docs.go b/docs/docs.go index 23353df..3e5b7b5 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -31,26 +31,15 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Streams containerlab events in real-time. The response stays open until the client disconnects.\n\n**JSON format example** (default, returns NDJSON - one JSON object per line):\n` + "`" + `` + "`" + `` + "`" + `json\n{\"time\":1706918400,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"clab-node-name\":\"srl1\",\"clab-node-kind\":\"nokia_srlinux\"}}\n{\"time\":1706918405,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl2\",\"lab\":\"mylab\",\"clab-node-name\":\"srl2\",\"clab-node-kind\":\"nokia_srlinux\"}}\n` + "`" + `` + "`" + `` + "`" + `\n\n**Interface stats example** (interfaceStats=true):\n` + "`" + `` + "`" + `` + "`" + `json\n{\"time\":1706918410,\"type\":\"interface-stats\",\"action\":\"stats\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"interface\":\"e1-1\",\"rx_bytes\":123456,\"tx_bytes\":654321}}\n` + "`" + `` + "`" + `` + "`" + `\n\n**Plain format example** (format=plain):\n` + "`" + `` + "`" + `` + "`" + `\n2024-02-03T10:30:00Z container start (name=clab-mylab-srl1, lab=mylab, kind=nokia_srlinux)\n2024-02-03T10:30:05Z container start (name=clab-mylab-srl2, lab=mylab, kind=nokia_srlinux)\n` + "`" + `` + "`" + `` + "`" + `", + "description": "Streams containerlab events in real time as NDJSON (one JSON object per line).\n\n**Notes**\n- The response stays open until the client disconnects.\n\n**Examples**\nNDJSON (one JSON object per line):\n` + "`" + `` + "`" + `` + "`" + `json\n{\"time\":1706918400,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"clab-node-name\":\"srl1\",\"clab-node-kind\":\"nokia_srlinux\"}}\n{\"time\":1706918405,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl2\",\"lab\":\"mylab\",\"clab-node-name\":\"srl2\",\"clab-node-kind\":\"nokia_srlinux\"}}\n` + "`" + `` + "`" + `` + "`" + `\n\n\nInterface stats (interfaceStats=true):\n` + "`" + `` + "`" + `` + "`" + `json\n{\"time\":1706918410,\"type\":\"interface-stats\",\"action\":\"stats\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"interface\":\"e1-1\",\"rx_bytes\":123456,\"tx_bytes\":654321}}\n` + "`" + `` + "`" + `` + "`" + `", "produces": [ - "application/json" + "application/x-ndjson" ], "tags": [ "Events" ], - "summary": "Stream Containerlab Events", + "summary": "Stream containerlab events", "parameters": [ - { - "enum": [ - "json", - "plain" - ], - "type": "string", - "default": "json", - "description": "Output format ('json' or 'plain'). Default is 'json'.", - "name": "format", - "in": "query" - }, { "type": "boolean", "default": false, @@ -75,7 +64,7 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "Event stream - returns newline-delimited events (plain text or NDJSON)", + "description": "Event stream - NDJSON (one JSON object per line)", "schema": { "$ref": "#/definitions/models.EventResponse" } @@ -108,7 +97,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Generates a containerlab topology file based on CLOS definitions. Optionally deploys it, setting the owner to the authenticated user.\nDeployment is DENIED if a lab with the target name already exists.\nThe 'images' and 'licenses' fields expect a map where the key is the node 'kind' and the value is the corresponding image or license path (e.g., {\"nokia_srlinux\": \"ghcr.io/...\"}).\nIf Deploy=true, the topology is saved to the user's ~/.clab/\u003clabName\u003e/ directory before deployment, and the 'outputFile' field is ignored.\nIf Deploy=false and 'outputFile' is empty, YAML is returned directly.\nIf Deploy=false and 'outputFile' is set, the file is saved to that path on the server (requires API server write permissions).", + "description": "Generates a containerlab topology from CLOS definitions and can optionally deploy it for the authenticated user.\n\n**Notes**\n- Deployment is denied if a lab with the target name already exists.\n- The ` + "`" + `images` + "`" + ` and ` + "`" + `licenses` + "`" + ` fields map node kind to image or license path (e.g., {\"nokia_srlinux\":\"ghcr.io/...\"}).\n- When ` + "`" + `deploy=true` + "`" + `, the topology is saved to the user's ` + "`" + `~/.clab/\u003clabName\u003e/` + "`" + ` directory and ` + "`" + `outputFile` + "`" + ` is ignored.\n- When ` + "`" + `deploy=false` + "`" + ` and ` + "`" + `outputFile` + "`" + ` is empty, YAML is returned in the response.\n- When ` + "`" + `deploy=false` + "`" + ` and ` + "`" + `outputFile` + "`" + ` is set, the file is saved to that path on the server (requires API server write permissions).", "consumes": [ "application/json" ], @@ -118,7 +107,7 @@ const docTemplate = `{ "tags": [ "Topology Generation" ], - "summary": "Generate Topology", + "summary": "Generate containerlab topology", "parameters": [ { "description": "Topology generation parameters. The 'images' field maps kind to image path.", @@ -171,14 +160,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Returns detailed CPU, memory, and disk metrics for the API server. Requires SUPERUSER privileges.", + "description": "Returns detailed CPU, memory, and disk metrics for the API server. Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Health" ], - "summary": "Get Detailed System Metrics", + "summary": "Get system metrics", "responses": { "200": { "description": "System metrics", @@ -214,14 +203,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Get details about all running labs (filtered by owner unless superuser).", + "description": "Returns details for all running labs.\n\n**Notes**\n- Results are filtered by owner unless the caller is a superuser.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "List All Labs", + "summary": "List labs", "responses": { "200": { "description": "All labs", @@ -249,7 +238,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Deploys a containerlab topology. Requires EITHER 'topologyContent' OR 'topologySourceUrl' in the request body, but not both.", + "description": "Deploys a containerlab topology.\n\n**Notes**\n- The request body must include either ` + "`" + `topologyContent` + "`" + ` or ` + "`" + `topologySourceUrl` + "`" + ` (not both).", "consumes": [ "application/json" ], @@ -259,7 +248,7 @@ const docTemplate = `{ "tags": [ "Labs" ], - "summary": "Deploy Lab", + "summary": "Deploy lab", "parameters": [ { "description": "Deployment Source", @@ -270,6 +259,12 @@ const docTemplate = `{ "$ref": "#/definitions/models.DeployRequest" } }, + { + "type": "string", + "description": "Override lab name when deploying from a URL (optional)", + "name": "labNameOverride", + "in": "query" + }, { "type": "boolean", "description": "Allow overwriting an existing lab IF owned by the user", @@ -364,7 +359,7 @@ const docTemplate = `{ "tags": [ "Labs" ], - "summary": "Deploy Lab from Archive", + "summary": "Deploy lab from archive", "parameters": [ { "type": "file", @@ -385,6 +380,36 @@ const docTemplate = `{ "description": "Allow overwriting an existing lab", "name": "reconfigure", "in": "query" + }, + { + "type": "integer", + "description": "Limit concurrent workers", + "name": "maxWorkers", + "in": "query" + }, + { + "type": "string", + "description": "Custom Go template file for topology data export", + "name": "exportTemplate", + "in": "query" + }, + { + "type": "string", + "description": "Comma-separated list of node names to deploy", + "name": "nodeFilter", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip post-deploy actions", + "name": "skipPostDeploy", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip setting extended ACLs on lab directory", + "name": "skipLabdirAcl", + "in": "query" } ], "responses": { @@ -434,14 +459,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Get details about a specific running lab.", + "description": "Returns details for a specific running lab.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "Inspect Lab", + "summary": "Inspect lab", "parameters": [ { "type": "string", @@ -449,12 +474,6 @@ const docTemplate = `{ "name": "labName", "in": "path", "required": true - }, - { - "type": "boolean", - "description": "Include full container details", - "name": "details", - "in": "query" } ], "responses": { @@ -499,14 +518,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Redeploys a lab by name (destroy + deploy).", + "description": "Redeploys a lab by name.\n\n**Notes**\n- This operation destroys the lab and then deploys it again.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "Redeploy Lab", + "summary": "Redeploy lab", "parameters": [ { "type": "string", @@ -514,6 +533,48 @@ const docTemplate = `{ "name": "labName", "in": "path", "required": true + }, + { + "type": "boolean", + "description": "Remove lab directory after destroy", + "name": "cleanup", + "in": "query" + }, + { + "type": "boolean", + "description": "Attempt graceful shutdown", + "name": "graceful", + "in": "query" + }, + { + "type": "boolean", + "description": "Keep the management network", + "name": "keepMgmtNet", + "in": "query" + }, + { + "type": "integer", + "description": "Limit concurrent workers", + "name": "maxWorkers", + "in": "query" + }, + { + "type": "string", + "description": "Custom Go template file for topology data export", + "name": "exportTemplate", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip post-deploy actions", + "name": "skipPostDeploy", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip setting extended ACLs on lab directory", + "name": "skipLabdirAcl", + "in": "query" } ], "responses": { @@ -555,14 +616,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Destroys a lab by name, checking ownership.", + "description": "Destroys a lab by name after verifying ownership.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "Destroy Lab", + "summary": "Destroy lab", "parameters": [ { "type": "string", @@ -598,7 +659,7 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "Lab destroyed successfully", "schema": { "$ref": "#/definitions/models.GenericSuccessResponse" } @@ -637,7 +698,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Executes a command on nodes within a specific lab.", + "description": "Executes a command on nodes within a lab.", "consumes": [ "application/json" ], @@ -647,7 +708,7 @@ const docTemplate = `{ "tags": [ "Labs" ], - "summary": "Execute Command in Lab", + "summary": "Execute command in lab", "parameters": [ { "type": "string", @@ -662,12 +723,6 @@ const docTemplate = `{ "name": "nodeFilter", "in": "query" }, - { - "type": "string", - "description": "Output format ('plain' or 'json')", - "name": "format", - "in": "query" - }, { "description": "Command to execute", "name": "exec_request", @@ -719,14 +774,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Get network interface details for nodes in a specific lab.", + "description": "Returns interface details for nodes in a lab.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "List Lab Interfaces", + "summary": "List lab interfaces", "parameters": [ { "type": "string", @@ -786,16 +841,15 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Get logs from a specific lab node (container). When follow=true, logs will stream until client disconnects or 30-minute timeout.", + "description": "Returns logs for a lab node.\n\n**Notes**\n- When ` + "`" + `follow=true` + "`" + `, the response streams as NDJSON (one JSON object per line) until the client disconnects or the 30-minute timeout.", "produces": [ - "text/plain", "application/json", - "application/octet-stream" + "application/x-ndjson" ], "tags": [ "Logs" ], - "summary": "Get Node Logs", + "summary": "Get node logs", "parameters": [ { "type": "string", @@ -812,27 +866,22 @@ const docTemplate = `{ "required": true }, { - "type": "integer", - "description": "Number of lines to show from the end of logs (default all)", + "type": "string", + "default": "all", + "description": "Number of lines to show from the end of logs (default all). Use an integer or 'all'.", "name": "tail", "in": "query" }, { "type": "boolean", - "description": "Follow log output (stream logs). Note: In Swagger UI, streaming may not display correctly.", + "description": "Follow log output (stream logs as NDJSON). Note: In Swagger UI, streaming may not display correctly.", "name": "follow", "in": "query" - }, - { - "type": "string", - "description": "Output format ('plain' or 'json'). Default is 'plain'. When follow=true, only 'plain' format is supported.", - "name": "format", - "in": "query" } ], "responses": { "200": { - "description": "Container logs (when format=json)", + "description": "Container logs (follow=false). When follow=true, response is NDJSON stream of LogLine objects.", "schema": { "$ref": "#/definitions/models.LogsResponse" } @@ -877,7 +926,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Creates temporary SSH access to a specific lab node, returning connection details", + "description": "Creates temporary SSH access to a lab node and returns connection details.", "consumes": [ "application/json" ], @@ -887,7 +936,7 @@ const docTemplate = `{ "tags": [ "SSH Access" ], - "summary": "Request SSH Access to Lab Node", + "summary": "Request SSH access to lab node", "parameters": [ { "type": "string", @@ -966,7 +1015,7 @@ const docTemplate = `{ "tags": [ "Labs" ], - "summary": "Save Lab Configuration", + "summary": "Save lab configuration", "parameters": [ { "type": "string", @@ -1023,14 +1072,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Lists active SSH sessions. For regular users, shows only their sessions. Superusers can see all sessions by using the 'all' query parameter.", + "description": "Returns active SSH sessions.\n\n**Notes**\n- Regular users see only their sessions.\n- Superusers can include all sessions via the ` + "`" + `all` + "`" + ` query parameter.", "produces": [ "application/json" ], "tags": [ "SSH Access" ], - "summary": "List SSH Sessions", + "summary": "List SSH sessions", "parameters": [ { "type": "boolean", @@ -1071,14 +1120,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Terminates a specific SSH session by port", + "description": "Terminates a specific SSH session by port.", "produces": [ "application/json" ], "tags": [ "SSH Access" ], - "summary": "Terminate SSH Session", + "summary": "Terminate SSH session", "parameters": [ { "type": "integer", @@ -1135,7 +1184,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Creates a CA certificate and private key. Requires SUPERUSER privileges. Files are stored in the user's ~/.clab/certs/\u003cca_name\u003e/ directory on the server.", + "description": "Creates a CA certificate and private key. Requires superuser privileges.\n\n**Notes**\n- Files are stored in the user's ` + "`" + `~/.clab/certs/\u003cca_name\u003e/` + "`" + ` directory on the server.", "consumes": [ "application/json" ], @@ -1145,7 +1194,7 @@ const docTemplate = `{ "tags": [ "Tools - Certificates" ], - "summary": "Create Certificate Authority (CA)", + "summary": "Create certificate authority (CA)", "parameters": [ { "description": "CA Generation Parameters", @@ -1198,7 +1247,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Creates a certificate/key and signs it with a previously generated CA. Requires SUPERUSER privileges. Files are stored in the user's ~/.clab/certs/\u003cca_name\u003e/ directory.", + "description": "Creates a certificate/key and signs it with a previously generated CA. Requires superuser privileges.\n\n**Notes**\n- Files are stored in the user's ` + "`" + `~/.clab/certs/\u003cca_name\u003e/` + "`" + ` directory.", "consumes": [ "application/json" ], @@ -1208,7 +1257,7 @@ const docTemplate = `{ "tags": [ "Tools - Certificates" ], - "summary": "Sign Certificate", + "summary": "Sign certificate", "parameters": [ { "description": "Certificate Signing Parameters", @@ -1267,7 +1316,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Disables TX checksum offload for the eth0 interface of a specific container. Requires SUPERUSER privileges.", + "description": "Disables TX checksum offload on the eth0 interface of a container. Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1277,7 +1326,7 @@ const docTemplate = `{ "tags": [ "Tools" ], - "summary": "Disable TX Checksum Offload", + "summary": "Disable TX checksum offload", "parameters": [ { "description": "Container Name", @@ -1336,7 +1385,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Creates a virtual Ethernet (vEth) pair between two specified endpoints (container, host, bridge, ovs-bridge). Requires SUPERUSER privileges.", + "description": "Creates a virtual Ethernet (vEth) pair between two endpoints (container, host, bridge, or ovs-bridge). Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1346,7 +1395,7 @@ const docTemplate = `{ "tags": [ "Tools - vEth" ], - "summary": "Create vEth Pair", + "summary": "Create vEth pair", "parameters": [ { "description": "vEth Creation Parameters", @@ -1399,7 +1448,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Creates a VxLAN tunnel interface and sets up tc rules for traffic redirection. Requires SUPERUSER privileges.", + "description": "Creates a VxLAN tunnel interface and sets up tc rules for traffic redirection. Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1409,7 +1458,7 @@ const docTemplate = `{ "tags": [ "Tools - VxLAN" ], - "summary": "Create VxLAN Tunnel", + "summary": "Create VxLAN tunnel", "parameters": [ { "description": "VxLAN Creation Parameters", @@ -1460,14 +1509,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Deletes VxLAN tunnel interfaces matching a given prefix (default: 'vx-'). Requires SUPERUSER privileges.", + "description": "Deletes VxLAN tunnel interfaces that match the provided prefix (default: ` + "`" + `vx-` + "`" + `). Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Tools - VxLAN" ], - "summary": "Delete VxLAN Tunnels by Prefix", + "summary": "Delete VxLAN tunnels by prefix", "parameters": [ { "type": "string", @@ -1518,14 +1567,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Get a list of all users in the system. Requires superuser privileges.", + "description": "Returns a list of system users. Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Users" ], - "summary": "List All Users", + "summary": "List users", "responses": { "200": { "description": "List of user details", @@ -1562,7 +1611,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Create a new system user. Requires superuser privileges.", + "description": "Creates a new system user. Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1572,7 +1621,7 @@ const docTemplate = `{ "tags": [ "Users" ], - "summary": "Create User", + "summary": "Create user", "parameters": [ { "description": "User creation details", @@ -1631,14 +1680,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Get detailed information about a specific user. Requires superuser privileges or the user's own account.", + "description": "Returns details for a specific user. Requires superuser privileges or the user's own account.", "produces": [ "application/json" ], "tags": [ "Users" ], - "summary": "Get User Details", + "summary": "Get user details", "parameters": [ { "type": "string", @@ -1687,7 +1736,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Update information for an existing user. Requires superuser privileges or the user's own account.", + "description": "Updates an existing user. Requires superuser privileges or the user's own account.", "consumes": [ "application/json" ], @@ -1697,7 +1746,7 @@ const docTemplate = `{ "tags": [ "Users" ], - "summary": "Update User", + "summary": "Update user", "parameters": [ { "type": "string", @@ -1761,14 +1810,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Delete a user from the system. Requires superuser privileges.", + "description": "Deletes a user from the system. Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Users" ], - "summary": "Delete User", + "summary": "Delete user", "parameters": [ { "type": "string", @@ -1819,7 +1868,7 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Change password for a user. Requires superuser privileges or the user's own account.", + "description": "Changes a user's password. Requires superuser privileges or the user's own account.", "consumes": [ "application/json" ], @@ -1829,7 +1878,7 @@ const docTemplate = `{ "tags": [ "Users" ], - "summary": "Change User Password", + "summary": "Change user password", "parameters": [ { "type": "string", @@ -1895,14 +1944,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "Retrieves version information about the containerlab library in use.", + "description": "Returns version information for the containerlab library in use.", "produces": [ "application/json" ], "tags": [ "Version" ], - "summary": "Get Containerlab Version", + "summary": "Get containerlab version", "responses": { "200": { "description": "Containerlab version details", @@ -1932,14 +1981,14 @@ const docTemplate = `{ "BearerAuth": [] } ], - "description": "This endpoint has been deprecated. Version checks are no longer supported when using containerlab as a library.", + "description": "**Deprecated**\nVersion checks are not supported when containerlab runs as a library.", "produces": [ "application/json" ], "tags": [ "Version" ], - "summary": "Check for Containerlab Updates", + "summary": "Check containerlab updates", "responses": { "200": { "description": "Result of the version check", @@ -1958,14 +2007,14 @@ const docTemplate = `{ }, "/health": { "get": { - "description": "Returns basic health status of the API server.", + "description": "Returns basic health status for the API server.", "produces": [ "application/json" ], "tags": [ "Health" ], - "summary": "Get API Server Basic Health", + "summary": "Get API server health", "responses": { "200": { "description": "Basic health information", @@ -1978,7 +2027,7 @@ const docTemplate = `{ }, "/login": { "post": { - "description": "Authenticate user and return JWT token", + "description": "Authenticates a user and returns a JWT token.", "consumes": [ "application/json" ], @@ -1988,7 +2037,7 @@ const docTemplate = `{ "tags": [ "Auth" ], - "summary": "Login", + "summary": "Log in", "parameters": [ { "description": "User Credentials", @@ -2002,7 +2051,7 @@ const docTemplate = `{ ], "responses": { "200": { - "description": "OK", + "description": "JWT token", "schema": { "$ref": "#/definitions/models.LoginResponse" } @@ -2521,7 +2570,7 @@ const docTemplate = `{ "type": "object", "properties": { "deployOutput": { - "description": "The output from the deploy command (only if Deploy=true). Can be JSON or plain text.\nUse swaggertype:\"object\" to represent json.RawMessage in Swagger.", + "description": "The output from the deploy command (only if Deploy=true). JSON object keyed by lab name.\nUse swaggertype:\"object\" to represent json.RawMessage in Swagger.", "type": "object" }, "message": { diff --git a/docs/swagger.json b/docs/swagger.json index 74967e1..3d91d9a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -27,26 +27,15 @@ "BearerAuth": [] } ], - "description": "Streams containerlab events in real-time. The response stays open until the client disconnects.\n\n**JSON format example** (default, returns NDJSON - one JSON object per line):\n```json\n{\"time\":1706918400,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"clab-node-name\":\"srl1\",\"clab-node-kind\":\"nokia_srlinux\"}}\n{\"time\":1706918405,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl2\",\"lab\":\"mylab\",\"clab-node-name\":\"srl2\",\"clab-node-kind\":\"nokia_srlinux\"}}\n```\n\n**Interface stats example** (interfaceStats=true):\n```json\n{\"time\":1706918410,\"type\":\"interface-stats\",\"action\":\"stats\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"interface\":\"e1-1\",\"rx_bytes\":123456,\"tx_bytes\":654321}}\n```\n\n**Plain format example** (format=plain):\n```\n2024-02-03T10:30:00Z container start (name=clab-mylab-srl1, lab=mylab, kind=nokia_srlinux)\n2024-02-03T10:30:05Z container start (name=clab-mylab-srl2, lab=mylab, kind=nokia_srlinux)\n```", + "description": "Streams containerlab events in real time as NDJSON (one JSON object per line).\n\n**Notes**\n- The response stays open until the client disconnects.\n\n**Examples**\nNDJSON (one JSON object per line):\n```json\n{\"time\":1706918400,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"clab-node-name\":\"srl1\",\"clab-node-kind\":\"nokia_srlinux\"}}\n{\"time\":1706918405,\"type\":\"container\",\"action\":\"start\",\"attributes\":{\"name\":\"clab-mylab-srl2\",\"lab\":\"mylab\",\"clab-node-name\":\"srl2\",\"clab-node-kind\":\"nokia_srlinux\"}}\n```\n\n\nInterface stats (interfaceStats=true):\n```json\n{\"time\":1706918410,\"type\":\"interface-stats\",\"action\":\"stats\",\"attributes\":{\"name\":\"clab-mylab-srl1\",\"lab\":\"mylab\",\"interface\":\"e1-1\",\"rx_bytes\":123456,\"tx_bytes\":654321}}\n```", "produces": [ - "application/json" + "application/x-ndjson" ], "tags": [ "Events" ], - "summary": "Stream Containerlab Events", + "summary": "Stream containerlab events", "parameters": [ - { - "enum": [ - "json", - "plain" - ], - "type": "string", - "default": "json", - "description": "Output format ('json' or 'plain'). Default is 'json'.", - "name": "format", - "in": "query" - }, { "type": "boolean", "default": false, @@ -71,7 +60,7 @@ ], "responses": { "200": { - "description": "Event stream - returns newline-delimited events (plain text or NDJSON)", + "description": "Event stream - NDJSON (one JSON object per line)", "schema": { "$ref": "#/definitions/models.EventResponse" } @@ -104,7 +93,7 @@ "BearerAuth": [] } ], - "description": "Generates a containerlab topology file based on CLOS definitions. Optionally deploys it, setting the owner to the authenticated user.\nDeployment is DENIED if a lab with the target name already exists.\nThe 'images' and 'licenses' fields expect a map where the key is the node 'kind' and the value is the corresponding image or license path (e.g., {\"nokia_srlinux\": \"ghcr.io/...\"}).\nIf Deploy=true, the topology is saved to the user's ~/.clab/\u003clabName\u003e/ directory before deployment, and the 'outputFile' field is ignored.\nIf Deploy=false and 'outputFile' is empty, YAML is returned directly.\nIf Deploy=false and 'outputFile' is set, the file is saved to that path on the server (requires API server write permissions).", + "description": "Generates a containerlab topology from CLOS definitions and can optionally deploy it for the authenticated user.\n\n**Notes**\n- Deployment is denied if a lab with the target name already exists.\n- The `images` and `licenses` fields map node kind to image or license path (e.g., {\"nokia_srlinux\":\"ghcr.io/...\"}).\n- When `deploy=true`, the topology is saved to the user's `~/.clab/\u003clabName\u003e/` directory and `outputFile` is ignored.\n- When `deploy=false` and `outputFile` is empty, YAML is returned in the response.\n- When `deploy=false` and `outputFile` is set, the file is saved to that path on the server (requires API server write permissions).", "consumes": [ "application/json" ], @@ -114,7 +103,7 @@ "tags": [ "Topology Generation" ], - "summary": "Generate Topology", + "summary": "Generate containerlab topology", "parameters": [ { "description": "Topology generation parameters. The 'images' field maps kind to image path.", @@ -167,14 +156,14 @@ "BearerAuth": [] } ], - "description": "Returns detailed CPU, memory, and disk metrics for the API server. Requires SUPERUSER privileges.", + "description": "Returns detailed CPU, memory, and disk metrics for the API server. Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Health" ], - "summary": "Get Detailed System Metrics", + "summary": "Get system metrics", "responses": { "200": { "description": "System metrics", @@ -210,14 +199,14 @@ "BearerAuth": [] } ], - "description": "Get details about all running labs (filtered by owner unless superuser).", + "description": "Returns details for all running labs.\n\n**Notes**\n- Results are filtered by owner unless the caller is a superuser.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "List All Labs", + "summary": "List labs", "responses": { "200": { "description": "All labs", @@ -245,7 +234,7 @@ "BearerAuth": [] } ], - "description": "Deploys a containerlab topology. Requires EITHER 'topologyContent' OR 'topologySourceUrl' in the request body, but not both.", + "description": "Deploys a containerlab topology.\n\n**Notes**\n- The request body must include either `topologyContent` or `topologySourceUrl` (not both).", "consumes": [ "application/json" ], @@ -255,7 +244,7 @@ "tags": [ "Labs" ], - "summary": "Deploy Lab", + "summary": "Deploy lab", "parameters": [ { "description": "Deployment Source", @@ -266,6 +255,12 @@ "$ref": "#/definitions/models.DeployRequest" } }, + { + "type": "string", + "description": "Override lab name when deploying from a URL (optional)", + "name": "labNameOverride", + "in": "query" + }, { "type": "boolean", "description": "Allow overwriting an existing lab IF owned by the user", @@ -360,7 +355,7 @@ "tags": [ "Labs" ], - "summary": "Deploy Lab from Archive", + "summary": "Deploy lab from archive", "parameters": [ { "type": "file", @@ -381,6 +376,36 @@ "description": "Allow overwriting an existing lab", "name": "reconfigure", "in": "query" + }, + { + "type": "integer", + "description": "Limit concurrent workers", + "name": "maxWorkers", + "in": "query" + }, + { + "type": "string", + "description": "Custom Go template file for topology data export", + "name": "exportTemplate", + "in": "query" + }, + { + "type": "string", + "description": "Comma-separated list of node names to deploy", + "name": "nodeFilter", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip post-deploy actions", + "name": "skipPostDeploy", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip setting extended ACLs on lab directory", + "name": "skipLabdirAcl", + "in": "query" } ], "responses": { @@ -430,14 +455,14 @@ "BearerAuth": [] } ], - "description": "Get details about a specific running lab.", + "description": "Returns details for a specific running lab.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "Inspect Lab", + "summary": "Inspect lab", "parameters": [ { "type": "string", @@ -445,12 +470,6 @@ "name": "labName", "in": "path", "required": true - }, - { - "type": "boolean", - "description": "Include full container details", - "name": "details", - "in": "query" } ], "responses": { @@ -495,14 +514,14 @@ "BearerAuth": [] } ], - "description": "Redeploys a lab by name (destroy + deploy).", + "description": "Redeploys a lab by name.\n\n**Notes**\n- This operation destroys the lab and then deploys it again.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "Redeploy Lab", + "summary": "Redeploy lab", "parameters": [ { "type": "string", @@ -510,6 +529,48 @@ "name": "labName", "in": "path", "required": true + }, + { + "type": "boolean", + "description": "Remove lab directory after destroy", + "name": "cleanup", + "in": "query" + }, + { + "type": "boolean", + "description": "Attempt graceful shutdown", + "name": "graceful", + "in": "query" + }, + { + "type": "boolean", + "description": "Keep the management network", + "name": "keepMgmtNet", + "in": "query" + }, + { + "type": "integer", + "description": "Limit concurrent workers", + "name": "maxWorkers", + "in": "query" + }, + { + "type": "string", + "description": "Custom Go template file for topology data export", + "name": "exportTemplate", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip post-deploy actions", + "name": "skipPostDeploy", + "in": "query" + }, + { + "type": "boolean", + "description": "Skip setting extended ACLs on lab directory", + "name": "skipLabdirAcl", + "in": "query" } ], "responses": { @@ -551,14 +612,14 @@ "BearerAuth": [] } ], - "description": "Destroys a lab by name, checking ownership.", + "description": "Destroys a lab by name after verifying ownership.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "Destroy Lab", + "summary": "Destroy lab", "parameters": [ { "type": "string", @@ -594,7 +655,7 @@ ], "responses": { "200": { - "description": "OK", + "description": "Lab destroyed successfully", "schema": { "$ref": "#/definitions/models.GenericSuccessResponse" } @@ -633,7 +694,7 @@ "BearerAuth": [] } ], - "description": "Executes a command on nodes within a specific lab.", + "description": "Executes a command on nodes within a lab.", "consumes": [ "application/json" ], @@ -643,7 +704,7 @@ "tags": [ "Labs" ], - "summary": "Execute Command in Lab", + "summary": "Execute command in lab", "parameters": [ { "type": "string", @@ -658,12 +719,6 @@ "name": "nodeFilter", "in": "query" }, - { - "type": "string", - "description": "Output format ('plain' or 'json')", - "name": "format", - "in": "query" - }, { "description": "Command to execute", "name": "exec_request", @@ -715,14 +770,14 @@ "BearerAuth": [] } ], - "description": "Get network interface details for nodes in a specific lab.", + "description": "Returns interface details for nodes in a lab.", "produces": [ "application/json" ], "tags": [ "Labs" ], - "summary": "List Lab Interfaces", + "summary": "List lab interfaces", "parameters": [ { "type": "string", @@ -782,16 +837,15 @@ "BearerAuth": [] } ], - "description": "Get logs from a specific lab node (container). When follow=true, logs will stream until client disconnects or 30-minute timeout.", + "description": "Returns logs for a lab node.\n\n**Notes**\n- When `follow=true`, the response streams as NDJSON (one JSON object per line) until the client disconnects or the 30-minute timeout.", "produces": [ - "text/plain", "application/json", - "application/octet-stream" + "application/x-ndjson" ], "tags": [ "Logs" ], - "summary": "Get Node Logs", + "summary": "Get node logs", "parameters": [ { "type": "string", @@ -808,27 +862,22 @@ "required": true }, { - "type": "integer", - "description": "Number of lines to show from the end of logs (default all)", + "type": "string", + "default": "all", + "description": "Number of lines to show from the end of logs (default all). Use an integer or 'all'.", "name": "tail", "in": "query" }, { "type": "boolean", - "description": "Follow log output (stream logs). Note: In Swagger UI, streaming may not display correctly.", + "description": "Follow log output (stream logs as NDJSON). Note: In Swagger UI, streaming may not display correctly.", "name": "follow", "in": "query" - }, - { - "type": "string", - "description": "Output format ('plain' or 'json'). Default is 'plain'. When follow=true, only 'plain' format is supported.", - "name": "format", - "in": "query" } ], "responses": { "200": { - "description": "Container logs (when format=json)", + "description": "Container logs (follow=false). When follow=true, response is NDJSON stream of LogLine objects.", "schema": { "$ref": "#/definitions/models.LogsResponse" } @@ -873,7 +922,7 @@ "BearerAuth": [] } ], - "description": "Creates temporary SSH access to a specific lab node, returning connection details", + "description": "Creates temporary SSH access to a lab node and returns connection details.", "consumes": [ "application/json" ], @@ -883,7 +932,7 @@ "tags": [ "SSH Access" ], - "summary": "Request SSH Access to Lab Node", + "summary": "Request SSH access to lab node", "parameters": [ { "type": "string", @@ -962,7 +1011,7 @@ "tags": [ "Labs" ], - "summary": "Save Lab Configuration", + "summary": "Save lab configuration", "parameters": [ { "type": "string", @@ -1019,14 +1068,14 @@ "BearerAuth": [] } ], - "description": "Lists active SSH sessions. For regular users, shows only their sessions. Superusers can see all sessions by using the 'all' query parameter.", + "description": "Returns active SSH sessions.\n\n**Notes**\n- Regular users see only their sessions.\n- Superusers can include all sessions via the `all` query parameter.", "produces": [ "application/json" ], "tags": [ "SSH Access" ], - "summary": "List SSH Sessions", + "summary": "List SSH sessions", "parameters": [ { "type": "boolean", @@ -1067,14 +1116,14 @@ "BearerAuth": [] } ], - "description": "Terminates a specific SSH session by port", + "description": "Terminates a specific SSH session by port.", "produces": [ "application/json" ], "tags": [ "SSH Access" ], - "summary": "Terminate SSH Session", + "summary": "Terminate SSH session", "parameters": [ { "type": "integer", @@ -1131,7 +1180,7 @@ "BearerAuth": [] } ], - "description": "Creates a CA certificate and private key. Requires SUPERUSER privileges. Files are stored in the user's ~/.clab/certs/\u003cca_name\u003e/ directory on the server.", + "description": "Creates a CA certificate and private key. Requires superuser privileges.\n\n**Notes**\n- Files are stored in the user's `~/.clab/certs/\u003cca_name\u003e/` directory on the server.", "consumes": [ "application/json" ], @@ -1141,7 +1190,7 @@ "tags": [ "Tools - Certificates" ], - "summary": "Create Certificate Authority (CA)", + "summary": "Create certificate authority (CA)", "parameters": [ { "description": "CA Generation Parameters", @@ -1194,7 +1243,7 @@ "BearerAuth": [] } ], - "description": "Creates a certificate/key and signs it with a previously generated CA. Requires SUPERUSER privileges. Files are stored in the user's ~/.clab/certs/\u003cca_name\u003e/ directory.", + "description": "Creates a certificate/key and signs it with a previously generated CA. Requires superuser privileges.\n\n**Notes**\n- Files are stored in the user's `~/.clab/certs/\u003cca_name\u003e/` directory.", "consumes": [ "application/json" ], @@ -1204,7 +1253,7 @@ "tags": [ "Tools - Certificates" ], - "summary": "Sign Certificate", + "summary": "Sign certificate", "parameters": [ { "description": "Certificate Signing Parameters", @@ -1263,7 +1312,7 @@ "BearerAuth": [] } ], - "description": "Disables TX checksum offload for the eth0 interface of a specific container. Requires SUPERUSER privileges.", + "description": "Disables TX checksum offload on the eth0 interface of a container. Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1273,7 +1322,7 @@ "tags": [ "Tools" ], - "summary": "Disable TX Checksum Offload", + "summary": "Disable TX checksum offload", "parameters": [ { "description": "Container Name", @@ -1332,7 +1381,7 @@ "BearerAuth": [] } ], - "description": "Creates a virtual Ethernet (vEth) pair between two specified endpoints (container, host, bridge, ovs-bridge). Requires SUPERUSER privileges.", + "description": "Creates a virtual Ethernet (vEth) pair between two endpoints (container, host, bridge, or ovs-bridge). Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1342,7 +1391,7 @@ "tags": [ "Tools - vEth" ], - "summary": "Create vEth Pair", + "summary": "Create vEth pair", "parameters": [ { "description": "vEth Creation Parameters", @@ -1395,7 +1444,7 @@ "BearerAuth": [] } ], - "description": "Creates a VxLAN tunnel interface and sets up tc rules for traffic redirection. Requires SUPERUSER privileges.", + "description": "Creates a VxLAN tunnel interface and sets up tc rules for traffic redirection. Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1405,7 +1454,7 @@ "tags": [ "Tools - VxLAN" ], - "summary": "Create VxLAN Tunnel", + "summary": "Create VxLAN tunnel", "parameters": [ { "description": "VxLAN Creation Parameters", @@ -1456,14 +1505,14 @@ "BearerAuth": [] } ], - "description": "Deletes VxLAN tunnel interfaces matching a given prefix (default: 'vx-'). Requires SUPERUSER privileges.", + "description": "Deletes VxLAN tunnel interfaces that match the provided prefix (default: `vx-`). Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Tools - VxLAN" ], - "summary": "Delete VxLAN Tunnels by Prefix", + "summary": "Delete VxLAN tunnels by prefix", "parameters": [ { "type": "string", @@ -1514,14 +1563,14 @@ "BearerAuth": [] } ], - "description": "Get a list of all users in the system. Requires superuser privileges.", + "description": "Returns a list of system users. Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Users" ], - "summary": "List All Users", + "summary": "List users", "responses": { "200": { "description": "List of user details", @@ -1558,7 +1607,7 @@ "BearerAuth": [] } ], - "description": "Create a new system user. Requires superuser privileges.", + "description": "Creates a new system user. Requires superuser privileges.", "consumes": [ "application/json" ], @@ -1568,7 +1617,7 @@ "tags": [ "Users" ], - "summary": "Create User", + "summary": "Create user", "parameters": [ { "description": "User creation details", @@ -1627,14 +1676,14 @@ "BearerAuth": [] } ], - "description": "Get detailed information about a specific user. Requires superuser privileges or the user's own account.", + "description": "Returns details for a specific user. Requires superuser privileges or the user's own account.", "produces": [ "application/json" ], "tags": [ "Users" ], - "summary": "Get User Details", + "summary": "Get user details", "parameters": [ { "type": "string", @@ -1683,7 +1732,7 @@ "BearerAuth": [] } ], - "description": "Update information for an existing user. Requires superuser privileges or the user's own account.", + "description": "Updates an existing user. Requires superuser privileges or the user's own account.", "consumes": [ "application/json" ], @@ -1693,7 +1742,7 @@ "tags": [ "Users" ], - "summary": "Update User", + "summary": "Update user", "parameters": [ { "type": "string", @@ -1757,14 +1806,14 @@ "BearerAuth": [] } ], - "description": "Delete a user from the system. Requires superuser privileges.", + "description": "Deletes a user from the system. Requires superuser privileges.", "produces": [ "application/json" ], "tags": [ "Users" ], - "summary": "Delete User", + "summary": "Delete user", "parameters": [ { "type": "string", @@ -1815,7 +1864,7 @@ "BearerAuth": [] } ], - "description": "Change password for a user. Requires superuser privileges or the user's own account.", + "description": "Changes a user's password. Requires superuser privileges or the user's own account.", "consumes": [ "application/json" ], @@ -1825,7 +1874,7 @@ "tags": [ "Users" ], - "summary": "Change User Password", + "summary": "Change user password", "parameters": [ { "type": "string", @@ -1891,14 +1940,14 @@ "BearerAuth": [] } ], - "description": "Retrieves version information about the containerlab library in use.", + "description": "Returns version information for the containerlab library in use.", "produces": [ "application/json" ], "tags": [ "Version" ], - "summary": "Get Containerlab Version", + "summary": "Get containerlab version", "responses": { "200": { "description": "Containerlab version details", @@ -1928,14 +1977,14 @@ "BearerAuth": [] } ], - "description": "This endpoint has been deprecated. Version checks are no longer supported when using containerlab as a library.", + "description": "**Deprecated**\nVersion checks are not supported when containerlab runs as a library.", "produces": [ "application/json" ], "tags": [ "Version" ], - "summary": "Check for Containerlab Updates", + "summary": "Check containerlab updates", "responses": { "200": { "description": "Result of the version check", @@ -1954,14 +2003,14 @@ }, "/health": { "get": { - "description": "Returns basic health status of the API server.", + "description": "Returns basic health status for the API server.", "produces": [ "application/json" ], "tags": [ "Health" ], - "summary": "Get API Server Basic Health", + "summary": "Get API server health", "responses": { "200": { "description": "Basic health information", @@ -1974,7 +2023,7 @@ }, "/login": { "post": { - "description": "Authenticate user and return JWT token", + "description": "Authenticates a user and returns a JWT token.", "consumes": [ "application/json" ], @@ -1984,7 +2033,7 @@ "tags": [ "Auth" ], - "summary": "Login", + "summary": "Log in", "parameters": [ { "description": "User Credentials", @@ -1998,7 +2047,7 @@ ], "responses": { "200": { - "description": "OK", + "description": "JWT token", "schema": { "$ref": "#/definitions/models.LoginResponse" } @@ -2517,7 +2566,7 @@ "type": "object", "properties": { "deployOutput": { - "description": "The output from the deploy command (only if Deploy=true). Can be JSON or plain text.\nUse swaggertype:\"object\" to represent json.RawMessage in Swagger.", + "description": "The output from the deploy command (only if Deploy=true). JSON object keyed by lab name.\nUse swaggertype:\"object\" to represent json.RawMessage in Swagger.", "type": "object" }, "message": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0a1013b..896116e 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -371,7 +371,7 @@ definitions: properties: deployOutput: description: |- - The output from the deploy command (only if Deploy=true). Can be JSON or plain text. + 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: @@ -740,33 +740,24 @@ paths: /api/v1/events: get: description: |- - Streams containerlab events in real-time. The response stays open until the client disconnects. + Streams containerlab events in real time as NDJSON (one JSON object per line). - **JSON format example** (default, returns 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 example** (interfaceStats=true): + + 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}} ``` - - **Plain format example** (format=plain): - ``` - 2024-02-03T10:30:00Z container start (name=clab-mylab-srl1, lab=mylab, kind=nokia_srlinux) - 2024-02-03T10:30:05Z container start (name=clab-mylab-srl2, lab=mylab, kind=nokia_srlinux) - ``` parameters: - - default: json - description: Output format ('json' or 'plain'). Default is 'json'. - enum: - - json - - plain - in: query - name: format - type: string - default: false description: Include initial snapshot events when the stream starts. in: query @@ -784,11 +775,10 @@ paths: name: interfaceStatsInterval type: string produces: - - application/json + - application/x-ndjson responses: "200": - description: Event stream - returns newline-delimited events (plain text - or NDJSON) + description: Event stream - NDJSON (one JSON object per line) schema: $ref: '#/definitions/models.EventResponse' "400": @@ -805,7 +795,7 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Stream Containerlab Events + summary: Stream containerlab events tags: - Events /api/v1/generate: @@ -813,12 +803,14 @@ paths: consumes: - application/json description: |- - Generates a containerlab topology file based on CLOS definitions. Optionally deploys it, setting the owner to the authenticated user. - Deployment is DENIED if a lab with the target name already exists. - The 'images' and 'licenses' fields expect a map where the key is the node 'kind' and the value is the corresponding image or license path (e.g., {"nokia_srlinux": "ghcr.io/..."}). - If Deploy=true, the topology is saved to the user's ~/.clab// directory before deployment, and the 'outputFile' field is ignored. - If Deploy=false and 'outputFile' is empty, YAML is returned directly. - If Deploy=false and 'outputFile' is set, the file is saved to that path on the server (requires API server write permissions). + 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 `~/.clab//` 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. @@ -852,13 +844,13 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Generate Topology + 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 SUPERUSER privileges. + Requires superuser privileges. produces: - application/json responses: @@ -880,12 +872,16 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Get Detailed System Metrics + summary: Get system metrics tags: - Health /api/v1/labs: get: - description: Get details about all running labs (filtered by owner unless superuser). + description: |- + Returns details for all running labs. + + **Notes** + - Results are filtered by owner unless the caller is a superuser. produces: - application/json responses: @@ -903,14 +899,17 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: List All Labs + summary: List labs tags: - Labs post: consumes: - application/json - description: Deploys a containerlab topology. Requires EITHER 'topologyContent' - OR 'topologySourceUrl' in the request body, but not both. + description: |- + Deploys a containerlab topology. + + **Notes** + - The request body must include either `topologyContent` or `topologySourceUrl` (not both). parameters: - description: Deployment Source in: body @@ -918,6 +917,10 @@ paths: 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 @@ -971,12 +974,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Deploy Lab + summary: Deploy lab tags: - Labs /api/v1/labs/{labName}: delete: - description: Destroys a lab by name, checking ownership. + description: Destroys a lab by name after verifying ownership. parameters: - description: Name of the lab to destroy in: path @@ -1003,7 +1006,7 @@ paths: - application/json responses: "200": - description: OK + description: Lab destroyed successfully schema: $ref: '#/definitions/models.GenericSuccessResponse' "400": @@ -1024,21 +1027,17 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Destroy Lab + summary: Destroy lab tags: - Labs get: - description: Get details about a specific running lab. + description: Returns details for a specific running lab. parameters: - description: Name of the lab to inspect in: path name: labName required: true type: string - - description: Include full container details - in: query - name: details - type: boolean produces: - application/json responses: @@ -1066,17 +1065,49 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Inspect Lab + summary: Inspect lab tags: - Labs put: - description: Redeploys a lab by name (destroy + deploy). + description: |- + Redeploys a lab by name. + + **Notes** + - This operation destroys the lab and then deploys it again. parameters: - description: Name of the lab to redeploy in: path name: labName required: true type: string + - description: Remove lab directory after destroy + in: query + name: cleanup + type: boolean + - description: Attempt graceful shutdown + in: query + name: graceful + type: boolean + - 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 produces: - application/json responses: @@ -1102,14 +1133,14 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Redeploy Lab + summary: Redeploy lab tags: - Labs /api/v1/labs/{labName}/exec: post: consumes: - application/json - description: Executes a command on nodes within a specific lab. + description: Executes a command on nodes within a lab. parameters: - description: Name of the lab in: path @@ -1120,10 +1151,6 @@ paths: in: query name: nodeFilter type: string - - description: Output format ('plain' or 'json') - in: query - name: format - type: string - description: Command to execute in: body name: exec_request @@ -1155,12 +1182,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Execute Command in Lab + summary: Execute command in lab tags: - Labs /api/v1/labs/{labName}/interfaces: get: - description: Get network interface details for nodes in a specific lab. + description: Returns interface details for nodes in a lab. parameters: - description: Name of the lab in: path @@ -1198,13 +1225,16 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: List Lab Interfaces + summary: List lab interfaces tags: - Labs /api/v1/labs/{labName}/nodes/{nodeName}/logs: get: - description: Get logs from a specific lab node (container). When follow=true, - logs will stream until client disconnects or 30-minute timeout. + 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 the 30-minute timeout. parameters: - description: Name of the lab in: path @@ -1216,27 +1246,24 @@ paths: name: nodeName required: true type: string - - description: Number of lines to show from the end of logs (default all) + - 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: integer - - description: 'Follow log output (stream logs). Note: In Swagger UI, streaming - may not display correctly.' + 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 - - description: Output format ('plain' or 'json'). Default is 'plain'. When follow=true, - only 'plain' format is supported. - in: query - name: format - type: string produces: - - text/plain - application/json - - application/octet-stream + - application/x-ndjson responses: "200": - description: Container logs (when format=json) + description: Container logs (follow=false). When follow=true, response is + NDJSON stream of LogLine objects. schema: $ref: '#/definitions/models.LogsResponse' "400": @@ -1261,15 +1288,15 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Get Node Logs + summary: Get node logs tags: - Logs /api/v1/labs/{labName}/nodes/{nodeName}/ssh: post: consumes: - application/json - description: Creates temporary SSH access to a specific lab node, returning - connection details + description: Creates temporary SSH access to a lab node and returns connection + details. parameters: - description: Lab name in: path @@ -1315,7 +1342,7 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Request SSH Access to Lab Node + summary: Request SSH access to lab node tags: - SSH Access /api/v1/labs/{labName}/save: @@ -1356,7 +1383,7 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Save Lab Configuration + summary: Save lab configuration tags: - Labs /api/v1/labs/archive: @@ -1379,6 +1406,26 @@ paths: 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 produces: - application/json responses: @@ -1408,13 +1455,17 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Deploy Lab from Archive + summary: Deploy lab from archive tags: - Labs /api/v1/ssh/sessions: get: - description: Lists active SSH sessions. For regular users, shows only their - sessions. Superusers can see all sessions by using the 'all' query parameter. + 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)' @@ -1440,12 +1491,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: List SSH Sessions + summary: List SSH sessions tags: - SSH Access /api/v1/ssh/sessions/{port}: delete: - description: Terminates a specific SSH session by port + description: Terminates a specific SSH session by port. parameters: - description: SSH session port to terminate in: path @@ -1481,15 +1532,18 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Terminate SSH Session + summary: Terminate SSH session tags: - SSH Access /api/v1/tools/certs/ca: post: consumes: - application/json - description: Creates a CA certificate and private key. Requires SUPERUSER privileges. - Files are stored in the user's ~/.clab/certs// directory on the server. + description: |- + Creates a CA certificate and private key. Requires superuser privileges. + + **Notes** + - Files are stored in the user's `~/.clab/certs//` directory on the server. parameters: - description: CA Generation Parameters in: body @@ -1522,16 +1576,18 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Create Certificate Authority (CA) + 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. Files are stored in the user's ~/.clab/certs// - directory. + 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//` directory. parameters: - description: Certificate Signing Parameters in: body @@ -1568,15 +1624,15 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Sign Certificate + summary: Sign certificate tags: - Tools - Certificates /api/v1/tools/disable-tx-offload: post: consumes: - application/json - description: Disables TX checksum offload for the eth0 interface of a specific - container. Requires SUPERUSER privileges. + description: Disables TX checksum offload on the eth0 interface of a container. + Requires superuser privileges. parameters: - description: Container Name in: body @@ -1613,15 +1669,15 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Disable TX Checksum Offload + summary: Disable TX checksum offload tags: - Tools /api/v1/tools/veth: post: consumes: - application/json - description: Creates a virtual Ethernet (vEth) pair between two specified endpoints - (container, host, bridge, ovs-bridge). Requires SUPERUSER privileges. + 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 @@ -1654,13 +1710,13 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Create vEth Pair + summary: Create vEth pair tags: - Tools - vEth /api/v1/tools/vxlan: delete: - description: 'Deletes VxLAN tunnel interfaces matching a given prefix (default: - ''vx-''). Requires SUPERUSER privileges.' + 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 @@ -1692,14 +1748,14 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Delete VxLAN Tunnels by Prefix + 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. + redirection. Requires superuser privileges. parameters: - description: VxLAN Creation Parameters in: body @@ -1732,12 +1788,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Create VxLAN Tunnel + summary: Create VxLAN tunnel tags: - Tools - VxLAN /api/v1/users: get: - description: Get a list of all users in the system. Requires superuser privileges. + description: Returns a list of system users. Requires superuser privileges. produces: - application/json responses: @@ -1761,13 +1817,13 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: List All Users + summary: List users tags: - Users post: consumes: - application/json - description: Create a new system user. Requires superuser privileges. + description: Creates a new system user. Requires superuser privileges. parameters: - description: User creation details in: body @@ -1804,12 +1860,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Create User + summary: Create user tags: - Users /api/v1/users/{username}: delete: - description: Delete a user from the system. Requires superuser privileges. + description: Deletes a user from the system. Requires superuser privileges. parameters: - description: Username to delete in: path @@ -1841,12 +1897,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Delete User + summary: Delete user tags: - Users get: - description: Get detailed information about a specific user. Requires superuser - privileges or the user's own account. + 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 @@ -1878,14 +1934,14 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Get User Details + summary: Get user details tags: - Users put: consumes: - application/json - description: Update information for an existing user. Requires superuser privileges - or the user's own account. + description: Updates an existing user. Requires superuser privileges or the + user's own account. parameters: - description: Username to update in: path @@ -1927,14 +1983,14 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Update User + summary: Update user tags: - Users /api/v1/users/{username}/password: put: consumes: - application/json - description: Change password for a user. Requires superuser privileges or the + description: Changes a user's password. Requires superuser privileges or the user's own account. parameters: - description: Username to change password for @@ -1977,13 +2033,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Change User Password + summary: Change user password tags: - Users /api/v1/version: get: - description: Retrieves version information about the containerlab library in - use. + description: Returns version information for the containerlab library in use. produces: - application/json responses: @@ -2001,13 +2056,14 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Get Containerlab Version + summary: Get containerlab version tags: - Version /api/v1/version/check: get: - description: This endpoint has been deprecated. Version checks are no longer - supported when using containerlab as a library. + description: |- + **Deprecated** + Version checks are not supported when containerlab runs as a library. produces: - application/json responses: @@ -2021,12 +2077,12 @@ paths: $ref: '#/definitions/models.ErrorResponse' security: - BearerAuth: [] - summary: Check for Containerlab Updates + summary: Check containerlab updates tags: - Version /health: get: - description: Returns basic health status of the API server. + description: Returns basic health status for the API server. produces: - application/json responses: @@ -2034,14 +2090,14 @@ paths: description: Basic health information schema: $ref: '#/definitions/models.HealthResponse' - summary: Get API Server Basic Health + summary: Get API server health tags: - Health /login: post: consumes: - application/json - description: Authenticate user and return JWT token + description: Authenticates a user and returns a JWT token. parameters: - description: User Credentials in: body @@ -2053,7 +2109,7 @@ paths: - application/json responses: "200": - description: OK + description: JWT token schema: $ref: '#/definitions/models.LoginResponse' "400": @@ -2068,7 +2124,7 @@ paths: description: Internal server error (PAM config?) schema: $ref: '#/definitions/models.ErrorResponse' - summary: Login + summary: Log in tags: - Auth schemes: diff --git a/example/flashpost/flashpost-collection-clab-api-server.json b/example/flashpost/flashpost-collection-clab-api-server.json index 6483a20..4ec2e1f 100644 --- a/example/flashpost/flashpost-collection-clab-api-server.json +++ b/example/flashpost/flashpost-collection-clab-api-server.json @@ -1 +1 @@ -{"app":"Flashpost","id":"85600be6-1481-49b3-b467-9d1d34ccb26f","name":"Containerlab API","version":"1.0","type":"collections","createdTime":"28-Apr-2025 15:17:38","exportedDate":"11-May-2025 10:47:37","collections":[{"id":"85600be6-1481-49b3-b467-9d1d34ccb26f","parent":"0","text":"Containerlab API","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"collection","variableId":""},"settings":{"auth":{"authType":"bearertoken","userName":"","password":"{{CLAB_API_TOKEN}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"","value":"","isChecked":false}],"tests":[{"parameter":"","action":"","expectedValue":""}]}},{"id":"01dff98a-1c15-4c75-b161-e649510d62b8","parent":"96f96610-3061-4a06-885a-52734700e2b7","text":"Get Logs","createdTime":"29-Apr-2025 11:48:29","droppable":false,"data":{"id":"01dff98a-1c15-4c75-b161-e649510d62b8","method":"get","name":"Get Logs","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/logs?tail=100&follow=false&format=plain","createdTime":"29-Apr-2025 11:48:29","treeNodeType":"request"}},{"id":"96f96610-3061-4a06-885a-52734700e2b7","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Logs","createdTime":"29-Apr-2025 11:48:17","droppable":true,"data":{"id":"96f96610-3061-4a06-885a-52734700e2b7","name":"Logs","createdTime":"29-Apr-2025 11:48:17","data":{},"treeNodeType":"folder"},"relativeIndex":10},{"id":"6ae6cd36-4378-40fc-91ce-6b02fcbf48a6","parent":"8628cca9-e708-4432-8703-c87d570f9f2c","text":"Generate Topology","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"469e1fb5-3cee-44bf-a7f1-8a347660eda5","method":"post","name":"Generate Topology","url":"{{baseUrl}}/api/v1/generate","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"8628cca9-e708-4432-8703-c87d570f9f2c","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Topology Generation","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":12},{"id":"07c915e4-5ac3-4b5d-b4b4-b1585c9a1e66","parent":"31e85d23-981b-40d5-be58-7a2ae5d6bb45","text":"Get Detailed System Metrics","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"1e5de0ea-2f96-4213-91ac-ceee3b377fd2","method":"get","name":"Get Detailed System Metrics","url":"{{baseUrl}}/api/v1/health/metrics","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"2f778f28-29da-4c60-bfc7-aed9bae2cae2","parent":"31e85d23-981b-40d5-be58-7a2ae5d6bb45","text":"Get API Server Basic Health","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"ec4fc060-d57c-44f5-a1cb-21f1c14f7713","method":"get","name":"Get API Server Basic Health","url":"{{baseUrl}}/health","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"31e85d23-981b-40d5-be58-7a2ae5d6bb45","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Health","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":11},{"id":"41b4b897-fd14-4476-a25e-0fb379f48fe8","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Deploy Lab (URL)","createdTime":"11-May-2025 09:47:06","droppable":false,"data":{"id":"41b4b897-fd14-4476-a25e-0fb379f48fe8","method":"post","name":"Deploy Lab (URL)","url":"{{baseUrl}}/api/v1/labs?reconfigure=true","createdTime":"11-May-2025 09:47:06","treeNodeType":"request"},"relativeIndex":7},{"id":"ca8d5092-a70f-4afb-9b9f-001c3285fe6e","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Redeploy Lab","createdTime":"29-Apr-2025 09:22:19","droppable":false,"data":{"id":"e5984782-5a82-4a7f-947d-8bbf33a4bde2","method":"put","name":"Redeploy Lab","url":"{{baseUrl}}/api/v1/labs/:labName?cleanup=true","createdTime":"29-Apr-2025 09:22:19","treeNodeType":"request"},"relativeIndex":10},{"id":"6009aaf8-97e0-4892-aa89-05b9eda3fb85","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"List All Labs","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"c58ce6dc-0bc3-4425-b751-a33d6d7f7a1f","method":"get","name":"List All Labs","url":"{{baseUrl}}/api/v1/labs","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":8},{"id":"9f71ff87-b6e6-4925-9b93-f16f11a053b3","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Deploy Lab","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"4d1f24fa-4c23-4806-92b0-ebbf1aa42ef2","method":"post","name":"Deploy Lab","url":"{{baseUrl}}/api/v1/labs?reconfigure=true","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":5},{"id":"292bb674-0a9b-4d40-9695-facb5dea38c0","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Destroy Lab","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"23f73c4b-53c8-4380-a5f3-a65d427c1f62","method":"delete","name":"Destroy Lab","url":"{{baseUrl}}/api/v1/labs/:labName?cleanup=true","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":4},{"id":"12d26a82-6948-4fd5-bd1c-aa19dbf60e55","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Inspect Lab","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"ba484950-5a1b-43e0-ac12-a86b321de1af","method":"get","name":"Inspect Lab","url":"{{baseUrl}}/api/v1/labs/:labName?details=true","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":3},{"id":"8bda0375-3781-4e9e-a783-21c0a4e721c5","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Execute Command in Lab","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"d5efc3df-0eeb-44b5-a1ba-bbe349d58f51","method":"post","name":"Execute Command in Lab","url":"{{baseUrl}}/api/v1/labs/:labName/exec","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":2},{"id":"4fbdb932-d9c7-45fb-98b5-c65c92544704","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"List Lab Interfaces","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"edfa56bc-db32-4c51-a6cf-a3b38da90750","method":"get","name":"List Lab Interfaces","url":"{{baseUrl}}/api/v1/labs/:labName/interfaces","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":1},{"id":"c24f5aa2-f446-4663-8342-9824510c1291","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Save Lab Configuration","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"b0913afc-f70a-4ad4-9ace-886a4152bbee","method":"post","name":"Save Lab Configuration","url":"{{baseUrl}}/api/v1/labs/:labName/save","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"6219e4a2-2b0f-4b62-a61a-178432cfcbf3","parent":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","text":"Deploy Lab from Archive","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"eb18e90d-fe93-4e72-8095-2e023169e662","method":"post","name":"Deploy Lab from Archive","url":"{{baseUrl}}/api/v1/labs/archive?labName=enim sunt labore&reconfigure=true&maxWorkers=54508974&exportTemplate=enim sunt labore&nodeFilter=enim sunt labore&skipPostDeploy=true&skipLabdirAcl=true","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":-1},{"id":"d348b203-cd46-4078-8c6c-3d3ca0e0c655","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Labs","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":8},{"id":"ea7a604b-c23d-4bda-9eca-04a2cf9dbd80","parent":"711e27d1-0878-4ea7-91f5-5824aa7a3370","text":"Reset Network Emulation","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"02716ba1-0379-4321-a05e-70ffed7d46ae","method":"delete","name":"Reset Network Emulation","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/interfaces/:interfaceName/netem","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"6f405047-cb70-4afd-ac5d-57366d67eecb","parent":"711e27d1-0878-4ea7-91f5-5824aa7a3370","text":"Set Network Emulation","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"5368aef7-ad51-4648-8746-9818aaf5a165","method":"put","name":"Set Network Emulation","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/interfaces/:interfaceName/netem","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"c8a4080e-4438-47bb-9ea2-bd0a682fb1cf","parent":"711e27d1-0878-4ea7-91f5-5824aa7a3370","text":"Show Network Emulation","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"60bfc4f2-9ec0-4158-8c72-3a299c93f915","method":"get","name":"Show Network Emulation","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/netem","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"711e27d1-0878-4ea7-91f5-5824aa7a3370","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Tools - Netem","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":7},{"id":"10881948-058d-4105-8c7d-439dde46add6","parent":"01fa16e3-c76b-4d78-bc91-e0f4cef28363","text":"Request SSH Access to Lab Node","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"4968e505-e207-416d-95b6-4ddfc1745b46","method":"post","name":"Request SSH Access to Lab Node","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/ssh","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"477c3ae1-d29e-4e19-84cf-e8c272956e2b","parent":"01fa16e3-c76b-4d78-bc91-e0f4cef28363","text":"List SSH Sessions","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"9171f785-a1cd-4147-b26a-f4fc75faa788","method":"get","name":"List SSH Sessions","url":"{{baseUrl}}/api/v1/ssh/sessions","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"a182a781-6762-4193-b4a7-295fa2649b69","parent":"01fa16e3-c76b-4d78-bc91-e0f4cef28363","text":"Terminate SSH Session","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"d138c114-7563-4d07-8f9d-8b47d0464deb","method":"delete","name":"Terminate SSH Session","url":"{{baseUrl}}/api/v1/ssh/sessions/:port","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"01fa16e3-c76b-4d78-bc91-e0f4cef28363","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"SSH Access","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":6},{"id":"bade1852-e968-4f54-803f-97eb76afaf5b","parent":"5fa47372-1d3d-4b20-9da9-5632815a3e38","text":"Create Certificate Authority (CA)","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"ac32ff96-b9a9-4120-b35f-e9573a92ef06","method":"post","name":"Create Certificate Authority (CA)","url":"{{baseUrl}}/api/v1/tools/certs/ca","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"94ba0d9b-8267-42a8-95b9-d4d977cf027b","parent":"5fa47372-1d3d-4b20-9da9-5632815a3e38","text":"Sign Certificate","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"075f2e40-685c-431a-b04f-f5eda9fe4cb3","method":"post","name":"Sign Certificate","url":"{{baseUrl}}/api/v1/tools/certs/sign","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"5fa47372-1d3d-4b20-9da9-5632815a3e38","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Tools - Certificates","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":5},{"id":"5bef21f3-f6fe-4781-b73d-1aee92d13e83","parent":"5d424006-ea73-4e5b-9fd3-c17503e83f7b","text":"Disable TX Checksum Offload","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"96f4abdb-5d88-442c-9136-c2e29d58c3d2","method":"post","name":"Disable TX Checksum Offload","url":"{{baseUrl}}/api/v1/tools/disable-tx-offload","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"5d424006-ea73-4e5b-9fd3-c17503e83f7b","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Tools","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":4},{"id":"1a1d51e0-cd0d-4813-96dc-6317af203172","parent":"0bf332d1-4bd6-4074-aab0-1b1c3e43673d","text":"Create vEth Pair","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"929ed3c3-a81a-40ef-adff-e7fd98afa6d8","method":"post","name":"Create vEth Pair","url":"{{baseUrl}}/api/v1/tools/veth","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"0bf332d1-4bd6-4074-aab0-1b1c3e43673d","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Tools - vEth","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":3},{"id":"181b6ae2-b8dd-4c42-adb4-5e79c381282d","parent":"c980becd-308f-47d1-a59c-e49ef6945b87","text":"Delete VxLAN Tunnels by Prefix","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"d62449fd-9eed-4c3a-9bf1-ac7a5deaa9dd","method":"delete","name":"Delete VxLAN Tunnels by Prefix","url":"{{baseUrl}}/api/v1/tools/vxlan?prefix=vx-","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"0f3efed3-4287-4c29-b95a-7fe476cd5cb3","parent":"c980becd-308f-47d1-a59c-e49ef6945b87","text":"Create VxLAN Tunnel","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"12c83db2-d5cb-40fd-8765-eed9e88e69ef","method":"post","name":"Create VxLAN Tunnel","url":"{{baseUrl}}/api/v1/tools/vxlan","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"c980becd-308f-47d1-a59c-e49ef6945b87","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Tools - VxLAN","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":2},{"id":"e5aaff86-f946-4c03-826f-21803ef9ac68","parent":"6a525308-3084-424e-8d61-1e193a474439","text":"List All Users","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"af299ac5-f652-416c-8f56-506a27ff319c","method":"get","name":"List All Users","url":"{{baseUrl}}/api/v1/users","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"0e1b6cc2-0d1e-45dd-beac-9d5e09e26d56","parent":"6a525308-3084-424e-8d61-1e193a474439","text":"Create User","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"aeb4093c-7968-49f4-a3c1-281b17752593","method":"post","name":"Create User","url":"{{baseUrl}}/api/v1/users","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"446c15ac-7566-4376-8b6a-9c6897ee31e3","parent":"6a525308-3084-424e-8d61-1e193a474439","text":"Delete User","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"b058495d-3907-4775-9238-3da6ca29d196","method":"delete","name":"Delete User","url":"{{baseUrl}}/api/v1/users/testuser_44h89","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"63f39a55-f36c-48c8-8494-85ace4953aa7","parent":"6a525308-3084-424e-8d61-1e193a474439","text":"Get User Details","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"ab4c026d-ef46-4e92-b963-6dea7633a7e8","method":"get","name":"Get User Details","url":"{{baseUrl}}/api/v1/users/test","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"5dc6d6f6-d0f3-44b0-8b3b-528134efa5cb","parent":"6a525308-3084-424e-8d61-1e193a474439","text":"Update User","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"6b02099d-6dee-4c40-be94-ba73edb2ceba","method":"put","name":"Update User","url":"{{baseUrl}}/api/v1/users/test","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"4415b59e-c577-426a-b554-f3953c77aacf","parent":"6a525308-3084-424e-8d61-1e193a474439","text":"Change User Password","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"675a9fae-4117-4061-835c-77f7da7d47e5","method":"put","name":"Change User Password","url":"{{baseUrl}}/api/v1/users/test/password","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"6a525308-3084-424e-8d61-1e193a474439","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Users","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":1},{"id":"2f1920a6-6946-4f56-b0a2-d072117c9696","parent":"4ecd6094-1e27-424b-aae3-5853d809143a","text":"Get Containerlab Version","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"7d52e864-74b9-4c1f-aa22-593f1d1b9abb","method":"get","name":"Get Containerlab Version","url":"{{baseUrl}}/api/v1/version","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"fab7c8d0-0e3c-4b47-a20c-bda6dd0d778a","parent":"4ecd6094-1e27-424b-aae3-5853d809143a","text":"Check for Containerlab Updates","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"0b288439-c259-463e-bfaf-2a313fe81b70","method":"get","name":"Check for Containerlab Updates","url":"{{baseUrl}}/api/v1/version/check","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"4ecd6094-1e27-424b-aae3-5853d809143a","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Version","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":0},{"id":"4a0cebe4-3383-4fac-87c6-b3c5430f83f6","parent":"4d7ff5f3-5dfb-4986-9240-95178088fafd","text":"Login","createdTime":"28-Apr-2025 15:17:38","droppable":false,"data":{"id":"01011935-a860-4225-b712-a44e0c3436d4","method":"post","name":"Login","url":"{{baseUrl}}/login","createdTime":"28-Apr-2025 15:17:38","treeNodeType":"request"},"relativeIndex":0},{"id":"4d7ff5f3-5dfb-4986-9240-95178088fafd","parent":"85600be6-1481-49b3-b467-9d1d34ccb26f","text":"Auth","createdTime":"28-Apr-2025 15:17:38","droppable":true,"data":{"treeNodeType":"folder"},"relativeIndex":-1}],"requests":[{"id":"01dff98a-1c15-4c75-b161-e649510d62b8","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/logs?tail=100&follow=false&format=plain","name":"Get Logs","createdTime":"29-Apr-2025 11:48:29","method":"get","params":[{"isChecked":true,"key":"tail","value":"100"},{"isChecked":true,"key":"follow","value":"false"},{"isChecked":true,"key":"format","value":"plain"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01","index":0},{"key":"nodeName","value":"clab-srl01-srl1","index":1}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"*/*","isChecked":true},{"key":"User-Agent","value":"Flashpost","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":"","selectedEnvironmentId":""},{"id":"6ae6cd36-4378-40fc-91ce-6b02fcbf48a6","url":"{{baseUrl}}/api/v1/generate","name":"Generate Topology","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"name\": \"3-tier-clos\",\n \"tiers\": [\n {\n \"count\": 4,\n \"kind\": \"nokia_srlinux\",\n \"type\": \"ixrd3\"\n }\n ],\n \"defaultKind\": \"nokia_srlinux\",\n \"deploy\": true,\n \"groupPrefix\": \"clos-tier\",\n \"images\": {\n \"nokia_srlinux\": \"ghcr.io/nokia/srlinux:latest\"\n },\n \"managementNetwork\": \"clos-mgmt\",\n \"nodePrefix\": \"clos-node\",\n \"outputFile\": \"clos.yml\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"07c915e4-5ac3-4b5d-b4b4-b1585c9a1e66","url":"{{baseUrl}}/api/v1/health/metrics","name":"Get Detailed System Metrics","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"2f778f28-29da-4c60-bfc7-aed9bae2cae2","url":"{{baseUrl}}/health","name":"Get API Server Basic Health","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"41b4b897-fd14-4476-a25e-0fb379f48fe8","url":"{{baseUrl}}/api/v1/labs?reconfigure=true","name":"Deploy Lab (URL)","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"exportTemplate","value":"enim+sunt+labore"},{"isChecked":false,"key":"nodeFilter","value":"enim+sunt+labore"},{"isChecked":false,"key":"skipPostDeploy","value":"true"},{"isChecked":false,"key":"skipLabdirAcl","value":"true"},{"isChecked":false,"key":"maxWorkers","value":"4"},{"isChecked":true,"key":"reconfigure","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"topologySourceUrl\" : \"https://github.com/srl-labs/srlinux-vlan-handling-lab\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"ca8d5092-a70f-4afb-9b9f-001c3285fe6e","url":"{{baseUrl}}/api/v1/labs/:labName?cleanup=true","name":"Redeploy Lab","createdTime":"29-Apr-2025 09:22:19","method":"put","params":[{"isChecked":false,"key":"graceful","value":"true"},{"isChecked":false,"key":"graph","value":"true"},{"isChecked":false,"key":"network","value":"minim+ea+reprehenderit+cupidatat+amet"},{"isChecked":false,"key":"ipv4Subnet","value":"minim+ea+reprehenderit+cupidatat+amet"},{"isChecked":false,"key":"ipv6Subnet","value":"minim+ea+reprehenderit+cupidatat+amet"},{"isChecked":false,"key":"maxWorkers","value":"-88903131"},{"isChecked":false,"key":"keepMgmtNet","value":"true"},{"isChecked":false,"key":"skipPostDeploy","value":"true"},{"isChecked":false,"key":"exportTemplate","value":"minim+ea+reprehenderit+cupidatat+amet"},{"isChecked":false,"key":"skipLabdirAcl","value":"true"},{"isChecked":true,"key":"cleanup","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01","index":0}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"isChecked":true,"key":"Content-Type","value":"application/json","isFixed":false},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"6009aaf8-97e0-4892-aa89-05b9eda3fb85","url":"{{baseUrl}}/api/v1/labs","name":"List All Labs","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"9f71ff87-b6e6-4925-9b93-f16f11a053b3","url":"{{baseUrl}}/api/v1/labs?reconfigure=true","name":"Deploy Lab","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"exportTemplate","value":"enim+sunt+labore"},{"isChecked":false,"key":"nodeFilter","value":"enim+sunt+labore"},{"isChecked":false,"key":"skipPostDeploy","value":"true"},{"isChecked":false,"key":"skipLabdirAcl","value":"true"},{"isChecked":false,"key":"maxWorkers","value":"4"},{"isChecked":true,"key":"reconfigure","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"topologyContent\": {\n \"name\": \"srl01\",\n \"topology\": {\n \"kinds\": {\n \"nokia_srlinux\": {\n \"type\": \"ixrd3\",\n \"image\": \"ghcr.io/nokia/srlinux\"\n }\n },\n \"nodes\": {\n \"srl1\": {\n \"kind\": \"nokia_srlinux\"\n },\n \"srl2\": {\n \"kind\": \"nokia_srlinux\"\n }\n },\n \"links\": [\n {\n \"endpoints\": [\n \"srl1:e1-1\",\n \"srl2:e1-1\"\n ]\n }\n ]\n }\n }\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"292bb674-0a9b-4d40-9695-facb5dea38c0","url":"{{baseUrl}}/api/v1/labs/:labName?cleanup=true","name":"Destroy Lab","createdTime":"28-Apr-2025 15:17:38","method":"delete","params":[{"isChecked":false,"key":"graceful","value":"true"},{"isChecked":false,"key":"keepMgmtNet","value":"true"},{"isChecked":false,"key":"nodeFilter","value":"enim+sunt+labore"},{"isChecked":true,"key":"cleanup","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01","index":0}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"12d26a82-6948-4fd5-bd1c-aa19dbf60e55","url":"{{baseUrl}}/api/v1/labs/:labName?details=true","name":"Inspect Lab","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":true,"key":"details","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01","index":0}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"8bda0375-3781-4e9e-a783-21c0a4e721c5","url":"{{baseUrl}}/api/v1/labs/:labName/exec","name":"Execute Command in Lab","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"nodeFilter","value":"enim sunt labore"},{"isChecked":false,"key":"format","value":"enim+sunt+labore"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"command\": \"ip addr show eth1\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"4fbdb932-d9c7-45fb-98b5-c65c92544704","url":"{{baseUrl}}/api/v1/labs/:labName/interfaces","name":"List Lab Interfaces","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"node","value":"enim sunt labore"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01","index":0}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"c24f5aa2-f446-4663-8342-9824510c1291","url":"{{baseUrl}}/api/v1/labs/:labName/save","name":"Save Lab Configuration","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"nodeFilter","value":"enim sunt labore"},{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"6219e4a2-2b0f-4b62-a61a-178432cfcbf3","url":"{{baseUrl}}/api/v1/labs/archive?labName=enim sunt labore&reconfigure=true&maxWorkers=54508974&exportTemplate=enim sunt labore&nodeFilter=enim sunt labore&skipPostDeploy=true&skipLabdirAcl=true","name":"Deploy Lab from Archive","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":true,"key":"labName","value":"enim sunt labore"},{"isChecked":true,"key":"reconfigure","value":"true"},{"isChecked":true,"key":"maxWorkers","value":"54508974"},{"isChecked":true,"key":"exportTemplate","value":"enim sunt labore"},{"isChecked":true,"key":"nodeFilter","value":"enim sunt labore"},{"isChecked":true,"key":"skipPostDeploy","value":"true"},{"isChecked":true,"key":"skipLabdirAcl","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"apikey","userName":"Authorization","password":"{{apiKey}}","addTo":"header","showPwd":false,"tokenPrefix":"","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""},"oauth2":{"grantType":"client_credentials","tokenPrefix":"","tokenValue":"","tokenUrl":"","clientId":"","clientSecret":"","scope":"","clientAuth":"in-header"}},"headers":[{"key":"Content-Type","value":"multipart/form-data","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"formdata","formdata":[{"key":"labArchive","type":"File","isChecked":false}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"ea7a604b-c23d-4bda-9eca-04a2cf9dbd80","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/interfaces/:interfaceName/netem","name":"Reset Network Emulation","createdTime":"28-Apr-2025 15:17:38","method":"delete","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01"},{"key":"nodeName","value":"clab-srl01-srl1"},{"key":"interfaceName","value":"e1-1"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"6f405047-cb70-4afd-ac5d-57366d67eecb","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/interfaces/:interfaceName/netem","name":"Set Network Emulation","createdTime":"28-Apr-2025 15:17:38","method":"put","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01"},{"key":"nodeName","value":"clab-srl01-srl1"},{"key":"interfaceName","value":"e1-1"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"corruption\": 0.1,\n \"delay\": \"50ms\",\n \"jitter\": \"5ms\",\n \"loss\": 10.5,\n \"rate\": 1000\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"c8a4080e-4438-47bb-9ea2-bd0a682fb1cf","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/netem","name":"Show Network Emulation","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01"},{"key":"nodeName","value":"clab-srl01-srl1"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"10881948-058d-4105-8c7d-439dde46add6","url":"{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/ssh","name":"Request SSH Access to Lab Node","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"labName","value":"srl01"},{"key":"nodeName","value":"clab-srl01-srl1"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"duration\": \"60m\",\n \"sshUsername\": \"admin\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"477c3ae1-d29e-4e19-84cf-e8c272956e2b","url":"{{baseUrl}}/api/v1/ssh/sessions","name":"List SSH Sessions","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"all","value":"true"},{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"a182a781-6762-4193-b4a7-295fa2649b69","url":"{{baseUrl}}/api/v1/ssh/sessions/:port","name":"Terminate SSH Session","createdTime":"28-Apr-2025 15:17:38","method":"delete","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[{"key":"port","value":"2223"}],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"bade1852-e968-4f54-803f-97eb76afaf5b","url":"{{baseUrl}}/api/v1/tools/certs/ca","name":"Create Certificate Authority (CA)","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"commonName\": \"ca.example.com\",\n \"country\": \"US\",\n \"expiry\": \"8760h\",\n \"locality\": \"City\",\n \"name\": \"my-root-ca\",\n \"orgUnit\": \"IT\",\n \"organization\": \"MyOrg\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"94ba0d9b-8267-42a8-95b9-d4d977cf027b","url":"{{baseUrl}}/api/v1/tools/certs/sign","name":"Sign Certificate","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"caName\": \"my-root-ca\",\n \"hosts\": [\n \"localhost\"\n ],\n \"name\": \"node1.example.com\",\n \"commonName\": \"node1.example.com\",\n \"country\": \"US\",\n \"keySize\": 4096,\n \"locality\": \"City\",\n \"orgUnit\": \"Nodes\",\n \"organization\": \"MyOrg\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"5bef21f3-f6fe-4781-b73d-1aee92d13e83","url":"{{baseUrl}}/api/v1/tools/disable-tx-offload","name":"Disable TX Checksum Offload","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"containerName\": \"srl01-srl1\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"1a1d51e0-cd0d-4813-96dc-6317af203172","url":"{{baseUrl}}/api/v1/tools/veth","name":"Create vEth Pair","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"aEndpoint\": \"clab-srl01-srl1:eth1\",\n \"bEndpoint\": \"clab-srl01-srl2:eth1\",\n \"mtu\": 1500\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"181b6ae2-b8dd-4c42-adb4-5e79c381282d","url":"{{baseUrl}}/api/v1/tools/vxlan?prefix=vx-","name":"Delete VxLAN Tunnels by Prefix","createdTime":"28-Apr-2025 15:17:38","method":"delete","params":[{"isChecked":true,"key":"prefix","value":"vx-"},{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"apikey","userName":"Authorization","password":"{{apiKey}}","addTo":"header","showPwd":false,"tokenPrefix":"","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""},"oauth2":{"grantType":"client_credentials","tokenPrefix":"","tokenValue":"","tokenUrl":"","clientId":"","clientSecret":"","scope":"","clientAuth":"in-header"}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"0f3efed3-4287-4c29-b95a-7fe476cd5cb3","url":"{{baseUrl}}/api/v1/tools/vxlan","name":"Create VxLAN Tunnel","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"link\": \"srl_e1-1\",\n \"remote\": \"10.0.0.20\",\n \"dev\": \"eth0\",\n \"id\": 100,\n \"mtu\": 1400,\n \"port\": 4789\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"e5aaff86-f946-4c03-826f-21803ef9ac68","url":"{{baseUrl}}/api/v1/users","name":"List All Users","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"0e1b6cc2-0d1e-45dd-beac-9d5e09e26d56","url":"{{baseUrl}}/api/v1/users","name":"Create User","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"password\": \"test\",\n \"username\": \"test\",\n \"displayName\": \"test\",\n \"groups\": [\n \"clab_admins\"\n ],\n \"isSuperuser\": false\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"446c15ac-7566-4376-8b6a-9c6897ee31e3","url":"{{baseUrl}}/api/v1/users/testuser_44h89","name":"Delete User","createdTime":"28-Apr-2025 15:17:38","method":"delete","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"63f39a55-f36c-48c8-8494-85ace4953aa7","url":"{{baseUrl}}/api/v1/users/test","name":"Get User Details","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"5dc6d6f6-d0f3-44b0-8b3b-528134efa5cb","url":"{{baseUrl}}/api/v1/users/test","name":"Update User","createdTime":"28-Apr-2025 15:17:38","method":"put","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"displayName\": \"test\",\n \"groups\": [\n \"clab_api\"\n ],\n \"isSuperuser\": false\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"4415b59e-c577-426a-b554-f3953c77aacf","url":"{{baseUrl}}/api/v1/users/test/password","name":"Change User Password","createdTime":"28-Apr-2025 15:17:38","method":"put","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"newPassword\": \"fugiat elit nostrud\",\n \"currentPassword\": \"sit dolor est ipsum\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"2f1920a6-6946-4f56-b0a2-d072117c9696","url":"{{baseUrl}}/api/v1/version","name":"Get Containerlab Version","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"fab7c8d0-0e3c-4b47-a20c-bda6dd0d778a","url":"{{baseUrl}}/api/v1/version/check","name":"Check for Containerlab Updates","createdTime":"28-Apr-2025 15:17:38","method":"get","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"bearertoken","userName":"","password":"{{apiKey}}","addTo":"queryparams","showPwd":false,"tokenPrefix":"Bearer","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""}},"headers":[{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"none","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"","key":"","variableName":""}],"notes":""},{"id":"4a0cebe4-3383-4fac-87c6-b3c5430f83f6","url":"{{baseUrl}}/login","name":"Login","createdTime":"28-Apr-2025 15:17:38","method":"post","params":[{"isChecked":false,"key":"","value":""}],"pathParams":[],"auth":{"authType":"inherit","userName":"","password":"","addTo":"queryparams","showPwd":false,"tokenPrefix":"","aws":{"service":"","region":"","accessKey":"","secretAccessKey":"","sessionToken":""},"oauth2":{"grantType":"client_credentials","tokenPrefix":"","tokenValue":"","tokenUrl":"","clientId":"","clientSecret":"","scope":"","clientAuth":"in-header"}},"headers":[{"key":"Content-Type","value":"application/json","isChecked":true},{"key":"Accept","value":"application/json","isChecked":true},{"key":"","value":"","isChecked":false}],"body":{"bodyType":"raw","formdata":[{"isChecked":false,"key":"","value":""}],"urlencoded":[{"isChecked":false,"key":"","value":""}],"raw":{"data":"{\n \"username\": \"{{USER_NAME}}\",\n \"password\": \"{{USER_PASSWORD}}\"\n}","lang":"json"},"binary":{"fileName":"","data":{},"contentTypeOption":"manual"},"graphql":{"query":"","variables":""}},"tests":[{"parameter":"","action":"","expectedValue":""}],"setvar":[{"parameter":"JSON","key":"token","variableName":"apiKey"},{"parameter":"","key":"","variableName":""}],"notes":""}]} \ No newline at end of file +{"app": "Flashpost", "id": "85600be6-1481-49b3-b467-9d1d34ccb26f", "name": "Containerlab API", "version": "1.0", "type": "collections", "createdTime": "28-Apr-2025 15:17:38", "exportedDate": "11-May-2025 10:47:37", "collections": [{"id": "85600be6-1481-49b3-b467-9d1d34ccb26f", "parent": "0", "text": "Containerlab API", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "collection", "variableId": ""}, "settings": {"auth": {"authType": "bearertoken", "userName": "", "password": "{{CLAB_API_TOKEN}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "", "value": "", "isChecked": false}], "tests": [{"parameter": "", "action": "", "expectedValue": ""}]}}, {"id": "01dff98a-1c15-4c75-b161-e649510d62b8", "parent": "96f96610-3061-4a06-885a-52734700e2b7", "text": "Get Logs", "createdTime": "29-Apr-2025 11:48:29", "droppable": false, "data": {"id": "01dff98a-1c15-4c75-b161-e649510d62b8", "method": "get", "name": "Get Logs", "url": "{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/logs?tail=100&follow=false", "createdTime": "29-Apr-2025 11:48:29", "treeNodeType": "request"}}, {"id": "96f96610-3061-4a06-885a-52734700e2b7", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Logs", "createdTime": "29-Apr-2025 11:48:17", "droppable": true, "data": {"id": "96f96610-3061-4a06-885a-52734700e2b7", "name": "Logs", "createdTime": "29-Apr-2025 11:48:17", "data": {}, "treeNodeType": "folder"}, "relativeIndex": 10}, {"id": "6ae6cd36-4378-40fc-91ce-6b02fcbf48a6", "parent": "8628cca9-e708-4432-8703-c87d570f9f2c", "text": "Generate Topology", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "469e1fb5-3cee-44bf-a7f1-8a347660eda5", "method": "post", "name": "Generate Topology", "url": "{{baseUrl}}/api/v1/generate", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "8628cca9-e708-4432-8703-c87d570f9f2c", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Topology Generation", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 12}, {"id": "07c915e4-5ac3-4b5d-b4b4-b1585c9a1e66", "parent": "31e85d23-981b-40d5-be58-7a2ae5d6bb45", "text": "Get Detailed System Metrics", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "1e5de0ea-2f96-4213-91ac-ceee3b377fd2", "method": "get", "name": "Get Detailed System Metrics", "url": "{{baseUrl}}/api/v1/health/metrics", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "2f778f28-29da-4c60-bfc7-aed9bae2cae2", "parent": "31e85d23-981b-40d5-be58-7a2ae5d6bb45", "text": "Get API Server Basic Health", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "ec4fc060-d57c-44f5-a1cb-21f1c14f7713", "method": "get", "name": "Get API Server Basic Health", "url": "{{baseUrl}}/health", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "31e85d23-981b-40d5-be58-7a2ae5d6bb45", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Health", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 11}, {"id": "41b4b897-fd14-4476-a25e-0fb379f48fe8", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Deploy Lab (URL)", "createdTime": "11-May-2025 09:47:06", "droppable": false, "data": {"id": "41b4b897-fd14-4476-a25e-0fb379f48fe8", "method": "post", "name": "Deploy Lab (URL)", "url": "{{baseUrl}}/api/v1/labs?reconfigure=true", "createdTime": "11-May-2025 09:47:06", "treeNodeType": "request"}, "relativeIndex": 7}, {"id": "ca8d5092-a70f-4afb-9b9f-001c3285fe6e", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Redeploy Lab", "createdTime": "29-Apr-2025 09:22:19", "droppable": false, "data": {"id": "e5984782-5a82-4a7f-947d-8bbf33a4bde2", "method": "put", "name": "Redeploy Lab", "url": "{{baseUrl}}/api/v1/labs/:labName?cleanup=true", "createdTime": "29-Apr-2025 09:22:19", "treeNodeType": "request"}, "relativeIndex": 10}, {"id": "6009aaf8-97e0-4892-aa89-05b9eda3fb85", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "List All Labs", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "c58ce6dc-0bc3-4425-b751-a33d6d7f7a1f", "method": "get", "name": "List All Labs", "url": "{{baseUrl}}/api/v1/labs", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 8}, {"id": "9f71ff87-b6e6-4925-9b93-f16f11a053b3", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Deploy Lab", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "4d1f24fa-4c23-4806-92b0-ebbf1aa42ef2", "method": "post", "name": "Deploy Lab", "url": "{{baseUrl}}/api/v1/labs?reconfigure=true", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 5}, {"id": "292bb674-0a9b-4d40-9695-facb5dea38c0", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Destroy Lab", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "23f73c4b-53c8-4380-a5f3-a65d427c1f62", "method": "delete", "name": "Destroy Lab", "url": "{{baseUrl}}/api/v1/labs/:labName?cleanup=true", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 4}, {"id": "12d26a82-6948-4fd5-bd1c-aa19dbf60e55", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Inspect Lab", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "ba484950-5a1b-43e0-ac12-a86b321de1af", "method": "get", "name": "Inspect Lab", "url": "{{baseUrl}}/api/v1/labs/:labName", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 3}, {"id": "8bda0375-3781-4e9e-a783-21c0a4e721c5", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Execute Command in Lab", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "d5efc3df-0eeb-44b5-a1ba-bbe349d58f51", "method": "post", "name": "Execute Command in Lab", "url": "{{baseUrl}}/api/v1/labs/:labName/exec", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 2}, {"id": "4fbdb932-d9c7-45fb-98b5-c65c92544704", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "List Lab Interfaces", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "edfa56bc-db32-4c51-a6cf-a3b38da90750", "method": "get", "name": "List Lab Interfaces", "url": "{{baseUrl}}/api/v1/labs/:labName/interfaces", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 1}, {"id": "c24f5aa2-f446-4663-8342-9824510c1291", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Save Lab Configuration", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "b0913afc-f70a-4ad4-9ace-886a4152bbee", "method": "post", "name": "Save Lab Configuration", "url": "{{baseUrl}}/api/v1/labs/:labName/save", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "6219e4a2-2b0f-4b62-a61a-178432cfcbf3", "parent": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "text": "Deploy Lab from Archive", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "eb18e90d-fe93-4e72-8095-2e023169e662", "method": "post", "name": "Deploy Lab from Archive", "url": "{{baseUrl}}/api/v1/labs/archive?labName=enim sunt labore&reconfigure=true&maxWorkers=54508974&exportTemplate=enim sunt labore&nodeFilter=enim sunt labore&skipPostDeploy=true&skipLabdirAcl=true", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": -1}, {"id": "d348b203-cd46-4078-8c6c-3d3ca0e0c655", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Labs", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 8}, {"id": "10881948-058d-4105-8c7d-439dde46add6", "parent": "01fa16e3-c76b-4d78-bc91-e0f4cef28363", "text": "Request SSH Access to Lab Node", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "4968e505-e207-416d-95b6-4ddfc1745b46", "method": "post", "name": "Request SSH Access to Lab Node", "url": "{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/ssh", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "477c3ae1-d29e-4e19-84cf-e8c272956e2b", "parent": "01fa16e3-c76b-4d78-bc91-e0f4cef28363", "text": "List SSH Sessions", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "9171f785-a1cd-4147-b26a-f4fc75faa788", "method": "get", "name": "List SSH Sessions", "url": "{{baseUrl}}/api/v1/ssh/sessions", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "a182a781-6762-4193-b4a7-295fa2649b69", "parent": "01fa16e3-c76b-4d78-bc91-e0f4cef28363", "text": "Terminate SSH Session", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "d138c114-7563-4d07-8f9d-8b47d0464deb", "method": "delete", "name": "Terminate SSH Session", "url": "{{baseUrl}}/api/v1/ssh/sessions/:port", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "01fa16e3-c76b-4d78-bc91-e0f4cef28363", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "SSH Access", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 6}, {"id": "bade1852-e968-4f54-803f-97eb76afaf5b", "parent": "5fa47372-1d3d-4b20-9da9-5632815a3e38", "text": "Create Certificate Authority (CA)", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "ac32ff96-b9a9-4120-b35f-e9573a92ef06", "method": "post", "name": "Create Certificate Authority (CA)", "url": "{{baseUrl}}/api/v1/tools/certs/ca", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "94ba0d9b-8267-42a8-95b9-d4d977cf027b", "parent": "5fa47372-1d3d-4b20-9da9-5632815a3e38", "text": "Sign Certificate", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "075f2e40-685c-431a-b04f-f5eda9fe4cb3", "method": "post", "name": "Sign Certificate", "url": "{{baseUrl}}/api/v1/tools/certs/sign", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "5fa47372-1d3d-4b20-9da9-5632815a3e38", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Tools - Certificates", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 5}, {"id": "5bef21f3-f6fe-4781-b73d-1aee92d13e83", "parent": "5d424006-ea73-4e5b-9fd3-c17503e83f7b", "text": "Disable TX Checksum Offload", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "96f4abdb-5d88-442c-9136-c2e29d58c3d2", "method": "post", "name": "Disable TX Checksum Offload", "url": "{{baseUrl}}/api/v1/tools/disable-tx-offload", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "5d424006-ea73-4e5b-9fd3-c17503e83f7b", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Tools", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 4}, {"id": "1a1d51e0-cd0d-4813-96dc-6317af203172", "parent": "0bf332d1-4bd6-4074-aab0-1b1c3e43673d", "text": "Create vEth Pair", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "929ed3c3-a81a-40ef-adff-e7fd98afa6d8", "method": "post", "name": "Create vEth Pair", "url": "{{baseUrl}}/api/v1/tools/veth", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "0bf332d1-4bd6-4074-aab0-1b1c3e43673d", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Tools - vEth", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 3}, {"id": "181b6ae2-b8dd-4c42-adb4-5e79c381282d", "parent": "c980becd-308f-47d1-a59c-e49ef6945b87", "text": "Delete VxLAN Tunnels by Prefix", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "d62449fd-9eed-4c3a-9bf1-ac7a5deaa9dd", "method": "delete", "name": "Delete VxLAN Tunnels by Prefix", "url": "{{baseUrl}}/api/v1/tools/vxlan?prefix=vx-", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "0f3efed3-4287-4c29-b95a-7fe476cd5cb3", "parent": "c980becd-308f-47d1-a59c-e49ef6945b87", "text": "Create VxLAN Tunnel", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "12c83db2-d5cb-40fd-8765-eed9e88e69ef", "method": "post", "name": "Create VxLAN Tunnel", "url": "{{baseUrl}}/api/v1/tools/vxlan", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "c980becd-308f-47d1-a59c-e49ef6945b87", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Tools - VxLAN", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 2}, {"id": "e5aaff86-f946-4c03-826f-21803ef9ac68", "parent": "6a525308-3084-424e-8d61-1e193a474439", "text": "List All Users", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "af299ac5-f652-416c-8f56-506a27ff319c", "method": "get", "name": "List All Users", "url": "{{baseUrl}}/api/v1/users", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "0e1b6cc2-0d1e-45dd-beac-9d5e09e26d56", "parent": "6a525308-3084-424e-8d61-1e193a474439", "text": "Create User", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "aeb4093c-7968-49f4-a3c1-281b17752593", "method": "post", "name": "Create User", "url": "{{baseUrl}}/api/v1/users", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "446c15ac-7566-4376-8b6a-9c6897ee31e3", "parent": "6a525308-3084-424e-8d61-1e193a474439", "text": "Delete User", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "b058495d-3907-4775-9238-3da6ca29d196", "method": "delete", "name": "Delete User", "url": "{{baseUrl}}/api/v1/users/testuser_44h89", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "63f39a55-f36c-48c8-8494-85ace4953aa7", "parent": "6a525308-3084-424e-8d61-1e193a474439", "text": "Get User Details", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "ab4c026d-ef46-4e92-b963-6dea7633a7e8", "method": "get", "name": "Get User Details", "url": "{{baseUrl}}/api/v1/users/test", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "5dc6d6f6-d0f3-44b0-8b3b-528134efa5cb", "parent": "6a525308-3084-424e-8d61-1e193a474439", "text": "Update User", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "6b02099d-6dee-4c40-be94-ba73edb2ceba", "method": "put", "name": "Update User", "url": "{{baseUrl}}/api/v1/users/test", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "4415b59e-c577-426a-b554-f3953c77aacf", "parent": "6a525308-3084-424e-8d61-1e193a474439", "text": "Change User Password", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "675a9fae-4117-4061-835c-77f7da7d47e5", "method": "put", "name": "Change User Password", "url": "{{baseUrl}}/api/v1/users/test/password", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "6a525308-3084-424e-8d61-1e193a474439", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Users", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 1}, {"id": "2f1920a6-6946-4f56-b0a2-d072117c9696", "parent": "4ecd6094-1e27-424b-aae3-5853d809143a", "text": "Get Containerlab Version", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "7d52e864-74b9-4c1f-aa22-593f1d1b9abb", "method": "get", "name": "Get Containerlab Version", "url": "{{baseUrl}}/api/v1/version", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "fab7c8d0-0e3c-4b47-a20c-bda6dd0d778a", "parent": "4ecd6094-1e27-424b-aae3-5853d809143a", "text": "Check for Containerlab Updates", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "0b288439-c259-463e-bfaf-2a313fe81b70", "method": "get", "name": "Check for Containerlab Updates", "url": "{{baseUrl}}/api/v1/version/check", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "4ecd6094-1e27-424b-aae3-5853d809143a", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Version", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": 0}, {"id": "4a0cebe4-3383-4fac-87c6-b3c5430f83f6", "parent": "4d7ff5f3-5dfb-4986-9240-95178088fafd", "text": "Login", "createdTime": "28-Apr-2025 15:17:38", "droppable": false, "data": {"id": "01011935-a860-4225-b712-a44e0c3436d4", "method": "post", "name": "Login", "url": "{{baseUrl}}/login", "createdTime": "28-Apr-2025 15:17:38", "treeNodeType": "request"}, "relativeIndex": 0}, {"id": "4d7ff5f3-5dfb-4986-9240-95178088fafd", "parent": "85600be6-1481-49b3-b467-9d1d34ccb26f", "text": "Auth", "createdTime": "28-Apr-2025 15:17:38", "droppable": true, "data": {"treeNodeType": "folder"}, "relativeIndex": -1}], "requests": [{"id": "01dff98a-1c15-4c75-b161-e649510d62b8", "url": "{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/logs?tail=100&follow=false", "name": "Get Logs", "createdTime": "29-Apr-2025 11:48:29", "method": "get", "params": [{"isChecked": true, "key": "tail", "value": "100"}, {"isChecked": true, "key": "follow", "value": "false"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01", "index": 0}, {"key": "nodeName", "value": "clab-srl01-srl1", "index": 1}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "*/*", "isChecked": true}, {"key": "User-Agent", "value": "Flashpost", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": "", "selectedEnvironmentId": ""}, {"id": "6ae6cd36-4378-40fc-91ce-6b02fcbf48a6", "url": "{{baseUrl}}/api/v1/generate", "name": "Generate Topology", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"name\": \"3-tier-clos\",\n \"tiers\": [\n {\n \"count\": 4,\n \"kind\": \"nokia_srlinux\",\n \"type\": \"ixrd3\"\n }\n ],\n \"defaultKind\": \"nokia_srlinux\",\n \"deploy\": true,\n \"groupPrefix\": \"clos-tier\",\n \"images\": {\n \"nokia_srlinux\": \"ghcr.io/nokia/srlinux:latest\"\n },\n \"managementNetwork\": \"clos-mgmt\",\n \"nodePrefix\": \"clos-node\",\n \"outputFile\": \"clos.yml\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "07c915e4-5ac3-4b5d-b4b4-b1585c9a1e66", "url": "{{baseUrl}}/api/v1/health/metrics", "name": "Get Detailed System Metrics", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "2f778f28-29da-4c60-bfc7-aed9bae2cae2", "url": "{{baseUrl}}/health", "name": "Get API Server Basic Health", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "41b4b897-fd14-4476-a25e-0fb379f48fe8", "url": "{{baseUrl}}/api/v1/labs?reconfigure=true", "name": "Deploy Lab (URL)", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "exportTemplate", "value": "enim+sunt+labore"}, {"isChecked": false, "key": "nodeFilter", "value": "enim+sunt+labore"}, {"isChecked": false, "key": "skipPostDeploy", "value": "true"}, {"isChecked": false, "key": "skipLabdirAcl", "value": "true"}, {"isChecked": false, "key": "maxWorkers", "value": "4"}, {"isChecked": true, "key": "reconfigure", "value": "true"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"topologySourceUrl\" : \"https://github.com/srl-labs/srlinux-vlan-handling-lab\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "ca8d5092-a70f-4afb-9b9f-001c3285fe6e", "url": "{{baseUrl}}/api/v1/labs/:labName?cleanup=true", "name": "Redeploy Lab", "createdTime": "29-Apr-2025 09:22:19", "method": "put", "params": [{"isChecked": false, "key": "graceful", "value": "true"}, {"isChecked": false, "key": "graph", "value": "true"}, {"isChecked": false, "key": "network", "value": "minim+ea+reprehenderit+cupidatat+amet"}, {"isChecked": false, "key": "ipv4Subnet", "value": "minim+ea+reprehenderit+cupidatat+amet"}, {"isChecked": false, "key": "ipv6Subnet", "value": "minim+ea+reprehenderit+cupidatat+amet"}, {"isChecked": false, "key": "maxWorkers", "value": "-88903131"}, {"isChecked": false, "key": "keepMgmtNet", "value": "true"}, {"isChecked": false, "key": "skipPostDeploy", "value": "true"}, {"isChecked": false, "key": "exportTemplate", "value": "minim+ea+reprehenderit+cupidatat+amet"}, {"isChecked": false, "key": "skipLabdirAcl", "value": "true"}, {"isChecked": true, "key": "cleanup", "value": "true"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01", "index": 0}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"isChecked": true, "key": "Content-Type", "value": "application/json", "isFixed": false}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "6009aaf8-97e0-4892-aa89-05b9eda3fb85", "url": "{{baseUrl}}/api/v1/labs", "name": "List All Labs", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "9f71ff87-b6e6-4925-9b93-f16f11a053b3", "url": "{{baseUrl}}/api/v1/labs?reconfigure=true", "name": "Deploy Lab", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "exportTemplate", "value": "enim+sunt+labore"}, {"isChecked": false, "key": "nodeFilter", "value": "enim+sunt+labore"}, {"isChecked": false, "key": "skipPostDeploy", "value": "true"}, {"isChecked": false, "key": "skipLabdirAcl", "value": "true"}, {"isChecked": false, "key": "maxWorkers", "value": "4"}, {"isChecked": true, "key": "reconfigure", "value": "true"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"topologyContent\": {\n \"name\": \"srl01\",\n \"topology\": {\n \"kinds\": {\n \"nokia_srlinux\": {\n \"type\": \"ixrd3\",\n \"image\": \"ghcr.io/nokia/srlinux\"\n }\n },\n \"nodes\": {\n \"srl1\": {\n \"kind\": \"nokia_srlinux\"\n },\n \"srl2\": {\n \"kind\": \"nokia_srlinux\"\n }\n },\n \"links\": [\n {\n \"endpoints\": [\n \"srl1:e1-1\",\n \"srl2:e1-1\"\n ]\n }\n ]\n }\n }\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "292bb674-0a9b-4d40-9695-facb5dea38c0", "url": "{{baseUrl}}/api/v1/labs/:labName?cleanup=true", "name": "Destroy Lab", "createdTime": "28-Apr-2025 15:17:38", "method": "delete", "params": [{"isChecked": false, "key": "graceful", "value": "true"}, {"isChecked": false, "key": "keepMgmtNet", "value": "true"}, {"isChecked": false, "key": "nodeFilter", "value": "enim+sunt+labore"}, {"isChecked": true, "key": "cleanup", "value": "true"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01", "index": 0}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "12d26a82-6948-4fd5-bd1c-aa19dbf60e55", "url": "{{baseUrl}}/api/v1/labs/:labName", "name": "Inspect Lab", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01", "index": 0}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "8bda0375-3781-4e9e-a783-21c0a4e721c5", "url": "{{baseUrl}}/api/v1/labs/:labName/exec", "name": "Execute Command in Lab", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "nodeFilter", "value": "enim sunt labore"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01"}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"command\": \"ip addr show eth1\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "4fbdb932-d9c7-45fb-98b5-c65c92544704", "url": "{{baseUrl}}/api/v1/labs/:labName/interfaces", "name": "List Lab Interfaces", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "node", "value": "enim sunt labore"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01", "index": 0}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "c24f5aa2-f446-4663-8342-9824510c1291", "url": "{{baseUrl}}/api/v1/labs/:labName/save", "name": "Save Lab Configuration", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "nodeFilter", "value": "enim sunt labore"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01"}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "6219e4a2-2b0f-4b62-a61a-178432cfcbf3", "url": "{{baseUrl}}/api/v1/labs/archive?labName=enim sunt labore&reconfigure=true&maxWorkers=54508974&exportTemplate=enim sunt labore&nodeFilter=enim sunt labore&skipPostDeploy=true&skipLabdirAcl=true", "name": "Deploy Lab from Archive", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": true, "key": "labName", "value": "enim sunt labore"}, {"isChecked": true, "key": "reconfigure", "value": "true"}, {"isChecked": true, "key": "maxWorkers", "value": "54508974"}, {"isChecked": true, "key": "exportTemplate", "value": "enim sunt labore"}, {"isChecked": true, "key": "nodeFilter", "value": "enim sunt labore"}, {"isChecked": true, "key": "skipPostDeploy", "value": "true"}, {"isChecked": true, "key": "skipLabdirAcl", "value": "true"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "apikey", "userName": "Authorization", "password": "{{apiKey}}", "addTo": "header", "showPwd": false, "tokenPrefix": "", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}, "oauth2": {"grantType": "client_credentials", "tokenPrefix": "", "tokenValue": "", "tokenUrl": "", "clientId": "", "clientSecret": "", "scope": "", "clientAuth": "in-header"}}, "headers": [{"key": "Content-Type", "value": "multipart/form-data", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "formdata", "formdata": [{"key": "labArchive", "type": "File", "isChecked": false}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "10881948-058d-4105-8c7d-439dde46add6", "url": "{{baseUrl}}/api/v1/labs/:labName/nodes/:nodeName/ssh", "name": "Request SSH Access to Lab Node", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "labName", "value": "srl01"}, {"key": "nodeName", "value": "clab-srl01-srl1"}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"duration\": \"60m\",\n \"sshUsername\": \"admin\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "477c3ae1-d29e-4e19-84cf-e8c272956e2b", "url": "{{baseUrl}}/api/v1/ssh/sessions", "name": "List SSH Sessions", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "all", "value": "true"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "a182a781-6762-4193-b4a7-295fa2649b69", "url": "{{baseUrl}}/api/v1/ssh/sessions/:port", "name": "Terminate SSH Session", "createdTime": "28-Apr-2025 15:17:38", "method": "delete", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [{"key": "port", "value": "2223"}], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "bade1852-e968-4f54-803f-97eb76afaf5b", "url": "{{baseUrl}}/api/v1/tools/certs/ca", "name": "Create Certificate Authority (CA)", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"commonName\": \"ca.example.com\",\n \"country\": \"US\",\n \"expiry\": \"8760h\",\n \"locality\": \"City\",\n \"name\": \"my-root-ca\",\n \"orgUnit\": \"IT\",\n \"organization\": \"MyOrg\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "94ba0d9b-8267-42a8-95b9-d4d977cf027b", "url": "{{baseUrl}}/api/v1/tools/certs/sign", "name": "Sign Certificate", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"caName\": \"my-root-ca\",\n \"hosts\": [\n \"localhost\"\n ],\n \"name\": \"node1.example.com\",\n \"commonName\": \"node1.example.com\",\n \"country\": \"US\",\n \"keySize\": 4096,\n \"locality\": \"City\",\n \"orgUnit\": \"Nodes\",\n \"organization\": \"MyOrg\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "5bef21f3-f6fe-4781-b73d-1aee92d13e83", "url": "{{baseUrl}}/api/v1/tools/disable-tx-offload", "name": "Disable TX Checksum Offload", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"containerName\": \"srl01-srl1\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "1a1d51e0-cd0d-4813-96dc-6317af203172", "url": "{{baseUrl}}/api/v1/tools/veth", "name": "Create vEth Pair", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"aEndpoint\": \"clab-srl01-srl1:eth1\",\n \"bEndpoint\": \"clab-srl01-srl2:eth1\",\n \"mtu\": 1500\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "181b6ae2-b8dd-4c42-adb4-5e79c381282d", "url": "{{baseUrl}}/api/v1/tools/vxlan?prefix=vx-", "name": "Delete VxLAN Tunnels by Prefix", "createdTime": "28-Apr-2025 15:17:38", "method": "delete", "params": [{"isChecked": true, "key": "prefix", "value": "vx-"}, {"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "apikey", "userName": "Authorization", "password": "{{apiKey}}", "addTo": "header", "showPwd": false, "tokenPrefix": "", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}, "oauth2": {"grantType": "client_credentials", "tokenPrefix": "", "tokenValue": "", "tokenUrl": "", "clientId": "", "clientSecret": "", "scope": "", "clientAuth": "in-header"}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "0f3efed3-4287-4c29-b95a-7fe476cd5cb3", "url": "{{baseUrl}}/api/v1/tools/vxlan", "name": "Create VxLAN Tunnel", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"link\": \"srl_e1-1\",\n \"remote\": \"10.0.0.20\",\n \"dev\": \"eth0\",\n \"id\": 100,\n \"mtu\": 1400,\n \"port\": 4789\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "e5aaff86-f946-4c03-826f-21803ef9ac68", "url": "{{baseUrl}}/api/v1/users", "name": "List All Users", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "0e1b6cc2-0d1e-45dd-beac-9d5e09e26d56", "url": "{{baseUrl}}/api/v1/users", "name": "Create User", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"password\": \"test\",\n \"username\": \"test\",\n \"displayName\": \"test\",\n \"groups\": [\n \"clab_admins\"\n ],\n \"isSuperuser\": false\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "446c15ac-7566-4376-8b6a-9c6897ee31e3", "url": "{{baseUrl}}/api/v1/users/testuser_44h89", "name": "Delete User", "createdTime": "28-Apr-2025 15:17:38", "method": "delete", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "63f39a55-f36c-48c8-8494-85ace4953aa7", "url": "{{baseUrl}}/api/v1/users/test", "name": "Get User Details", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "5dc6d6f6-d0f3-44b0-8b3b-528134efa5cb", "url": "{{baseUrl}}/api/v1/users/test", "name": "Update User", "createdTime": "28-Apr-2025 15:17:38", "method": "put", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"displayName\": \"test\",\n \"groups\": [\n \"clab_api\"\n ],\n \"isSuperuser\": false\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "4415b59e-c577-426a-b554-f3953c77aacf", "url": "{{baseUrl}}/api/v1/users/test/password", "name": "Change User Password", "createdTime": "28-Apr-2025 15:17:38", "method": "put", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"newPassword\": \"fugiat elit nostrud\",\n \"currentPassword\": \"sit dolor est ipsum\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "2f1920a6-6946-4f56-b0a2-d072117c9696", "url": "{{baseUrl}}/api/v1/version", "name": "Get Containerlab Version", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "fab7c8d0-0e3c-4b47-a20c-bda6dd0d778a", "url": "{{baseUrl}}/api/v1/version/check", "name": "Check for Containerlab Updates", "createdTime": "28-Apr-2025 15:17:38", "method": "get", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "bearertoken", "userName": "", "password": "{{apiKey}}", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "Bearer", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}}, "headers": [{"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "none", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "", "key": "", "variableName": ""}], "notes": ""}, {"id": "4a0cebe4-3383-4fac-87c6-b3c5430f83f6", "url": "{{baseUrl}}/login", "name": "Login", "createdTime": "28-Apr-2025 15:17:38", "method": "post", "params": [{"isChecked": false, "key": "", "value": ""}], "pathParams": [], "auth": {"authType": "inherit", "userName": "", "password": "", "addTo": "queryparams", "showPwd": false, "tokenPrefix": "", "aws": {"service": "", "region": "", "accessKey": "", "secretAccessKey": "", "sessionToken": ""}, "oauth2": {"grantType": "client_credentials", "tokenPrefix": "", "tokenValue": "", "tokenUrl": "", "clientId": "", "clientSecret": "", "scope": "", "clientAuth": "in-header"}}, "headers": [{"key": "Content-Type", "value": "application/json", "isChecked": true}, {"key": "Accept", "value": "application/json", "isChecked": true}, {"key": "", "value": "", "isChecked": false}], "body": {"bodyType": "raw", "formdata": [{"isChecked": false, "key": "", "value": ""}], "urlencoded": [{"isChecked": false, "key": "", "value": ""}], "raw": {"data": "{\n \"username\": \"{{USER_NAME}}\",\n \"password\": \"{{USER_PASSWORD}}\"\n}", "lang": "json"}, "binary": {"fileName": "", "data": {}, "contentTypeOption": "manual"}, "graphql": {"query": "", "variables": ""}}, "tests": [{"parameter": "", "action": "", "expectedValue": ""}], "setvar": [{"parameter": "JSON", "key": "token", "variableName": "apiKey"}, {"parameter": "", "key": "", "variableName": ""}], "notes": ""}]} \ No newline at end of file diff --git a/internal/api/auth_handlers.go b/internal/api/auth_handlers.go index 0c976f6..f0f1a5c 100644 --- a/internal/api/auth_handlers.go +++ b/internal/api/auth_handlers.go @@ -12,13 +12,13 @@ import ( ) // LoginHandler - Handles user authentication -// @Summary Login -// @Description Authenticate user and return JWT token +// @Summary Log in +// @Description Authenticates a user and returns a JWT token. // @Tags Auth // @Accept json // @Produce json // @Param credentials body models.LoginRequest true "User Credentials" -// @Success 200 {object} models.LoginResponse +// @Success 200 {object} models.LoginResponse "JWT token" // @Failure 400 {object} models.ErrorResponse "Invalid input" // @Failure 401 {object} models.ErrorResponse "Invalid credentials" // @Failure 500 {object} models.ErrorResponse "Internal server error (PAM config?)" diff --git a/internal/api/events_handlers.go b/internal/api/events_handlers.go index cea0e44..28581c9 100644 --- a/internal/api/events_handlers.go +++ b/internal/api/events_handlers.go @@ -37,33 +37,31 @@ type clabEventJSON struct { Attributes map[string]string `json:"attributes"` } -// @Summary Stream Containerlab Events -// @Description Streams containerlab events in real-time. The response stays open until the client disconnects. +// @Summary Stream containerlab events +// @Description Streams containerlab events in real time as NDJSON (one JSON object per line). // @Description -// @Description **JSON format example** (default, returns NDJSON - one JSON object per line): +// @Description **Notes** +// @Description - The response stays open until the client disconnects. +// @Description +// @Description **Examples** +// @Description NDJSON (one JSON object per line): // @Description ```json // @Description {"time":1706918400,"type":"container","action":"start","attributes":{"name":"clab-mylab-srl1","lab":"mylab","clab-node-name":"srl1","clab-node-kind":"nokia_srlinux"}} // @Description {"time":1706918405,"type":"container","action":"start","attributes":{"name":"clab-mylab-srl2","lab":"mylab","clab-node-name":"srl2","clab-node-kind":"nokia_srlinux"}} // @Description ``` // @Description -// @Description **Interface stats example** (interfaceStats=true): +// @Description +// @Description Interface stats (interfaceStats=true): // @Description ```json // @Description {"time":1706918410,"type":"interface-stats","action":"stats","attributes":{"name":"clab-mylab-srl1","lab":"mylab","interface":"e1-1","rx_bytes":123456,"tx_bytes":654321}} // @Description ``` -// @Description -// @Description **Plain format example** (format=plain): -// @Description ``` -// @Description 2024-02-03T10:30:00Z container start (name=clab-mylab-srl1, lab=mylab, kind=nokia_srlinux) -// @Description 2024-02-03T10:30:05Z container start (name=clab-mylab-srl2, lab=mylab, kind=nokia_srlinux) -// @Description ``` // @Tags Events // @Security BearerAuth -// @Produce json -// @Param format query string false "Output format ('json' or 'plain'). Default is 'json'." Enums(json, plain) default(json) +// @Produce application/x-ndjson // @Param initialState query boolean false "Include initial snapshot events when the stream starts." default(false) // @Param interfaceStats query boolean false "Include interface stats events." default(false) // @Param interfaceStatsInterval query string false "Interval for interface stats collection (e.g., 10s). Requires interfaceStats=true." default(10s) -// @Success 200 {object} models.EventResponse "Event stream - returns newline-delimited events (plain text or NDJSON)" +// @Success 200 {object} models.EventResponse "Event stream - NDJSON (one JSON object per line)" // @Failure 400 {object} models.ErrorResponse "Invalid input" // @Failure 401 {object} models.ErrorResponse "Unauthorized" // @Failure 500 {object} models.ErrorResponse "Internal server error" @@ -72,12 +70,6 @@ func StreamEventsHandler(c *gin.Context) { username := c.GetString("username") isSuperuserUser := isSuperuser(username) - format := strings.ToLower(c.DefaultQuery("format", "json")) - if format != "plain" && format != "json" { - c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Invalid format parameter. Use 'plain' or 'json'."}) - return - } - initialState, err := parseBoolQuery(c, "initialState", false) if err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Invalid initialState parameter. Use true or false."}) @@ -114,14 +106,10 @@ func StreamEventsHandler(c *gin.Context) { runtime = "docker" } - log.Infof("StreamEvents user '%s': Starting containerlab events stream (format=%s, initialState=%v, interfaceStats=%v, interval=%s)", - username, format, initialState, interfaceStats, interfaceStatsInterval) + log.Infof("StreamEvents user '%s': Starting containerlab events stream (initialState=%v, interfaceStats=%v, interval=%s)", + username, initialState, interfaceStats, interfaceStatsInterval) - if format == "json" { - c.Writer.Header().Set("Content-Type", "application/x-ndjson; charset=utf-8") - } else { - c.Writer.Header().Set("Content-Type", "text/plain; charset=utf-8") - } + c.Writer.Header().Set("Content-Type", "application/x-ndjson; charset=utf-8") c.Writer.Header().Set("X-Content-Type-Options", "nosniff") c.Writer.Header().Set("Cache-Control", "no-cache") @@ -137,7 +125,7 @@ func StreamEventsHandler(c *gin.Context) { streamReader, streamWriter := io.Pipe() eventsOpts := clabevents.Options{ - Format: format, + Format: "json", Runtime: runtime, IncludeInitialState: initialState, IncludeInterfaceStats: interfaceStats, @@ -208,7 +196,7 @@ func StreamEventsHandler(c *gin.Context) { for scanner.Scan() { line := scanner.Text() if !isSuperuserUser { - labName, ok := extractLabFromEventLine(line, format) + labName, ok := extractLabFromEventLine(line) if !ok || !allowedLab(labName) { continue } @@ -238,11 +226,8 @@ func parseBoolQuery(c *gin.Context, name string, defaultValue bool) (bool, error return strconv.ParseBool(raw) } -func extractLabFromEventLine(line, format string) (string, bool) { - if format == "json" { - return extractLabFromJSONLine(line) - } - return extractLabFromPlainLine(line) +func extractLabFromEventLine(line string) (string, bool) { + return extractLabFromJSONLine(line) } func extractLabFromJSONLine(line string) (string, bool) { @@ -262,24 +247,4 @@ func extractLabFromJSONLine(line string) (string, bool) { return "", false } -func extractLabFromPlainLine(line string) (string, bool) { - start := strings.LastIndex(line, "(") - end := strings.LastIndex(line, ")") - if start == -1 || end == -1 || end <= start { - return "", false - } - attrs := line[start+1 : end] - parts := strings.Split(attrs, ", ") - for _, part := range parts { - kv := strings.SplitN(part, "=", 2) - if len(kv) != 2 { - continue - } - key := kv[0] - value := kv[1] - if key == "lab" || key == "containerlab" { - return value, true - } - } - return "", false -} +// Plain-text event parsing removed; NDJSON-only output is supported. diff --git a/internal/api/health_handlers.go b/internal/api/health_handlers.go index 6d762c9..85fe03a 100644 --- a/internal/api/health_handlers.go +++ b/internal/api/health_handlers.go @@ -30,8 +30,8 @@ func InitHealth(version string) { apiServerVersion = version } -// @Summary Get API Server Basic Health -// @Description Returns basic health status of the API server. +// @Summary Get API server health +// @Description Returns basic health status for the API server. // @Tags Health // @Produce json // @Success 200 {object} models.HealthResponse "Basic health information" @@ -52,8 +52,8 @@ func HealthCheckHandler(c *gin.Context) { c.JSON(http.StatusOK, response) } -// @Summary Get Detailed System Metrics -// @Description Returns detailed CPU, memory, and disk metrics for the API server. Requires SUPERUSER privileges. +// @Summary Get system metrics +// @Description Returns detailed CPU, memory, and disk metrics for the API server. Requires superuser privileges. // @Tags Health // @Security BearerAuth // @Produce json diff --git a/internal/api/info_handlers.go b/internal/api/info_handlers.go index c80c69f..c12098b 100644 --- a/internal/api/info_handlers.go +++ b/internal/api/info_handlers.go @@ -10,8 +10,8 @@ import ( "github.com/srl-labs/clab-api-server/internal/models" ) -// @Summary Get Containerlab Version -// @Description Retrieves version information about the containerlab library in use. +// @Summary Get containerlab version +// @Description Returns version information for the containerlab library in use. // @Tags Version // @Security BearerAuth // @Produce json @@ -31,8 +31,9 @@ func GetVersionHandler(c *gin.Context) { c.JSON(http.StatusOK, models.VersionResponse{VersionInfo: versionInfo}) } -// @Summary Check for Containerlab Updates -// @Description This endpoint has been deprecated. Version checks are no longer supported when using containerlab as a library. +// @Summary Check containerlab updates +// @Description **Deprecated** +// @Description Version checks are not supported when containerlab runs as a library. // @Tags Version // @Security BearerAuth // @Produce json diff --git a/internal/api/lab_handlers.go b/internal/api/lab_handlers.go index 48830de..ca6e14c 100644 --- a/internal/api/lab_handlers.go +++ b/internal/api/lab_handlers.go @@ -23,13 +23,17 @@ import ( "github.com/srl-labs/clab-api-server/internal/models" ) -// @Summary Deploy Lab -// @Description Deploys a containerlab topology. Requires EITHER 'topologyContent' OR 'topologySourceUrl' in the request body, but not both. +// @Summary Deploy lab +// @Description Deploys a containerlab topology. +// @Description +// @Description **Notes** +// @Description - The request body must include either `topologyContent` or `topologySourceUrl` (not both). // @Tags Labs // @Security BearerAuth // @Accept json // @Produce json // @Param deploy_request body models.DeployRequest true "Deployment Source" +// @Param labNameOverride query string false "Override lab name when deploying from a URL (optional)" // @Param reconfigure query boolean false "Allow overwriting an existing lab IF owned by the user" // @Param maxWorkers query int false "Limit concurrent workers" // @Param exportTemplate query string false "Custom Go template file for topology data export" @@ -245,7 +249,7 @@ func DeployLabHandler(c *gin.Context) { c.JSON(http.StatusOK, result) } -// @Summary Deploy Lab from Archive +// @Summary Deploy lab from archive // @Description Deploys a containerlab topology provided as a .zip or .tar.gz archive. // @Tags Labs // @Security BearerAuth @@ -254,6 +258,11 @@ func DeployLabHandler(c *gin.Context) { // @Param labArchive formData file true "Lab archive (.zip or .tar.gz)" // @Param labName query string true "Name for the lab" // @Param reconfigure query boolean false "Allow overwriting an existing lab" +// @Param maxWorkers query int false "Limit concurrent workers" +// @Param exportTemplate query string false "Custom Go template file for topology data export" +// @Param nodeFilter query string false "Comma-separated list of node names to deploy" +// @Param skipPostDeploy query boolean false "Skip post-deploy actions" +// @Param skipLabdirAcl query boolean false "Skip setting extended ACLs on lab directory" // @Success 200 {object} models.ClabInspectOutput "Deployed lab details" // @Failure 400 {object} models.ErrorResponse "Invalid input" // @Failure 401 {object} models.ErrorResponse "Unauthorized" @@ -431,8 +440,8 @@ func DeployLabArchiveHandler(c *gin.Context) { c.JSON(http.StatusOK, result) } -// @Summary Destroy Lab -// @Description Destroys a lab by name, checking ownership. +// @Summary Destroy lab +// @Description Destroys a lab by name after verifying ownership. // @Tags Labs // @Security BearerAuth // @Produce json @@ -441,7 +450,7 @@ func DeployLabArchiveHandler(c *gin.Context) { // @Param graceful query boolean false "Attempt graceful shutdown" // @Param keepMgmtNet query boolean false "Keep the management network" // @Param nodeFilter query string false "Destroy only specific nodes" -// @Success 200 {object} models.GenericSuccessResponse +// @Success 200 {object} models.GenericSuccessResponse "Lab destroyed successfully" // @Failure 400 {object} models.ErrorResponse "Invalid lab name" // @Failure 401 {object} models.ErrorResponse "Unauthorized" // @Failure 404 {object} models.ErrorResponse "Lab not found" @@ -530,12 +539,22 @@ func DestroyLabHandler(c *gin.Context) { c.JSON(http.StatusOK, models.GenericSuccessResponse{Message: fmt.Sprintf("Lab '%s' destroyed successfully", labName)}) } -// @Summary Redeploy Lab -// @Description Redeploys a lab by name (destroy + deploy). +// @Summary Redeploy lab +// @Description Redeploys a lab by name. +// @Description +// @Description **Notes** +// @Description - This operation destroys the lab and then deploys it again. // @Tags Labs // @Security BearerAuth // @Produce json // @Param labName path string true "Name of the lab to redeploy" +// @Param cleanup query boolean false "Remove lab directory after destroy" +// @Param graceful query boolean false "Attempt graceful shutdown" +// @Param keepMgmtNet query boolean false "Keep the management network" +// @Param maxWorkers query int false "Limit concurrent workers" +// @Param exportTemplate query string false "Custom Go template file for topology data export" +// @Param skipPostDeploy query boolean false "Skip post-deploy actions" +// @Param skipLabdirAcl query boolean false "Skip setting extended ACLs on lab directory" // @Success 200 {object} models.ClabInspectOutput "Redeployed lab details" // @Failure 400 {object} models.ErrorResponse "Invalid lab name" // @Failure 401 {object} models.ErrorResponse "Unauthorized" @@ -632,13 +651,12 @@ func RedeployLabHandler(c *gin.Context) { c.JSON(http.StatusOK, result) } -// @Summary Inspect Lab -// @Description Get details about a specific running lab. +// @Summary Inspect lab +// @Description Returns details for a specific running lab. // @Tags Labs // @Security BearerAuth // @Produce json // @Param labName path string true "Name of the lab to inspect" -// @Param details query boolean false "Include full container details" // @Success 200 {object} []models.ClabContainerInfo "Lab containers" // @Failure 400 {object} models.ErrorResponse "Invalid lab name" // @Failure 401 {object} models.ErrorResponse "Unauthorized" @@ -691,8 +709,8 @@ func InspectLabHandler(c *gin.Context) { c.JSON(http.StatusOK, labContainers) } -// @Summary List Lab Interfaces -// @Description Get network interface details for nodes in a specific lab. +// @Summary List lab interfaces +// @Description Returns interface details for nodes in a lab. // @Tags Labs // @Security BearerAuth // @Produce json @@ -767,8 +785,11 @@ func InspectInterfacesHandler(c *gin.Context) { c.JSON(http.StatusOK, result) } -// @Summary List All Labs -// @Description Get details about all running labs (filtered by owner unless superuser). +// @Summary List labs +// @Description Returns details for all running labs. +// @Description +// @Description **Notes** +// @Description - Results are filtered by owner unless the caller is a superuser. // @Tags Labs // @Security BearerAuth // @Produce json @@ -824,7 +845,7 @@ func ListLabsHandler(c *gin.Context) { c.JSON(http.StatusOK, finalResult) } -// @Summary Save Lab Configuration +// @Summary Save lab configuration // @Description Saves the running configuration for nodes in a lab. // @Tags Labs // @Security BearerAuth @@ -893,15 +914,14 @@ func SaveLabConfigHandler(c *gin.Context) { }) } -// @Summary Execute Command in Lab -// @Description Executes a command on nodes within a specific lab. +// @Summary Execute command in lab +// @Description Executes a command on nodes within a lab. // @Tags Labs // @Security BearerAuth // @Accept json // @Produce json // @Param labName path string true "Name of the lab" // @Param nodeFilter query string false "Execute only on this specific node" -// @Param format query string false "Output format ('plain' or 'json')" // @Param exec_request body models.ExecRequest true "Command to execute" // @Success 200 {object} models.ExecResponse "Execution result" // @Failure 400 {object} models.ErrorResponse "Invalid input" @@ -922,7 +942,6 @@ func ExecCommandHandler(c *gin.Context) { c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Invalid characters in nodeFilter."}) return } - var req models.ExecRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Invalid request body: " + err.Error()}) diff --git a/internal/api/logs_handlers.go b/internal/api/logs_handlers.go index 64e9f78..00bbf25 100644 --- a/internal/api/logs_handlers.go +++ b/internal/api/logs_handlers.go @@ -4,6 +4,7 @@ package api import ( "bufio" "context" + "encoding/json" "fmt" "io" "net/http" @@ -19,18 +20,19 @@ import ( "github.com/srl-labs/clab-api-server/internal/models" ) -// @Summary Get Node Logs -// @Description Get logs from a specific lab node (container). When follow=true, logs will stream until client disconnects or 30-minute timeout. +// @Summary Get node logs +// @Description Returns logs for a lab node. +// @Description +// @Description **Notes** +// @Description - When `follow=true`, the response streams as NDJSON (one JSON object per line) until the client disconnects or the 30-minute timeout. // @Tags Logs // @Security BearerAuth -// @Produce plain,json,octet-stream +// @Produce json,application/x-ndjson // @Param labName path string true "Name of the lab" example="my-lab" // @Param nodeName path string true "Full name of the container (node)" example="clab-my-lab-srl1" -// @Param tail query int false "Number of lines to show from the end of logs (default all)" example="100" -// @Param follow query boolean false "Follow log output (stream logs). Note: In Swagger UI, streaming may not display correctly." example="false" -// @Param format query string false "Output format ('plain' or 'json'). Default is 'plain'. When follow=true, only 'plain' format is supported." example="plain" -// @Success 200 {string} string "Container logs (when format=plain)" -// @Success 200 {object} models.LogsResponse "Container logs (when format=json)" +// @Param tail query string false "Number of lines to show from the end of logs (default all). Use an integer or 'all'." example="100" default(all) +// @Param follow query boolean false "Follow log output (stream logs as NDJSON). Note: In Swagger UI, streaming may not display correctly." example="false" +// @Success 200 {object} models.LogsResponse "Container logs (follow=false). When follow=true, response is NDJSON stream of LogLine objects." // @Failure 400 {object} models.ErrorResponse "Invalid input (lab name, node filter, etc.)" // @Failure 401 {object} models.ErrorResponse "Unauthorized" // @Failure 403 {object} models.ErrorResponse "Forbidden (not owner of the lab)" @@ -41,7 +43,6 @@ func GetNodeLogsHandler(c *gin.Context) { username := c.GetString("username") labName := c.Param("labName") containerName := c.Param("nodeName") - outputFormat := c.DefaultQuery("format", "plain") tailQuery := c.DefaultQuery("tail", "all") follow := c.Query("follow") == "true" @@ -58,12 +59,6 @@ func GetNodeLogsHandler(c *gin.Context) { return } - if outputFormat != "plain" && outputFormat != "json" { - log.Warnf("GetNodeLogs failed for user '%s': Invalid format '%s'", username, outputFormat) - c.JSON(http.StatusBadRequest, models.ErrorResponse{Error: "Invalid format parameter. Use 'plain' or 'json'."}) - return - } - // Process tail parameter var tailLines string if tailQuery != "all" { @@ -138,7 +133,7 @@ func GetNodeLogsHandler(c *gin.Context) { // Determine if we should stream logs or fetch once if follow { // --- Stream Logs --- - c.Writer.Header().Set("Content-Type", "text/plain; charset=utf-8") + c.Writer.Header().Set("Content-Type", "application/x-ndjson; charset=utf-8") c.Writer.Header().Set("X-Content-Type-Options", "nosniff") // Set up a context with timeout for streaming logs (30 minutes) @@ -197,14 +192,22 @@ func GetNodeLogsHandler(c *gin.Context) { } }() - // Stream the logs line by line + // Stream the logs line by line as NDJSON scanner := bufio.NewScanner(stdout) c.Stream(func(w io.Writer) bool { if !scanner.Scan() { return false } - line := scanner.Text() + "\n" - w.Write([]byte(line)) + line := scanner.Text() + payload, err := json.Marshal(models.LogLine{ + ContainerName: containerName, + Line: line, + }) + if err != nil { + log.Errorf("GetNodeLogs failed to marshal log line for user '%s': %v", username, err) + return false + } + _, _ = w.Write(append(payload, '\n')) return true }) @@ -261,19 +264,12 @@ func GetNodeLogsHandler(c *gin.Context) { log.Infof("GetNodeLogs success for user '%s', container '%s'", username, containerName) - // Return logs based on requested format - if outputFormat == "json" { - // Format as JSON - response := models.LogsResponse{ - ContainerName: containerName, - Logs: stdout, - } - c.JSON(http.StatusOK, response) - } else { - // Plain text output - c.Header("Content-Type", "text/plain; charset=utf-8") - c.String(http.StatusOK, stdout) + // Return logs as JSON + response := models.LogsResponse{ + ContainerName: containerName, + Logs: stdout, } + c.JSON(http.StatusOK, response) } } diff --git a/internal/api/ssh_handlers.go b/internal/api/ssh_handlers.go index e51a192..b1eecdc 100644 --- a/internal/api/ssh_handlers.go +++ b/internal/api/ssh_handlers.go @@ -37,8 +37,8 @@ func ShutdownSSHManager() { } } -// @Summary Request SSH Access to Lab Node -// @Description Creates temporary SSH access to a specific lab node, returning connection details +// @Summary Request SSH access to lab node +// @Description Creates temporary SSH access to a lab node and returns connection details. // @Tags SSH Access // @Security BearerAuth // @Accept json @@ -177,8 +177,12 @@ func RequestSSHAccessHandler(c *gin.Context) { c.JSON(http.StatusOK, response) } -// @Summary List SSH Sessions -// @Description Lists active SSH sessions. For regular users, shows only their sessions. Superusers can see all sessions by using the 'all' query parameter. +// @Summary List SSH sessions +// @Description Returns active SSH sessions. +// @Description +// @Description **Notes** +// @Description - Regular users see only their sessions. +// @Description - Superusers can include all sessions via the `all` query parameter. // @Tags SSH Access // @Security BearerAuth // @Produce json @@ -209,8 +213,8 @@ func ListSSHSessionsHandler(c *gin.Context) { c.JSON(http.StatusOK, sessions) } -// @Summary Terminate SSH Session -// @Description Terminates a specific SSH session by port +// @Summary Terminate SSH session +// @Description Terminates a specific SSH session by port. // @Tags SSH Access // @Security BearerAuth // @Produce json diff --git a/internal/api/tools_handlers.go b/internal/api/tools_handlers.go index d56c5c1..2199896 100644 --- a/internal/api/tools_handlers.go +++ b/internal/api/tools_handlers.go @@ -21,8 +21,8 @@ import ( // --- TX Offload Handler --- -// @Summary Disable TX Checksum Offload -// @Description Disables TX checksum offload for the eth0 interface of a specific container. Requires SUPERUSER privileges. +// @Summary Disable TX checksum offload +// @Description Disables TX checksum offload on the eth0 interface of a container. Requires superuser privileges. // @Tags Tools // @Security BearerAuth // @Accept json @@ -90,8 +90,11 @@ func DisableTxOffloadHandler(c *gin.Context) { // --- Certificate Handlers --- -// @Summary Create Certificate Authority (CA) -// @Description Creates a CA certificate and private key. Requires SUPERUSER privileges. Files are stored in the user's ~/.clab/certs// directory on the server. +// @Summary Create certificate authority (CA) +// @Description Creates a CA certificate and private key. Requires superuser privileges. +// @Description +// @Description **Notes** +// @Description - Files are stored in the user's `~/.clab/certs//` directory on the server. // @Tags Tools - Certificates // @Security BearerAuth // @Accept json @@ -239,8 +242,11 @@ func CreateCAHandler(c *gin.Context) { }) } -// @Summary Sign Certificate -// @Description Creates a certificate/key and signs it with a previously generated CA. Requires SUPERUSER privileges. Files are stored in the user's ~/.clab/certs// directory. +// @Summary Sign certificate +// @Description Creates a certificate/key and signs it with a previously generated CA. Requires superuser privileges. +// @Description +// @Description **Notes** +// @Description - Files are stored in the user's `~/.clab/certs//` directory. // @Tags Tools - Certificates // @Security BearerAuth // @Accept json @@ -401,8 +407,8 @@ func SignCertHandler(c *gin.Context) { }) } -// @Summary Create vEth Pair -// @Description Creates a virtual Ethernet (vEth) pair between two specified endpoints (container, host, bridge, ovs-bridge). Requires SUPERUSER privileges. +// @Summary Create vEth pair +// @Description Creates a virtual Ethernet (vEth) pair between two endpoints (container, host, bridge, or ovs-bridge). Requires superuser privileges. // @Tags Tools - vEth // @Security BearerAuth // @Accept json @@ -475,8 +481,8 @@ func CreateVethHandler(c *gin.Context) { // --- VxLAN Handlers --- -// @Summary Create VxLAN Tunnel -// @Description Creates a VxLAN tunnel interface and sets up tc rules for traffic redirection. Requires SUPERUSER privileges. +// @Summary Create VxLAN tunnel +// @Description Creates a VxLAN tunnel interface and sets up tc rules for traffic redirection. Requires superuser privileges. // @Tags Tools - VxLAN // @Security BearerAuth // @Accept json @@ -561,8 +567,8 @@ func CreateVxlanHandler(c *gin.Context) { }) } -// @Summary Delete VxLAN Tunnels by Prefix -// @Description Deletes VxLAN tunnel interfaces matching a given prefix (default: 'vx-'). Requires SUPERUSER privileges. +// @Summary Delete VxLAN tunnels by prefix +// @Description Deletes VxLAN tunnel interfaces that match the provided prefix (default: `vx-`). Requires superuser privileges. // @Tags Tools - VxLAN // @Security BearerAuth // @Produce json diff --git a/internal/api/topology_handlers.go b/internal/api/topology_handlers.go index 458b3c2..35ed532 100644 --- a/internal/api/topology_handlers.go +++ b/internal/api/topology_handlers.go @@ -17,13 +17,15 @@ import ( "github.com/srl-labs/clab-api-server/internal/models" ) -// @Summary Generate Topology -// @Description Generates a containerlab topology file based on CLOS definitions. Optionally deploys it, setting the owner to the authenticated user. -// @Description Deployment is DENIED if a lab with the target name already exists. -// @Description The 'images' and 'licenses' fields expect a map where the key is the node 'kind' and the value is the corresponding image or license path (e.g., {"nokia_srlinux": "ghcr.io/..."}). -// @Description If Deploy=true, the topology is saved to the user's ~/.clab// directory before deployment, and the 'outputFile' field is ignored. -// @Description If Deploy=false and 'outputFile' is empty, YAML is returned directly. -// @Description If Deploy=false and 'outputFile' is set, the file is saved to that path on the server (requires API server write permissions). +// @Summary Generate containerlab topology +// @Description Generates a containerlab topology from CLOS definitions and can optionally deploy it for the authenticated user. +// @Description +// @Description **Notes** +// @Description - Deployment is denied if a lab with the target name already exists. +// @Description - The `images` and `licenses` fields map node kind to image or license path (e.g., {"nokia_srlinux":"ghcr.io/..."}). +// @Description - When `deploy=true`, the topology is saved to the user's `~/.clab//` directory and `outputFile` is ignored. +// @Description - When `deploy=false` and `outputFile` is empty, YAML is returned in the response. +// @Description - When `deploy=false` and `outputFile` is set, the file is saved to that path on the server (requires API server write permissions). // @Tags Topology Generation // @Security BearerAuth // @Accept json diff --git a/internal/api/user_handlers.go b/internal/api/user_handlers.go index 43a96c6..7f13388 100644 --- a/internal/api/user_handlers.go +++ b/internal/api/user_handlers.go @@ -13,8 +13,8 @@ import ( "github.com/srl-labs/clab-api-server/internal/models" ) -// @Summary List All Users -// @Description Get a list of all users in the system. Requires superuser privileges. +// @Summary List users +// @Description Returns a list of system users. Requires superuser privileges. // @Tags Users // @Security BearerAuth // @Produce json @@ -41,8 +41,8 @@ func ListUsersHandler(c *gin.Context) { c.JSON(http.StatusOK, users) } -// @Summary Get User Details -// @Description Get detailed information about a specific user. Requires superuser privileges or the user's own account. +// @Summary Get user details +// @Description Returns details for a specific user. Requires superuser privileges or the user's own account. // @Tags Users // @Security BearerAuth // @Produce json @@ -81,8 +81,8 @@ func GetUserDetailsHandler(c *gin.Context) { c.JSON(http.StatusOK, userDetails) } -// @Summary Create User -// @Description Create a new system user. Requires superuser privileges. +// @Summary Create user +// @Description Creates a new system user. Requires superuser privileges. // @Tags Users // @Security BearerAuth // @Accept json @@ -129,8 +129,8 @@ func CreateUserHandler(c *gin.Context) { c.JSON(http.StatusCreated, models.GenericSuccessResponse{Message: fmt.Sprintf("User '%s' created successfully", req.Username)}) } -// @Summary Update User -// @Description Update information for an existing user. Requires superuser privileges or the user's own account. +// @Summary Update user +// @Description Updates an existing user. Requires superuser privileges or the user's own account. // @Tags Users // @Security BearerAuth // @Accept json @@ -193,8 +193,8 @@ func UpdateUserHandler(c *gin.Context) { c.JSON(http.StatusOK, models.GenericSuccessResponse{Message: fmt.Sprintf("User '%s' updated successfully", targetUser)}) } -// @Summary Delete User -// @Description Delete a user from the system. Requires superuser privileges. +// @Summary Delete user +// @Description Deletes a user from the system. Requires superuser privileges. // @Tags Users // @Security BearerAuth // @Produce json @@ -240,8 +240,8 @@ func DeleteUserHandler(c *gin.Context) { c.JSON(http.StatusOK, models.GenericSuccessResponse{Message: fmt.Sprintf("User '%s' deleted successfully", targetUser)}) } -// @Summary Change User Password -// @Description Change password for a user. Requires superuser privileges or the user's own account. +// @Summary Change user password +// @Description Changes a user's password. Requires superuser privileges or the user's own account. // @Tags Users // @Security BearerAuth // @Accept json diff --git a/internal/models/logs.go b/internal/models/logs.go index 1c60187..99690d9 100644 --- a/internal/models/logs.go +++ b/internal/models/logs.go @@ -11,3 +11,9 @@ type LogsResponse struct { ContainerName string `json:"containerName"` Logs string `json:"logs"` } + +// LogLine represents a single streamed log line in NDJSON format +type LogLine struct { + ContainerName string `json:"containerName"` + Line string `json:"line"` +} diff --git a/internal/models/models.go b/internal/models/models.go index bd32d23..0a27e44 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -185,7 +185,7 @@ type GenerateResponse struct { Message string `json:"message"` // The generated topology YAML (only if Deploy=false and OutputFile is empty). TopologyYAML string `json:"topologyYaml,omitempty"` - // The output from the deploy command (only if Deploy=true). Can be JSON or plain text. + // 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. DeployOutput json.RawMessage `json:"deployOutput,omitempty" swaggertype:"object"` // Path where the file was saved (if Deploy=true, it's the path in the user's ~/.clab dir; if Deploy=false, it's the OutputFile path if provided). diff --git a/tests_go/events_suite_test.go b/tests_go/events_suite_test.go index 02b1501..b45e6f4 100644 --- a/tests_go/events_suite_test.go +++ b/tests_go/events_suite_test.go @@ -100,7 +100,7 @@ func (s *EventsSuite) TestEventsStreamJSONFiltersByLab() { _, expectedLabPresent := allowedLabs[s.apiLabName] s.Require().True(expectedLabPresent, "Expected API user lab '%s' to be visible in /api/v1/labs", s.apiLabName) - eventsURL := fmt.Sprintf("%s/api/v1/events?format=json&initialState=true", s.cfg.APIURL) + eventsURL := fmt.Sprintf("%s/api/v1/events?initialState=true", s.cfg.APIURL) lines, statusCode, err := s.collectEventLines(eventsURL, s.apiUserHeaders, s.streamTimeout(), 20) s.Require().NoError(err, "Failed to stream events") s.Require().Equal(http.StatusOK, statusCode, "Expected status 200 for events stream") @@ -123,7 +123,7 @@ func (s *EventsSuite) TestEventsStreamJSONFiltersByLab() { func (s *EventsSuite) TestEventsStreamJSONSuperuserSeesBothLabs() { s.logTest("Streaming JSON events as superuser (expecting labs '%s' and '%s')", s.apiLabName, s.suLabName) - eventsURL := fmt.Sprintf("%s/api/v1/events?format=json&initialState=true", s.cfg.APIURL) + eventsURL := fmt.Sprintf("%s/api/v1/events?initialState=true", s.cfg.APIURL) lines, statusCode, err := s.collectEventLines(eventsURL, s.superuserHeaders, s.streamTimeout(), 40) s.Require().NoError(err, "Failed to stream events") s.Require().Equal(http.StatusOK, statusCode, "Expected status 200 for events stream") @@ -162,7 +162,7 @@ func (s *EventsSuite) TestEventsStreamJSONLifecycleMessages() { labName := fmt.Sprintf("%s-events-life-%s", s.cfg.LabNamePrefix, s.randomSuffix(5)) topology := strings.ReplaceAll(s.cfg.SimpleTopologyContent, "{lab_name}", labName) - eventsURL := fmt.Sprintf("%s/api/v1/events?format=json", s.cfg.APIURL) + eventsURL := fmt.Sprintf("%s/api/v1/events", s.cfg.APIURL) ctx, cancel := context.WithTimeout(context.Background(), s.lifecycleTimeout()) defer cancel() @@ -236,19 +236,6 @@ func (s *EventsSuite) TestEventsStreamJSONLifecycleMessages() { } } -func (s *EventsSuite) TestEventsInvalidFormat() { - s.logTest("Testing events endpoint with invalid format parameter (expecting 400 Bad Request)") - - eventsURL := fmt.Sprintf("%s/api/v1/events?format=invalid", s.cfg.APIURL) - bodyBytes, statusCode, err := s.doRequest("GET", eventsURL, s.apiUserHeaders, nil, s.cfg.RequestTimeout) - s.Require().NoError(err, "Failed to execute invalid format request") - s.Assert().Equal(http.StatusBadRequest, statusCode, "Expected status 400 for invalid format. Body: %s", string(bodyBytes)) - - if statusCode == http.StatusBadRequest && !s.T().Failed() { - s.logSuccess("Correctly received status 400 for invalid format parameter") - } -} - func (s *EventsSuite) collectEventLines(url string, headers http.Header, timeout time.Duration, maxLines int) ([]string, int, error) { s.T().Helper() diff --git a/tests_go/lab_exec_suite_test.go b/tests_go/lab_exec_suite_test.go index 8084abc..11249b3 100644 --- a/tests_go/lab_exec_suite_test.go +++ b/tests_go/lab_exec_suite_test.go @@ -68,32 +68,6 @@ func (s *LabExecSuite) TestExecCommandInLab() { } } -func (s *LabExecSuite) TestPlainFormatExecCommandInLab() { - labName, userHeaders := s.setupEphemeralLab() - defer s.cleanupLab(labName, true) - - // Simple Linux command - command := "echo 'plain format test'" - payload := map[string]string{"command": command} - jsonPayload := s.mustMarshal(payload) - - s.logTest("Executing command '%s' in lab '%s' with plain format", command, labName) - - execURL := fmt.Sprintf("%s/api/v1/labs/%s/exec?format=plain", s.cfg.APIURL, labName) - bodyBytes, statusCode, err := s.doRequest("POST", execURL, userHeaders, bytes.NewBuffer(jsonPayload), s.cfg.RequestTimeout) - s.Require().NoError(err, "Failed to execute plain format command request") - s.Require().Equal(http.StatusOK, statusCode, "Expected status 200 executing plain format command in lab '%s'. Body: %s", labName, string(bodyBytes)) - - // Response should be plain text - responseText := string(bodyBytes) - s.Assert().NotEmpty(responseText, "Plain format exec command in lab '%s' returned empty output", labName) - s.Assert().Contains(responseText, "plain format test", "Plain format exec command output does not contain expected string.") - - if !s.T().Failed() { - s.logSuccess("Successfully executed plain format command in lab '%s'", labName) - } -} - func (s *LabExecSuite) TestNodeFilteredExec() { labName, userHeaders := s.setupEphemeralLab() defer s.cleanupLab(labName, true) diff --git a/tests_go/logs_suite_test.go b/tests_go/logs_suite_test.go index 049e870..f483b7b 100644 --- a/tests_go/logs_suite_test.go +++ b/tests_go/logs_suite_test.go @@ -143,7 +143,7 @@ func (s *LogsSuite) TearDownTest() { s.BaseSuite.TearDownTest() } -// TestBasicLogsRetrieval tests basic logs retrieval in plain format +// TestBasicLogsRetrieval tests basic logs retrieval in JSON format (default) func (s *LogsSuite) TestBasicLogsRetrieval() { s.logTest("Retrieving logs for node '%s' in lab '%s'", s.sharedNodeName, s.sharedLabName) logsURL := fmt.Sprintf("%s/api/v1/labs/%s/nodes/%s/logs", s.cfg.APIURL, s.sharedLabName, s.sharedNodeName) @@ -152,15 +152,23 @@ func (s *LogsSuite) TestBasicLogsRetrieval() { s.Require().NoError(err, "Failed to execute logs request") s.Require().Equal(http.StatusOK, statusCode, "Expected status 200 for logs request. Body: %s", string(bodyBytes)) - // For plain text logs, the response should have Content-Type: text/plain + // Verify we can parse the response as JSON + var logsResp struct { + ContainerName string `json:"containerName"` + Logs string `json:"logs"` + } + err = json.Unmarshal(bodyBytes, &logsResp) + s.Require().NoError(err, "Failed to unmarshal JSON logs response") + s.Assert().Equal(s.sharedNodeName, logsResp.ContainerName, "Container name in response should match requested node") + s.logSuccess("Successfully retrieved logs for node '%s'", s.sharedNodeName) } // TestLogsRetrievalJSON tests logs retrieval in JSON format func (s *LogsSuite) TestLogsRetrievalJSON() { - s.logTest("Retrieving JSON format logs for node '%s' in lab '%s'", s.sharedNodeName, s.sharedLabName) + s.logTest("Retrieving logs for node '%s' in lab '%s'", s.sharedNodeName, s.sharedLabName) - logsURL := fmt.Sprintf("%s/api/v1/labs/%s/nodes/%s/logs?format=json", s.cfg.APIURL, s.sharedLabName, s.sharedNodeName) + logsURL := fmt.Sprintf("%s/api/v1/labs/%s/nodes/%s/logs", s.cfg.APIURL, s.sharedLabName, s.sharedNodeName) bodyBytes, statusCode, err := s.doRequest("GET", logsURL, s.apiUserHeaders, nil, s.cfg.RequestTimeout) s.Require().NoError(err, "Failed to execute JSON logs request") s.Require().Equal(http.StatusOK, statusCode, "Expected status 200 for JSON logs request. Body: %s", string(bodyBytes)) @@ -191,26 +199,6 @@ func (s *LogsSuite) TestLogsRetrievalWithTail() { s.logSuccess("Successfully retrieved logs with tail=10 for node '%s'", s.sharedNodeName) } -// TestInvalidFormat tests error handling for an invalid format parameter -func (s *LogsSuite) TestInvalidFormat() { - s.logTest("Testing logs endpoint with invalid format parameter (expecting 400 Bad Request)") - - logsURL := fmt.Sprintf("%s/api/v1/labs/%s/nodes/%s/logs?format=invalid", s.cfg.APIURL, s.sharedLabName, s.sharedNodeName) - bodyBytes, statusCode, err := s.doRequest("GET", logsURL, s.apiUserHeaders, nil, s.cfg.RequestTimeout) - s.Require().NoError(err, "Failed to execute invalid format logs request") - - s.Assert().Equal(http.StatusBadRequest, statusCode, "Expected status 400 for invalid format. Body: %s", string(bodyBytes)) - - var errResp struct { - Error string `json:"error"` - } - err = json.Unmarshal(bodyBytes, &errResp) - s.Require().NoError(err, "Failed to unmarshal error response") - s.Assert().Contains(errResp.Error, "Invalid format", "Error message should mention invalid format") - - s.logSuccess("Correctly received status 400 for invalid format parameter") -} - // TestInvalidTail tests error handling for an invalid tail parameter func (s *LogsSuite) TestInvalidTail() { s.logTest("Testing logs endpoint with invalid tail parameter (expecting 400 Bad Request)")