diff --git a/cmd/agent_helpers.go b/cmd/agent_helpers.go
index 8782a961..1e3523c2 100644
--- a/cmd/agent_helpers.go
+++ b/cmd/agent_helpers.go
@@ -46,7 +46,7 @@ func setupAgent(
b := connectNATSBundle(ctx, log, connCfg, kvBucket, namespace, streamName)
providerFactory := agent.NewProviderFactory(log)
- hostProvider, diskProvider, memProvider, loadProvider, dnsProvider, pingProvider, netinfoProvider, commandProvider, containerProvider := providerFactory.CreateProviders()
+ hostProvider, diskProvider, memProvider, loadProvider, dnsProvider, pingProvider, netinfoProvider, commandProvider, dockerProvider := providerFactory.CreateProviders()
// Create file provider if Object Store and file-state KV are configured
hostname, _ := job.GetAgentHostname(appConfig.Agent.Hostname)
@@ -67,7 +67,7 @@ func setupAgent(
netinfoProvider,
commandProvider,
fileProvider,
- containerProvider,
+ dockerProvider,
b.registryKV,
b.factsKV,
)
diff --git a/cmd/api_helpers.go b/cmd/api_helpers.go
index 2d682651..5dedc404 100644
--- a/cmd/api_helpers.go
+++ b/cmd/api_helpers.go
@@ -63,8 +63,8 @@ type ServerManager interface {
GetMetricsHandler(metricsHandler http.Handler, path string) []func(e *echo.Echo)
// GetAuditHandler returns audit handler for registration.
GetAuditHandler(store audit.Store) []func(e *echo.Echo)
- // GetContainerHandler returns container handler for registration.
- GetContainerHandler(jobClient jobclient.JobClient) []func(e *echo.Echo)
+ // GetDockerHandler returns Docker handler for registration.
+ GetDockerHandler(jobClient jobclient.JobClient) []func(e *echo.Echo)
// GetFileHandler returns file handler for registration.
GetFileHandler(objStore file.ObjectStoreManager) []func(e *echo.Echo)
// RegisterHandlers registers a list of handlers with the Echo instance.
@@ -482,7 +482,7 @@ func registerAPIHandlers(
handlers = append(
handlers,
sm.GetHealthHandler(checker, startTime, "0.1.0", metricsProvider)...)
- handlers = append(handlers, sm.GetContainerHandler(jc)...)
+ handlers = append(handlers, sm.GetDockerHandler(jc)...)
handlers = append(handlers, sm.GetMetricsHandler(metricsHandler, metricsPath)...)
if auditStore != nil {
handlers = append(handlers, sm.GetAuditHandler(auditStore)...)
diff --git a/cmd/client_container.go b/cmd/client_container.go
index 3d85de55..2b6b2ec5 100644
--- a/cmd/client_container.go
+++ b/cmd/client_container.go
@@ -22,11 +22,11 @@ package cmd
import "github.com/spf13/cobra"
-// clientContainerCmd represents the clientContainer command.
+// clientContainerCmd represents the container parent command.
var clientContainerCmd = &cobra.Command{
Use: "container",
- Short: "Container management operations",
- Long: `Manage containers on target nodes.`,
+ Short: "Container runtime management",
+ Long: `Manage containers using runtime-specific subcommands.`,
}
func init() {
diff --git a/internal/provider/container/runtime/mocks/generate.go b/cmd/client_container_docker.go
similarity index 75%
rename from internal/provider/container/runtime/mocks/generate.go
rename to cmd/client_container_docker.go
index b47d6304..70c784a9 100644
--- a/internal/provider/container/runtime/mocks/generate.go
+++ b/cmd/client_container_docker.go
@@ -18,7 +18,17 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-// Package mocks provides mock implementations for testing.
-package mocks
+package cmd
-//go:generate go tool github.com/golang/mock/mockgen -source=../driver.go -destination=driver.gen.go -package=mocks
+import "github.com/spf13/cobra"
+
+// clientContainerDockerCmd represents the docker subcommand under container.
+var clientContainerDockerCmd = &cobra.Command{
+ Use: "docker",
+ Short: "Docker container operations",
+ Long: `Manage Docker containers on target nodes.`,
+}
+
+func init() {
+ clientContainerCmd.AddCommand(clientContainerDockerCmd)
+}
diff --git a/cmd/client_container_create.go b/cmd/client_container_docker_create.go
similarity index 82%
rename from cmd/client_container_create.go
rename to cmd/client_container_docker_create.go
index 53912f56..3fc93770 100644
--- a/cmd/client_container_create.go
+++ b/cmd/client_container_docker_create.go
@@ -29,8 +29,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// clientContainerCreateCmd represents the clientContainerCreate command.
-var clientContainerCreateCmd = &cobra.Command{
+// clientContainerDockerCreateCmd represents the clientContainerDockerCreate command.
+var clientContainerDockerCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a new container",
Long: `Create a new container on the target node from the specified image.`,
@@ -44,7 +44,7 @@ var clientContainerCreateCmd = &cobra.Command{
volumeFlags, _ := cmd.Flags().GetStringSlice("volume")
autoStart, _ := cmd.Flags().GetBool("auto-start")
- body := gen.ContainerCreateRequest{
+ body := gen.DockerCreateRequest{
Image: image,
AutoStart: &autoStart,
}
@@ -62,7 +62,7 @@ var clientContainerCreateCmd = &cobra.Command{
body.Volumes = &volumeFlags
}
- resp, err := sdkClient.Container.Create(ctx, host, body)
+ resp, err := sdkClient.Docker.Create(ctx, host, body)
if err != nil {
cli.HandleError(err, logger)
return
@@ -98,20 +98,20 @@ var clientContainerCreateCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerCreateCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerCreateCmd)
- clientContainerCreateCmd.PersistentFlags().
+ clientContainerDockerCreateCmd.PersistentFlags().
String("image", "", "Container image reference (required)")
- clientContainerCreateCmd.PersistentFlags().
+ clientContainerDockerCreateCmd.PersistentFlags().
String("name", "", "Optional name for the container")
- clientContainerCreateCmd.PersistentFlags().
+ clientContainerDockerCreateCmd.PersistentFlags().
StringSlice("env", []string{}, "Environment variable in KEY=VALUE format (repeatable)")
- clientContainerCreateCmd.PersistentFlags().
+ clientContainerDockerCreateCmd.PersistentFlags().
StringSlice("port", []string{}, "Port mapping in host:container format (repeatable)")
- clientContainerCreateCmd.PersistentFlags().
+ clientContainerDockerCreateCmd.PersistentFlags().
StringSlice("volume", []string{}, "Volume mount in host:container format (repeatable)")
- clientContainerCreateCmd.PersistentFlags().
+ clientContainerDockerCreateCmd.PersistentFlags().
Bool("auto-start", true, "Start the container immediately after creation")
- _ = clientContainerCreateCmd.MarkPersistentFlagRequired("image")
+ _ = clientContainerDockerCreateCmd.MarkPersistentFlagRequired("image")
}
diff --git a/cmd/client_container_exec.go b/cmd/client_container_docker_exec.go
similarity index 81%
rename from cmd/client_container_exec.go
rename to cmd/client_container_docker_exec.go
index 39db9bf4..e92cce0f 100644
--- a/cmd/client_container_exec.go
+++ b/cmd/client_container_docker_exec.go
@@ -30,8 +30,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// clientContainerExecCmd represents the clientContainerExec command.
-var clientContainerExecCmd = &cobra.Command{
+// clientContainerDockerExecCmd represents the clientContainerDockerExec command.
+var clientContainerDockerExecCmd = &cobra.Command{
Use: "exec",
Short: "Execute a command in a container",
Long: `Execute a command inside a running container on the target node.`,
@@ -43,7 +43,7 @@ var clientContainerExecCmd = &cobra.Command{
envFlags, _ := cmd.Flags().GetStringSlice("env")
workingDir, _ := cmd.Flags().GetString("working-dir")
- body := gen.ContainerExecRequest{
+ body := gen.DockerExecRequest{
Command: command,
}
@@ -54,7 +54,7 @@ var clientContainerExecCmd = &cobra.Command{
body.WorkingDir = &workingDir
}
- resp, err := sdkClient.Container.Exec(ctx, host, id, body)
+ resp, err := sdkClient.Docker.Exec(ctx, host, id, body)
if err != nil {
cli.HandleError(err, logger)
return
@@ -89,17 +89,17 @@ var clientContainerExecCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerExecCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerExecCmd)
- clientContainerExecCmd.PersistentFlags().
+ clientContainerDockerExecCmd.PersistentFlags().
String("id", "", "Container ID to exec in (required)")
- clientContainerExecCmd.PersistentFlags().
+ clientContainerDockerExecCmd.PersistentFlags().
StringSlice("command", []string{}, "Command to execute (required, comma-separated)")
- clientContainerExecCmd.PersistentFlags().
+ clientContainerDockerExecCmd.PersistentFlags().
StringSlice("env", []string{}, "Environment variable in KEY=VALUE format (repeatable)")
- clientContainerExecCmd.PersistentFlags().
+ clientContainerDockerExecCmd.PersistentFlags().
String("working-dir", "", "Working directory inside the container")
- _ = clientContainerExecCmd.MarkPersistentFlagRequired("id")
- _ = clientContainerExecCmd.MarkPersistentFlagRequired("command")
+ _ = clientContainerDockerExecCmd.MarkPersistentFlagRequired("id")
+ _ = clientContainerDockerExecCmd.MarkPersistentFlagRequired("command")
}
diff --git a/cmd/client_container_inspect.go b/cmd/client_container_docker_inspect.go
similarity index 88%
rename from cmd/client_container_inspect.go
rename to cmd/client_container_docker_inspect.go
index 14abfcd2..ffcc2f92 100644
--- a/cmd/client_container_inspect.go
+++ b/cmd/client_container_docker_inspect.go
@@ -29,8 +29,8 @@ import (
"github.com/retr0h/osapi/internal/cli"
)
-// clientContainerInspectCmd represents the clientContainerInspect command.
-var clientContainerInspectCmd = &cobra.Command{
+// clientContainerDockerInspectCmd represents the clientContainerDockerInspect command.
+var clientContainerDockerInspectCmd = &cobra.Command{
Use: "inspect",
Short: "Inspect a container",
Long: `Retrieve detailed information about a specific container on the target node.`,
@@ -39,7 +39,7 @@ var clientContainerInspectCmd = &cobra.Command{
host, _ := cmd.Flags().GetString("target")
id, _ := cmd.Flags().GetString("id")
- resp, err := sdkClient.Container.Inspect(ctx, host, id)
+ resp, err := sdkClient.Docker.Inspect(ctx, host, id)
if err != nil {
cli.HandleError(err, logger)
return
@@ -97,10 +97,10 @@ var clientContainerInspectCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerInspectCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerInspectCmd)
- clientContainerInspectCmd.PersistentFlags().
+ clientContainerDockerInspectCmd.PersistentFlags().
String("id", "", "Container ID to inspect (required)")
- _ = clientContainerInspectCmd.MarkPersistentFlagRequired("id")
+ _ = clientContainerDockerInspectCmd.MarkPersistentFlagRequired("id")
}
diff --git a/cmd/client_container_list.go b/cmd/client_container_docker_list.go
similarity index 85%
rename from cmd/client_container_list.go
rename to cmd/client_container_docker_list.go
index 3bbc55e1..f04346a4 100644
--- a/cmd/client_container_list.go
+++ b/cmd/client_container_docker_list.go
@@ -29,8 +29,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// clientContainerListCmd represents the clientContainerList command.
-var clientContainerListCmd = &cobra.Command{
+// clientContainerDockerListCmd represents the clientContainerDockerList command.
+var clientContainerDockerListCmd = &cobra.Command{
Use: "list",
Short: "List containers on target node",
Long: `List containers on the target node, optionally filtered by state.`,
@@ -40,17 +40,17 @@ var clientContainerListCmd = &cobra.Command{
stateFlag, _ := cmd.Flags().GetString("state")
limit, _ := cmd.Flags().GetInt("limit")
- params := &gen.GetNodeContainerParams{}
+ params := &gen.GetNodeContainerDockerParams{}
if stateFlag != "" {
- state := gen.GetNodeContainerParamsState(stateFlag)
+ state := gen.GetNodeContainerDockerParamsState(stateFlag)
params.State = &state
}
if limit > 0 {
params.Limit = &limit
}
- resp, err := sdkClient.Container.List(ctx, host, params)
+ resp, err := sdkClient.Docker.List(ctx, host, params)
if err != nil {
cli.HandleError(err, logger)
return
@@ -98,10 +98,10 @@ var clientContainerListCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerListCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerListCmd)
- clientContainerListCmd.PersistentFlags().
+ clientContainerDockerListCmd.PersistentFlags().
String("state", "running", "Filter by state: running, stopped, all")
- clientContainerListCmd.PersistentFlags().
+ clientContainerDockerListCmd.PersistentFlags().
Int("limit", 0, "Maximum number of containers to return")
}
diff --git a/cmd/client_container_pull.go b/cmd/client_container_docker_pull.go
similarity index 83%
rename from cmd/client_container_pull.go
rename to cmd/client_container_docker_pull.go
index 0173c56e..e610078c 100644
--- a/cmd/client_container_pull.go
+++ b/cmd/client_container_docker_pull.go
@@ -29,8 +29,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// clientContainerPullCmd represents the clientContainerPull command.
-var clientContainerPullCmd = &cobra.Command{
+// clientContainerDockerPullCmd represents the clientContainerDockerPull command.
+var clientContainerDockerPullCmd = &cobra.Command{
Use: "pull",
Short: "Pull a container image",
Long: `Pull a container image on the target node.`,
@@ -39,11 +39,11 @@ var clientContainerPullCmd = &cobra.Command{
host, _ := cmd.Flags().GetString("target")
image, _ := cmd.Flags().GetString("image")
- body := gen.ContainerPullRequest{
+ body := gen.DockerPullRequest{
Image: image,
}
- resp, err := sdkClient.Container.Pull(ctx, host, body)
+ resp, err := sdkClient.Docker.Pull(ctx, host, body)
if err != nil {
cli.HandleError(err, logger)
return
@@ -73,10 +73,10 @@ var clientContainerPullCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerPullCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerPullCmd)
- clientContainerPullCmd.PersistentFlags().
+ clientContainerDockerPullCmd.PersistentFlags().
String("image", "", "Image reference to pull (required)")
- _ = clientContainerPullCmd.MarkPersistentFlagRequired("image")
+ _ = clientContainerDockerPullCmd.MarkPersistentFlagRequired("image")
}
diff --git a/cmd/client_container_remove.go b/cmd/client_container_docker_remove.go
similarity index 81%
rename from cmd/client_container_remove.go
rename to cmd/client_container_docker_remove.go
index 21bfce7c..dcbfb97f 100644
--- a/cmd/client_container_remove.go
+++ b/cmd/client_container_docker_remove.go
@@ -29,8 +29,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// clientContainerRemoveCmd represents the clientContainerRemove command.
-var clientContainerRemoveCmd = &cobra.Command{
+// clientContainerDockerRemoveCmd represents the clientContainerDockerRemove command.
+var clientContainerDockerRemoveCmd = &cobra.Command{
Use: "remove",
Short: "Remove a container",
Long: `Remove a container from the target node.`,
@@ -40,12 +40,12 @@ var clientContainerRemoveCmd = &cobra.Command{
id, _ := cmd.Flags().GetString("id")
force, _ := cmd.Flags().GetBool("force")
- params := &gen.DeleteNodeContainerByIDParams{}
+ params := &gen.DeleteNodeContainerDockerByIDParams{}
if force {
params.Force = &force
}
- resp, err := sdkClient.Container.Remove(ctx, host, id, params)
+ resp, err := sdkClient.Docker.Remove(ctx, host, id, params)
if err != nil {
cli.HandleError(err, logger)
return
@@ -74,12 +74,12 @@ var clientContainerRemoveCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerRemoveCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerRemoveCmd)
- clientContainerRemoveCmd.PersistentFlags().
+ clientContainerDockerRemoveCmd.PersistentFlags().
String("id", "", "Container ID to remove (required)")
- clientContainerRemoveCmd.PersistentFlags().
+ clientContainerDockerRemoveCmd.PersistentFlags().
Bool("force", false, "Force removal of a running container")
- _ = clientContainerRemoveCmd.MarkPersistentFlagRequired("id")
+ _ = clientContainerDockerRemoveCmd.MarkPersistentFlagRequired("id")
}
diff --git a/cmd/client_container_start.go b/cmd/client_container_docker_start.go
similarity index 84%
rename from cmd/client_container_start.go
rename to cmd/client_container_docker_start.go
index fe518089..4037cead 100644
--- a/cmd/client_container_start.go
+++ b/cmd/client_container_docker_start.go
@@ -28,8 +28,8 @@ import (
"github.com/retr0h/osapi/internal/cli"
)
-// clientContainerStartCmd represents the clientContainerStart command.
-var clientContainerStartCmd = &cobra.Command{
+// clientContainerDockerStartCmd represents the clientContainerDockerStart command.
+var clientContainerDockerStartCmd = &cobra.Command{
Use: "start",
Short: "Start a stopped container",
Long: `Start a stopped container on the target node.`,
@@ -38,7 +38,7 @@ var clientContainerStartCmd = &cobra.Command{
host, _ := cmd.Flags().GetString("target")
id, _ := cmd.Flags().GetString("id")
- resp, err := sdkClient.Container.Start(ctx, host, id)
+ resp, err := sdkClient.Docker.Start(ctx, host, id)
if err != nil {
cli.HandleError(err, logger)
return
@@ -67,10 +67,10 @@ var clientContainerStartCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerStartCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerStartCmd)
- clientContainerStartCmd.PersistentFlags().
+ clientContainerDockerStartCmd.PersistentFlags().
String("id", "", "Container ID to start (required)")
- _ = clientContainerStartCmd.MarkPersistentFlagRequired("id")
+ _ = clientContainerDockerStartCmd.MarkPersistentFlagRequired("id")
}
diff --git a/cmd/client_container_stop.go b/cmd/client_container_docker_stop.go
similarity index 82%
rename from cmd/client_container_stop.go
rename to cmd/client_container_docker_stop.go
index bb744b57..7cebcbbd 100644
--- a/cmd/client_container_stop.go
+++ b/cmd/client_container_docker_stop.go
@@ -29,8 +29,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// clientContainerStopCmd represents the clientContainerStop command.
-var clientContainerStopCmd = &cobra.Command{
+// clientContainerDockerStopCmd represents the clientContainerDockerStop command.
+var clientContainerDockerStopCmd = &cobra.Command{
Use: "stop",
Short: "Stop a running container",
Long: `Stop a running container on the target node.`,
@@ -40,12 +40,12 @@ var clientContainerStopCmd = &cobra.Command{
id, _ := cmd.Flags().GetString("id")
timeout, _ := cmd.Flags().GetInt("timeout")
- body := gen.ContainerStopRequest{}
+ body := gen.DockerStopRequest{}
if cmd.Flags().Changed("timeout") {
body.Timeout = &timeout
}
- resp, err := sdkClient.Container.Stop(ctx, host, id, body)
+ resp, err := sdkClient.Docker.Stop(ctx, host, id, body)
if err != nil {
cli.HandleError(err, logger)
return
@@ -74,12 +74,12 @@ var clientContainerStopCmd = &cobra.Command{
}
func init() {
- clientContainerCmd.AddCommand(clientContainerStopCmd)
+ clientContainerDockerCmd.AddCommand(clientContainerDockerStopCmd)
- clientContainerStopCmd.PersistentFlags().
+ clientContainerDockerStopCmd.PersistentFlags().
String("id", "", "Container ID to stop (required)")
- clientContainerStopCmd.PersistentFlags().
+ clientContainerDockerStopCmd.PersistentFlags().
Int("timeout", 10, "Seconds to wait before killing the container")
- _ = clientContainerStopCmd.MarkPersistentFlagRequired("id")
+ _ = clientContainerDockerStopCmd.MarkPersistentFlagRequired("id")
}
diff --git a/cmd/provider_run.go b/cmd/provider_run.go
deleted file mode 100644
index 08129fcf..00000000
--- a/cmd/provider_run.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package cmd
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
-)
-
-var providerRunData string
-
-var providerRunCmd = &cobra.Command{
- Use: "run [provider] [operation]",
- Short: "Run a provider operation (internal)",
- Hidden: true,
- Args: cobra.ExactArgs(2),
- RunE: func(
- _ *cobra.Command,
- args []string,
- ) error {
- providerName := args[0]
- operationName := args[1]
-
- reg := buildProviderRegistry()
- spec, ok := reg.Lookup(providerName, operationName)
- if !ok {
- return fmt.Errorf("unknown provider/operation: %s/%s", providerName, operationName)
- }
-
- var params any
- if spec.NewParams != nil {
- params = spec.NewParams()
- }
- if providerRunData != "" && params != nil {
- if err := json.Unmarshal([]byte(providerRunData), params); err != nil {
- return fmt.Errorf("parse input data: %w", err)
- }
- }
-
- result, err := spec.Run(context.Background(), params)
- if err != nil {
- return err
- }
-
- output, err := json.Marshal(result)
- if err != nil {
- return fmt.Errorf("marshal result: %w", err)
- }
-
- _, _ = fmt.Fprintln(os.Stdout, string(output))
-
- return nil
- },
-}
-
-var providerCmd = &cobra.Command{
- Use: "provider",
- Short: "Provider operations (internal)",
- Hidden: true,
-}
-
-func init() {
- providerRunCmd.Flags().StringVar(&providerRunData, "data", "", "JSON input data")
- providerCmd.AddCommand(providerRunCmd)
- rootCmd.AddCommand(providerCmd)
-}
diff --git a/cmd/provider_run_registry.go b/cmd/provider_run_registry.go
deleted file mode 100644
index 8d5a57b1..00000000
--- a/cmd/provider_run_registry.go
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package cmd
-
-import (
- "context"
- "io"
- "log/slog"
-
- "github.com/retr0h/osapi/internal/exec"
- "github.com/retr0h/osapi/internal/provider/command"
- "github.com/retr0h/osapi/internal/provider/network/dns"
- "github.com/retr0h/osapi/internal/provider/network/ping"
- "github.com/retr0h/osapi/internal/provider/node/disk"
- nodeHost "github.com/retr0h/osapi/internal/provider/node/host"
- "github.com/retr0h/osapi/internal/provider/node/load"
- "github.com/retr0h/osapi/internal/provider/node/mem"
- "github.com/retr0h/osapi/internal/provider/registry"
- "github.com/retr0h/osapi/pkg/sdk/platform"
-)
-
-// PingParams holds the input for the ping.do operation.
-type PingParams struct {
- Address string `json:"address"`
-}
-
-// DNSGetParams holds the input for dns.get-resolv-conf.
-type DNSGetParams struct {
- InterfaceName string `json:"interface_name"`
-}
-
-// DNSUpdateParams holds the input for dns.update-resolv-conf.
-type DNSUpdateParams struct {
- Servers []string `json:"servers"`
- SearchDomains []string `json:"search_domains"`
- InterfaceName string `json:"interface_name"`
-}
-
-// buildProviderRegistry creates a registry with all known provider operations,
-// using platform detection to select the correct provider variant (Ubuntu,
-// Darwin, or generic Linux).
-func buildProviderRegistry() *registry.Registry {
- reg := registry.New()
-
- logger := slog.New(slog.NewTextHandler(io.Discard, nil))
- execManager := exec.New(logger)
- plat := platform.Detect()
-
- registerHostProvider(reg, plat)
- registerDiskProvider(reg, plat, logger)
- registerMemProvider(reg, plat)
- registerLoadProvider(reg, plat)
- registerPingProvider(reg, plat)
- registerDNSProvider(reg, plat, logger, execManager)
- registerCommandProvider(reg, logger, execManager)
-
- return reg
-}
-
-func registerHostProvider(
- reg *registry.Registry,
- platform string,
-) {
- var p nodeHost.Provider
- switch platform {
- case "ubuntu":
- p = nodeHost.NewUbuntuProvider()
- case "darwin":
- p = nodeHost.NewDarwinProvider()
- default:
- p = nodeHost.NewLinuxProvider()
- }
-
- reg.Register(registry.Registration{
- Name: "host",
- Operations: map[string]registry.OperationSpec{
- "get-hostname": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetHostname()
- },
- },
- "get-uptime": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetUptime()
- },
- },
- "get-os-info": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetOSInfo()
- },
- },
- "get-architecture": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetArchitecture()
- },
- },
- "get-kernel-version": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetKernelVersion()
- },
- },
- "get-fqdn": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetFQDN()
- },
- },
- "get-cpu-count": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetCPUCount()
- },
- },
- "get-service-manager": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetServiceManager()
- },
- },
- "get-package-manager": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetPackageManager()
- },
- },
- },
- })
-}
-
-func registerDiskProvider(
- reg *registry.Registry,
- platform string,
- logger *slog.Logger,
-) {
- var p disk.Provider
- switch platform {
- case "ubuntu":
- p = disk.NewUbuntuProvider(logger)
- case "darwin":
- p = disk.NewDarwinProvider(logger)
- default:
- p = disk.NewLinuxProvider()
- }
-
- reg.Register(registry.Registration{
- Name: "disk",
- Operations: map[string]registry.OperationSpec{
- "get-local-usage-stats": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetLocalUsageStats()
- },
- },
- },
- })
-}
-
-func registerMemProvider(
- reg *registry.Registry,
- platform string,
-) {
- var p mem.Provider
- switch platform {
- case "ubuntu":
- p = mem.NewUbuntuProvider()
- case "darwin":
- p = mem.NewDarwinProvider()
- default:
- p = mem.NewLinuxProvider()
- }
-
- reg.Register(registry.Registration{
- Name: "mem",
- Operations: map[string]registry.OperationSpec{
- "get-stats": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetStats()
- },
- },
- },
- })
-}
-
-func registerLoadProvider(
- reg *registry.Registry,
- platform string,
-) {
- var p load.Provider
- switch platform {
- case "ubuntu":
- p = load.NewUbuntuProvider()
- case "darwin":
- p = load.NewDarwinProvider()
- default:
- p = load.NewLinuxProvider()
- }
-
- reg.Register(registry.Registration{
- Name: "load",
- Operations: map[string]registry.OperationSpec{
- "get-average-stats": {
- Run: func(_ context.Context, _ any) (any, error) {
- return p.GetAverageStats()
- },
- },
- },
- })
-}
-
-func registerPingProvider(
- reg *registry.Registry,
- platform string,
-) {
- var p ping.Provider
- switch platform {
- case "ubuntu":
- p = ping.NewUbuntuProvider()
- case "darwin":
- p = ping.NewDarwinProvider()
- default:
- p = ping.NewLinuxProvider()
- }
-
- reg.Register(registry.Registration{
- Name: "ping",
- Operations: map[string]registry.OperationSpec{
- "do": {
- NewParams: func() any { return &PingParams{} },
- Run: func(_ context.Context, params any) (any, error) {
- pp := params.(*PingParams)
- return p.Do(pp.Address)
- },
- },
- },
- })
-}
-
-func registerDNSProvider(
- reg *registry.Registry,
- platform string,
- logger *slog.Logger,
- em exec.Manager,
-) {
- var p dns.Provider
- switch platform {
- case "ubuntu":
- p = dns.NewUbuntuProvider(logger, em)
- case "darwin":
- p = dns.NewDarwinProvider(logger, em)
- default:
- p = dns.NewLinuxProvider()
- }
-
- reg.Register(registry.Registration{
- Name: "dns",
- Operations: map[string]registry.OperationSpec{
- "get-resolv-conf": {
- NewParams: func() any { return &DNSGetParams{} },
- Run: func(_ context.Context, params any) (any, error) {
- pp := params.(*DNSGetParams)
- return p.GetResolvConfByInterface(pp.InterfaceName)
- },
- },
- "update-resolv-conf": {
- NewParams: func() any { return &DNSUpdateParams{} },
- Run: func(_ context.Context, params any) (any, error) {
- pp := params.(*DNSUpdateParams)
- return p.UpdateResolvConfByInterface(
- pp.Servers,
- pp.SearchDomains,
- pp.InterfaceName,
- )
- },
- },
- },
- })
-}
-
-func registerCommandProvider(
- reg *registry.Registry,
- logger *slog.Logger,
- em exec.Manager,
-) {
- p := command.New(logger, em)
-
- reg.Register(registry.Registration{
- Name: "command",
- Operations: map[string]registry.OperationSpec{
- "exec": {
- NewParams: func() any { return &command.ExecParams{} },
- Run: func(_ context.Context, params any) (any, error) {
- pp := params.(*command.ExecParams)
- return p.Exec(*pp)
- },
- },
- "shell": {
- NewParams: func() any { return &command.ShellParams{} },
- Run: func(_ context.Context, params any) (any, error) {
- pp := params.(*command.ShellParams)
- return p.Shell(*pp)
- },
- },
- },
- })
-}
diff --git a/docs/docs/gen/api/delete-node-container-by-id.api.mdx b/docs/docs/gen/api/delete-node-container-docker-by-id.api.mdx
similarity index 93%
rename from docs/docs/gen/api/delete-node-container-by-id.api.mdx
rename to docs/docs/gen/api/delete-node-container-docker-by-id.api.mdx
index 43c96215..a6bcc82b 100644
--- a/docs/docs/gen/api/delete-node-container-by-id.api.mdx
+++ b/docs/docs/gen/api/delete-node-container-docker-by-id.api.mdx
@@ -1,11 +1,11 @@
---
-id: delete-node-container-by-id
+id: delete-node-container-docker-by-id
title: "Remove a container"
description: "Remove a container from the target node. Use the force query parameter to remove a running container."
sidebar_label: "Remove a container"
hide_title: true
hide_table_of_contents: true
-api: eJztWFFv2zYQ/isHYg/JIDtK53SrgT24TQJ4aIuiTVFgmWfQ4tliIpEqeUrjGvrvw1GWrMTOmnbt0AJ5sizxjnffd3c83koo9InTBWlrxFC8xtxeIUhIrCGpDTqYO5sDpQgk3QIJjFXYh7cew8u5dQnC+xLdEgrpZI6EDsiCazS50hhtFhuN/b+MiATJhRfDc/GseT19IY1cYI6GpqNX42m7fmoLdJIN9GISifbfWImhOMYMCV9aha2ip8vxsYiEx6R0mpZieL4ST1E6dKOSUt6zVT384DShmFSTSLTW+yBhZI5iKFLrKTxGQjNAhaRURMLh+1I7VGJIrsToFopnNVJygYag0RCBQ4/uChU4WxJDciWzEmFvKs0ygqnMsv0IrINMzjADjxkmZB3sXeJyGJbu19Bd96wsdC+xChdoenhNTvZqPFfiSmZaSWLbGyOjXJvfD6PwZVqzKKpI+CTFXLIMLQte78lpsxCRyLV5jmbBYB1WVdSCodVnwdAyAlqhIT3X6GCPdbGX4+P9PrwoPYEn6Qg+aEpBGpBZkUpT5uh0AkkqnUw4pKRRkMtlE0aQITFXESi90OQjKI1C5xPrkF9afsUy6bJI0fj/gtz9weIoYrPY+7/PZe/jqPdn3Hsy2TxO+73Jzz+JLqohhRpgQybdQHYuM78F7WlIu5BjMgM7vzvP7uuyzTVhXtByp7czazOUrE/hXJYZre2qOHMc+sIaj0Hlo/gR/9wVCY3JMkmwIFR9EYV0REMsJosi00lI74MLz7KrbWPs7AITEpEoHBcD0vXOF3Y21WoXRXPrckliKMoyhPCtbE0RLuwMxsdQelRcvApnE/QeKNUemAr0xJbitcyLjHUfHcX42yCOe/joyaw3OFSDnvz18HFvMHj8+OhoMIjjOGYkHfoyI9+xSjonmWGG2+/y6nZFZgU1xZuinOk5JsskQ5AJL+xvodEWrh14bPvfrOZ9uKyH0tVnB3Yj+ulED8I5ei8X97DhDUkqPazX34R643UoFKhYc5JKs0B1R4h2Vb9LkVI+k1KE9uyA3Co2U4FfesKcVRMGm9E56z5t8QkvawwG3YEN5lJnHNlV1c3j8w0lk0iQpuBcC90o8FizPSbMRXVbvAmlu6Wf2YzPjFpPSEnWUkViEMfbSTk2If2b+N4c3/4rJuU90RxB538ThEEWKJUENklK5+pysYmM0wB03W2Q03iFgcfSByIVktSZv8fmSml+lBmsZUDObEkbI3Zuq0rkrQ3SB+sugXSOtqyThqttZ19tCBfodmZe7SQL3NjkKI6ZuIboEG1bpB5uk/rWyJJS6/RHVNCD0asxXOIS2jh6IPZHIPaXbWJPrZtppdBAD8bGl/O5TjRXmwJdrr0P7fEDuz8Cu4N/a5CMJZjb0nzNzuiBzW/G5tGuk7XuDUKre7Mjf6D0u6c0dK2UWh4uqDBcEFF93R2KA559HKyaPq46aJk9WGlVhaGDu6onCJPNBOINc1rT1p1DtG6kRIVYX7pCJxsWiWj9cNrcXv54dxZ6Sm3mNoivnRiFrnMzPuFTX0SCDanxOOzH/XAbKaynXIZAW18+twc+t9FcbUL2/xwP1dAQXtNBkUlt2PzSZWxPzca54K1EJIadGU3Xi6FW3CvzV169Ws2kx7cuqyp+XV+0edKjtJez7K6rdtf9+9+6d5p/icvOdT9MdMRQCL5CX0mn2YjPNGjv9bqv24dvPHPa6VBzozXLrj+Noy0tPOv4Ip++vwHSF8CglagmVSRSlApdILj+MAojkI7I1nnAkdEWo+OT5ydnJyIS8mb1uFUtwgY7LVqt6hVn9hJNVbUGEv9nG6vqH5hFq3Q=
+api: eJztWFFv20YM/ivEYQ/JIDtO53SrgT24TQp4WIeiTVFgmRfQOtq6RLpT76g0rqH/PvBk2U7srGnXDi2QJ0vykUd+H8njcaE0hdSbko2zaqBeUeGuCBBSZxmNJQ9T7wrgjIDRz4jBOk1deBMofpw6nxK8q8jPoUSPBTF5YAe+1eQra42drTV2/7IqUYyzoAZn6till+TPX6DFGRVk+Xz4cnSum6+uJI9iWlDjRK3eRloN1DHlxPSH0/Ss1dzoejofHatEBUorb3iuBmcL9ZTQkx9WnMmejfbBe2+Y1LgeJ2pleojLLRakBipzgeNjooygUyJnKlGe3lXGk1YD9hUltyA8bWDCGVmGVkMCngL5K9LgXcWCxxXmFcHeOdp5AueY5/sJOA85TiiHQDml7DzsXdJ8EJfuN7hddxyWppM6TTOyHbpmj50GzIW6wtxoZLG9NTIpjP31MIn/nDcUqjpRIc2oQJHheSnrA3tjZypRhbG/k50JUod1nazAMPqTYFiRAkaTZTM15GFPdImXo+P9LryoAkNg9AzvDWeAFjAvM7RVQd6kkGboMZV4QquhwHkbQ5ATC1cJaDMzHBKorCYfUudJPjr5JDLZvMzIhv+C3P3BkigSs8T7v8+w82HY+bPXeTJeP553O+Mff1CbqMb8aYGNaXQD2SnmYQva5zHnYoJhDm56d5Ld12VXGKai5PlObyfO5YSiT9MUq5yXdtWSOZ5C6WygqPJR75H83BUJrcmYplQy6a5KlFhMlkUMyzI3aczwg4sgsottY9zkglJWiSq91AM2zc4XbnJu9C6Kps4XyGqgqiqG8K1szQgu3ARGx1AF0lK5Su9SCgE4MwGECgosltI1FmUuuo+OevRLv9fr0KMnk07/UPc7+PPh406///jx0VG/3+v1eoKkp1DlHDasQu9RGBa4wy6vbpdjUdBQvK7IuZlSOk9zAkxlYXcLjVXh2oHHtv/tatlHanosXV1xYDeiH0/0KFxQCDi7hw2vGbkKsFx/E+q117FQkBbNaYZ2RvqOEN1U/TYjzuRAyghWxwcUTouZGsI8MBWiminaTN47/3GLT2RZazCYDdhgiiaXyK7rzTw+W1MyThQbjs4159UwkthQPWIqVH1bto2jO0SfuVxOi0ZJTEZRUSeq3+ttp+PIxsRvI3t9aocvmI73xHEIG+9t+EVZ4AwZXJpW3jeFYh0TzyPETZPB3tAVRQarECnUxGjycI/NtTbyiDksZQAnruK1ETu31RXJ1pb4vfOXwKYgVzXpInV2Y19jmWbkd+Zc46QI3NjkqNcT4lqWY5xtkXq4TeobixVnzpsPpKEDw5cjuKQ5rILogdjvgdiftol97vzEaE0WOjCyoZpOTWqkzpTkCxNC7I0f2P0e2O3/W2tkHcPUVfZL9kQPbH41No92naxNVxCb3Ju9+AOl3zylsV/lzMlkQcfJgkqai+5AHcjI42DRdnD1wYrZg2aScLAwuo4jB3/VjBDG6/nDa6G2YW9zCrHyJmMu1fLWFVvZuEgly4fn7fXlt7ensak0duqi+NKXYWw71/MTOfxVosSQBpbDbq8bryOlC1xgjLfl7XN73HMb1MU6cv/P4VADDdM1H5Q5GivmVz4XexpSzpRspRI12BjS3PAiMiMLjJbGWZaJ2GIxwUBvfF7X8rm5csvMR5uAk/yuS/cmDve/f+/045LmGxf/ONtRA6XkMn2F3ogRn2jQ3qtln7cPX3n6tNOh9m5r55v+tI6u+JGpx2f59O2Nkj4DBqNVPa4TlRFq8pHg5o9hHIZsiGydDxIZq+J0fPL7yemJShTeLCO3ykbcYKdFi0Wz4tRdkq3rlYEs72JjXf8DKoqs5A==
sidebar_class_name: "delete api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/container-management-api-container-exec.tag.mdx b/docs/docs/gen/api/docker-management-api-docker-exec.tag.mdx
similarity index 72%
rename from docs/docs/gen/api/container-management-api-container-exec.tag.mdx
rename to docs/docs/gen/api/docker-management-api-docker-exec.tag.mdx
index d04bbf28..7a0e24fc 100644
--- a/docs/docs/gen/api/container-management-api-container-exec.tag.mdx
+++ b/docs/docs/gen/api/docker-management-api-docker-exec.tag.mdx
@@ -1,7 +1,7 @@
---
-id: container-management-api-container-exec
-title: "Node/Container/Exec"
-description: "Node/Container/Exec"
+id: docker-management-api-docker-exec
+title: "Node/Docker/Exec"
+description: "Node/Docker/Exec"
custom_edit_url: null
---
diff --git a/docs/docs/gen/api/container-management-api-container-operations.tag.mdx b/docs/docs/gen/api/docker-management-api-docker-image.tag.mdx
similarity index 60%
rename from docs/docs/gen/api/container-management-api-container-operations.tag.mdx
rename to docs/docs/gen/api/docker-management-api-docker-image.tag.mdx
index d52cc96d..ddf9911f 100644
--- a/docs/docs/gen/api/container-management-api-container-operations.tag.mdx
+++ b/docs/docs/gen/api/docker-management-api-docker-image.tag.mdx
@@ -1,13 +1,13 @@
---
-id: container-management-api-container-operations
-title: "Node/Container"
-description: "Node/Container"
+id: docker-management-api-docker-image
+title: "Node/Docker/Image"
+description: "Node/Docker/Image"
custom_edit_url: null
---
-Container lifecycle operations on a target node.
+Docker image operations on a target node.
diff --git a/docs/docs/gen/api/container-management-api-container-image.tag.mdx b/docs/docs/gen/api/docker-management-api-docker-operations.tag.mdx
similarity index 60%
rename from docs/docs/gen/api/container-management-api-container-image.tag.mdx
rename to docs/docs/gen/api/docker-management-api-docker-operations.tag.mdx
index d67c27ac..33b16ebd 100644
--- a/docs/docs/gen/api/container-management-api-container-image.tag.mdx
+++ b/docs/docs/gen/api/docker-management-api-docker-operations.tag.mdx
@@ -1,13 +1,13 @@
---
-id: container-management-api-container-image
-title: "Node/Container/Image"
-description: "Node/Container/Image"
+id: docker-management-api-docker-operations
+title: "Node/Docker"
+description: "Node/Docker"
custom_edit_url: null
---
-Container image operations on a target node.
+Docker lifecycle operations on a target node.
diff --git a/docs/docs/gen/api/get-node-container-by-id.api.mdx b/docs/docs/gen/api/get-node-container-docker-by-id.api.mdx
similarity index 93%
rename from docs/docs/gen/api/get-node-container-by-id.api.mdx
rename to docs/docs/gen/api/get-node-container-docker-by-id.api.mdx
index f1d73908..bf25e7eb 100644
--- a/docs/docs/gen/api/get-node-container-by-id.api.mdx
+++ b/docs/docs/gen/api/get-node-container-docker-by-id.api.mdx
@@ -1,11 +1,11 @@
---
-id: get-node-container-by-id
+id: get-node-container-docker-by-id
title: "Inspect a container"
description: "Get detailed information about a specific container."
sidebar_label: "Inspect a container"
hide_title: true
hide_table_of_contents: true
-api: eJztWF9v2zYQ/yoEsYdkkGw5tbNUwB7Spu08rEXQpSvQzDNo8WwxkUiVPLlRDX334ShbtmO3SdsNaIE8WZbu//3ujrwFl+ASqwpURvOYvwBkElCoDCRTempsLugTExNTIhPMFZCoqUpYYjQKpcF2/tY84ChmjseX/Onq9fil0GIGOWgcn54Pxy392BRgvVDHRwFv/w1lo/+VkdBKeVINz3jAHSSlVVjx+HLBn4CwYE9LTElhKze2ICQf1aOAF8KKHBCs8wxa5MBjnhqH/jHginwtBKY84Bbel8qC5DHaEoJbAbkQdgbIxAw0spWEgFlwYOcgmTUlKj1jc5GVwA7GQlcBG4ssOwyYsSwTE8iYgwwSNJYdXEMVe9LDJmw3oRGFChMjYQY6hBu0ImxiueBzkSkpkGxfGRnkSv/aC/yXMXrbeB1wl6SQC+LBqiB6h1bpGQ94rvQfoGcUq15dB20wlPyiMLQJYUqCRjVVYNkBySIvh2eHHfaydMgcCovsg8KUCc1EVqRClzlYAkwqrEgQLBNaslxUKwixDJByFTCpZgpdwEotwbrEWKCXhl4RT1oVKWj3LZG7f7AIRWQWef/PpQg/nobvovDxaP047oSjn3/iNSHOgiuMduC1H0UR/Xwqgk19dXjgsQsaiVgURaYSXwjdK0cci11DzeQKEuQBLyyVDapG35WZjJXc51BTvzzmZekTfgvbKbArM2HDM1Y6kAwNK6xJwDmGqXKMQgcOyVK4EXmRkezBIIKTfhSFcPR4EvZ7sh+KX3rHYb9/fDwY9PtRFEUUZQuuzNBtWCWsFRWhDiF3+7zatu7sc21o3X12otGW+Z547Pq/omZmyjCFptA75MD+iN5dFtvhEr3JUfJI9mEwPSap97NsLZfotyXmVahnSt94G3Mxu4e4IZE1OZ5U3s2t+K1le8FxJhBc01fQF9Gd5pbWUn9spTLPuC3blloTcx3wxIJA+KL4ehZCAKocHIq82JZ+FB31w6gX9gYXvSh+FMVR9I5UFcbuBeG2nnNjkeWiKJSeuc4ejC7tqzdUXvKT6CSKTyI+qgOem1LfQ9FfJitzYA31vRV1pUARd+fCdjM18f+8UtDzOzU+03NljaY5zObCKjHJ4LOaCaSAH4y9HjtAGm73KNZXDQchYKpmZTPRSYuQUtGzyM63qnRXaQoio857FyZ+83QsSSG59jgrHVPTVjPIbWA0YisPu1To2RbsJsZkIPSOjrcpYArWl0p7QGG5kVThkrnKIeQrkFMirDX2btOfERnLwTmqR7XRcdjU97qOj8R6FF+uu9ko4KjQu9RWRdMiXy9nD69vM6968Kd5n5qMjibK6E0pdcD7+2bYUPvBuhoMbH3O+g+n2T1jeco2/q+6t+dlmApkJkmoK91Cw/NmpKBhFtAqmMMSQj6NzWTeg88d5S2ql9PcLSdTa8RetbIEUr0sL9/KTNlMGzrHbOhVGmEGdu/Iapwkhi0lgyiixK0S7bG2k9TeblLfaFFiaqz6CJKF7PR8yK6hYi2OHhL7IyT20W5inxs7UVKCZiEbaldOpypR1GsKsLlyzt/AHrL7I2S3/7n7hDbIpqbU8qEJ/wjZHOybrM3JQGlar/h9wtYB/SGp33dS6fwPmBraYNFGJmiWKjHvaiOhu1gd4upum9buQsnab7bsvNlTjdZrrj8poU3ONpddrQ8pYsGXiwx/jPVEPFg+PF/d+n9/e+EPlHSD9uxLD079kXO9oKOhzwNOhjTB6HWiTtRcnxzmwqNsuTgaNhjdvIPfjuViDdhvWCg2riLcYLfIhNJkTmkzEt9E95JTdHnA443N3qZRsZJ09KWvRL1YTISDNzara3r9vgRbNXFf3Yv8tlAqR8+Sx1ORudubsE3fDl4vz0iH7H9eE+4Nxurap+nS56l5zHnAr6Ha3HbS0u+rfPr+dn5fEQYleT1qbpcSrE9w8+E0SaDADZadzkp7vbasXzy7oNvsdh3eqjsvfa85i0VDcWGuQdd1ax3SfzKwrv8FFJgoYA==
+api: eJztWG1v2zYQ/isEsQ/JINlyamepgH1Im7bzsBZBl65AM8+gxbPFRCJV8uTGNfTfhyP9GrtN2m5AC+STJfl4L8+98uZcgsusqlAZzVP+ApBJQKEKkEzpsbGloL+YGJkamWCugkyNVcYyo1EoDbb1t+YRRzFxPL3kZya7Bjt8KbSYQAkah6fn/aEMX00F1rNzfBDx1VtfBsmvjISnS7aB0ZNZ/4xH3EFWW4Uznl7O+RMQFuxpjTkJDKxTC0LyQTOIeCWsKAHBOk+tRQk85blx6B8jrsjQSmDOI27hfa0sSJ6irSG6hcaFsBNAJiagkS05RMyCAzsFyaypUekJm4qiBnYwFHoWsaEoisOIGcsKMYKCOSggQ2PZwTXMUk96GDC7iY2oVJwZCRPQMdygFXEAcs6nolBSIOm+VDIqlf61E/l/huh1403EXZZDKegMziqid2iVnvCIl0r/AXpCQHWaJlqBoeQXwbDyCVMSNKqxAssOiBdZ2T87bLGXtUPmUFhkHxTmTGgmiioXui7BUrTkwooMwTKhJSvFbBk/rAAkX0VMqolCF7FaS7AuMxboo6FPdCafVTlo9y3I3R8siiJSi6z/51LEH0/jd0n8eLB+HLbiwc8/8YYizoKrjHbgpR8lCf18CsGQXC0ecQIANBKxqKpCZT4X2leOTsx3FTWjK8iQR7yylDmogrwrMxoquc+gkLw85XXtHX4rtnNgV2bE+mesdiAZGlZZk4FzDHPlGEEHDklTuBFlVRDvXi+Bk26SxHD0eBR3O7Ibi186x3G3e3zc63W7SZIkhLIFVxfoNrQS1ooZRR1C6fZZta3d2edq0Lr07KCxSvM9eOzav6RmZswwh5DoLTJgP6J3p8U2XKIzOsoeyS70xsfE9X6arfkS/TbHchbridI3XsdSTO7Brk9kwcejmTdzC781b884LQSCC3UFfRLdqW5tLdXHFVfmD27ztrXWdLiJeGZBIHwRvv4IRQCqEhyKstrmfpQcdeOkE3d6F50kfZSkSfKORFXG7g3CbTnnxiIrRVUpPXGtPTG60K/ZEHnJT5KTJD1J+KCJeGlqfQ9Bf5miLoEF6nsLakuBIm1PhW0XauTfvFDQ0zslPtNTZY2mPsymwioxKuCzkilIAT8Yez10gNTc7pGsr8IJioCxmtShqZMUIaWiZ1Gcb2XprtAcREGV966Y+M3TsSyH7NrHWe2YGq8kg9wOjMB25sMuF3qyFXYjYwoQekfG2xwwB+tTZTWjsNJIynDJ3MwhlMsgJ0dYa+zdqj8jMlaCc5SPaqPisLGvdS2PxLoVX66r2SDiqNCbFOaiUB9fLxoPb26fXBbgTxx8agoaSpTRmyyaiHf3da++9i112RLYesL6D/vYPVE8ZRvvy7rtzzLMBTKTZVSPbsXB89BM0DALaBVMYRE83oGhJ++JzB3hq3he9HG36EkrJfaKlTWQ6EVi+SJm6tBnaILZkKs0wgTs3mYVjKQDW0J6SUKOW3rZR9mOUzu7Tn2jRY25seojSBaz0/M+u4YZWwXRg2N/BMc+2nXsc2NHSkrQLGZ97erxWGWKqkwFtlTO+evXg3d/BO92P3eT0AbZ2NRaPhThH8GbvX2dNcwEStNWxW8StkbzB6d+306lyR8wN7S+ol1MFNYpKW9rI6E9X45vTXvl1nZYV7XnSjZ+r2WnYVE1WC+5/iS/BtdtrrpWpuSIFV9sMvwc64l4tHh4vrz2//72wk+UdIX2xxeGnPqZc72ho97PI06KBEw6raSVhPuTw1L4YFtsjvohVDcv4bchna/j9hvWicFUhBtsV4VQmtSpbUHsA8iXnEDmEU83VntbSnmkiUBJmoOJjI7N5yPh4I0tmoY+v6/BzoIDljckvzeUytGz5OlYFO72TmzTyIPXi5npkP3PC8O9qCwvgJquf56ap5xH/Bpmm3tPWv99lU3f3/bvK2BQkjeDcM+UYL2Dwx+nWQYVbhzZqbS04Vul+YtnF3Sv3U7IWwnoue9VZz4PFBfmGnTTrLRDeicFm+Zfd4Mp0A==
sidebar_class_name: "get api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/get-node-container.api.mdx b/docs/docs/gen/api/get-node-container-docker.api.mdx
similarity index 93%
rename from docs/docs/gen/api/get-node-container.api.mdx
rename to docs/docs/gen/api/get-node-container-docker.api.mdx
index 257fd8f5..a95cc55b 100644
--- a/docs/docs/gen/api/get-node-container.api.mdx
+++ b/docs/docs/gen/api/get-node-container-docker.api.mdx
@@ -1,11 +1,11 @@
---
-id: get-node-container
+id: get-node-container-docker
title: "List containers"
description: "List containers on the target node, optionally filtered by state."
sidebar_label: "List containers"
hide_title: true
hide_table_of_contents: true
-api: eJztWG1v2zYQ/isEP7UAncip3W0C+iF9SeGhG4o2RYGlhkGLZ4uJSKrkKYtm6L8PR1myHTttUrTABvRT7Ph4fO557o7krbiCkHldonaWp/yNDsgyZ1FqCz4wZxnmwFD6JSCzToFgLhrLoqjZQhcIHhSb1yygRDj6ZLngKJeBpxf8Redo9oe0cgkGLM5O305m/Q4zV4KX5C/wqeD9t4niKX8N+KdT0HvhggfIKq+x5unFij8H6cGfVpjTZr3P1INUfNpMBS+llwYQfIgLrDTAU567gPGj4JqCLiXmXHAPnyvtQfEUfQXiFjPnLQVyCRZZ50EwDwH8NSjmXYXaLtm1LCpgj2bS1oLNZFE8Fsx5Vsg5FCxAARk6zx5dQZ1G08ctZTcDJ0s9yJyCJdgB3KCXg5bHFb+WhVYSCXsHUhhtnw1F/GXWysMbwUOWg5G0BuuS7AN6bZdccKPtG7BL4mrYNKInI8rWMfG5Al/vULGQRdjj4izKvp0nvf7sJSxkVWBg6NgnLoviE39YhM5oBFNiLZwFt3jmK2uJ2ICuLEExWRRfjlS1CHhKu3PBwVaGEmTtiLKodcVFtJhu01Foo/GBdPwhb7SpDLOVmYNnbrHNDDrmAStvv5WFVmgjb54Nk+Rg5NoiLGN59KGfJFFxgsXToeCmhcjTYZI0VBkeQulsgLjvSZLQnwOtYCeWIy5ilYFFMpdlWegsluvxZaA1q31sbn4JGRFaeipu1O2Ol24+0+qQegvnjSTxqkorvleFObBLN2eTl6wKoIjd0rsMQmCY68BIKQhISOFGmrIg3+NxAr+OkmQAJ7/NB6OhGg3kL8Ong9Ho6dPxeDRKkpZYD4EydwuV9F5SApAW4VBUu+j6TsVCZYz0NVtQ6Uci+z53tEdG348OJvPt8Dtr0oZ6c+xIR4R/o9SBEL4mbtvqdej83Tvo517DlqMu9P0wD+t9F4NagUW90OB3xZTD+Un2RI1gvHhKQd+PuI1fst/1aOqBXWp7Q960kct7uJuQWZuB8zqq0Me/6zs6TguJENr+HLvt1+FW3tM5s8Vq7K47vrt+Rsp7kAgP4jcu0SS6NhBQmnLX+0lyMhokw8FwfD5M0idJmiR/8aYRHDVGg97V+1bw+GOWS7vcATJ3rgBp95B8zAFz8JG8vjiYcYo0VyzUAcF0YTeCg/fOfz3AV2TGDIRACumtEmELqQtQRxHnpqNfbMpveiA4KpQJguHN7WVdt7hr1QtX0GGvnX237rXkoxF8dKjbTmxs/l0DY5uby3fsuvfk8JRtfe/aTFzLMJfIXJZRfqrdhDmL9K7PO6/hGqJ6VYjyKUCpi3CPzZXS7f2SrdcwOXcVbkAc3FZVQFtbwL+dv4pJ7aquLSq447S83VvbIGnBziZjOjQ3Mscc2xN1uC/qBysrzJ3X/4BiA3b6dsKuoGZ9Fv0U9v8g7JN9Yc+cn2ulwLIBm9hQLRY609RjSvBGhxDfMz/V/e+rOz7Ui9szhK5t9O74Ifffn5L+IEkbwQ1g7mh+QG9i0b7uU35Mw4vjVXfYN8fZzljBX7dDgulmxvCetGzl2p409PBzxJKvn2PxphONuFh/OOseMr9/PI93Dm0XLi5fgz+Nt5LNZITOBy44AWl5GB4lR/FhUrqARsYEWz9Tb81pblO42uTp9xrptDEj3OBxWUhtCVflC9qrZfiCky8ueLo1X9mQPBXxokV2q9VcBvjgi6ahf7evbJrPKB3kvLjrnb0d1DdNIA7GcAX11hQkjmR4yjmNBO4P5yETgC+g6IYPGxRT+uI1wXggQ4/erW8Zj9kPHl0dDKh7fdp6O54u0D5DmmkjeA5SgY/xtT+fZhmU20TstVoipq/z16/OaZSzW523qjF6PwhqtWotzt0V2KbpMSJ9J4BN8y9Es1Ve
+api: eJztWG1v2zYQ/isEP7UAncipnW0C+iF9SeGhG4o2RYGlRkCLZ4uJRKrkKYtm6L8PR1rya9ukaIEN6Cdb0vF4z/Mcj+QtuQKfOV2htoan/LX2yDJrUGoDzjNrGObAULoFIDNWgWA2GMuiaNhcFwgOFJs1zKNEOPpouOAoF56nl/yFzW7AXf0hjVxACQavzt5MrlR8aytwkjx5PhW8f5oonvJXgH9aBc+7QKIjLriHrHYaG55eLvkzkA7cWY05TRbdpg6k4tN2KnglnSwBwflgbWQJPOW59Rj+Cq4JcSUx54I7+FRrB4qn6GoQO7RcRPxyAQZZ50EwBx7cLSjmbI3aLNitLGpgj66kaQS7kkXxWDDrWCFnUDAPBWRoHXt0A00aTB9Hvu4GVlZ6kFkFCzADuEMnB5HEJb+VhVYSKfYuSFFq83QowperqA1vBfdZDqWkMdhUZO/RabPggpfavAazIKKGbSt6MoJmHROfanDNFhVzWfg9Ls6D5ptJ0ovPXsBc1gV6hpZ95LIoPvKHIbSlRigrbIQ1YOdPXW0MEevRVhUoJoviy0hVjICnNDsXHExdUnasHFEKRVdcBIvpJh2FLjU+kI4/5J0u65KZupyBY3a+yQxa5gBrZ76VhSh0Ke+eDpPkIHJtEBZhbfTQT5KgOIXF06HgZQyRp8MkaWllOPCVNR7CvCdJQj8H6sAWliMuOD2BQTKXVVXoLKzY42tPY5b7sdnZNWREaOVofaOOM17b2ZVWh9SbW1dKEq+uteJ7qzAHdm1nbPKC1R4UsVs5m4H3DHPtGSkFHilSuJNlVZDv8TiBX0dJMoCT32aD0VCNBvKX4elgNDo9HY9HoySJxDrwlLkbUUnnJCUAaeEPodqOri9WzNdlKV3D5rT0A5F9qTvaI6OvRweTeRd+Z03aUGEOFemI4l8rdQDC18SNdV77zt+9QT9zGjYcddD3YR7W+3MMagUG9VyD2xZTDmcn2RM1gvH8lEDfj7i1X7Lf9lg2A7PQ5o686VIu7uFuQmYxA2dNUKHHv+07OE4LieBjfQ7V9uvh1s7RPrPBaqiuW767ekbKO5AID+I3DNEkui7Boyyrbe8nyclokAwHw/HFMEmfJGmS/MXbVnDUGAzihvwuqh2+ZLk0i60oZtYWIM1eGB9ywBxcYK5fGay0igRXzDceoewwt4KDc9Z9Hd1LMmMleE/y6I31weZSF6COQpzrcn65XnvTXWS0RCYIJW93x3R14uCQ57agPV5b83ZVYslBK/joUJGdmFDzu7rF1geW71hs78neGdt47qpLGMswl8hsllFaqu08OQ/ErrY5p+EWgm61D8IpQKkLf4/JldLxTMlWY5ic2RrXQRycVtVAUxvAv627Cbls664aKvjMJrlbUiNIGrA1yZj2yrXGIbv2RB3ui/reyBpz6/Q/oNiAnb2ZsBtoWJ9CP4X9Pwj7ZF/Yc+tmWikwbMAmxtfzuc40VZcKXKm9DzeZn+r+99UdH6rFcfeg0xpdN37IsfenpD9I0lbwEjC31Dmgq7CIl/qUH1PD4njZbfPtca/rsVp3FNxtbBFM1+2FdyRpVG2zydCjyBErvrqMhaNOMOJi9ee8u8b8/uEiHDq0mdswfIXhLBxL1n0R2ia44BRIpGN4lByFa0llPZYy5NnqkrrTotllcrlO1+/VzYmYEe7wuCqkNhRX7QqaKxJ9yckXFzzd6K7081KEke2pCEcuGrBczqSH965oW3odL9vUplHay1nxuev2JrpvakQcBHMDzUYzJHRmeMo5dQbuH85DGgFfiKLrQayjmNKD0xTGAxl69HZ16njMfnAH6yCg7hJqmk08HdA+VdppK3gOUoEL+OLnsyyDapOIvdJLxPTr/tXLC+robC/TnWUZvB8MarmMFhf2Bkzb9jEiPVOAbfsvu5lVgw==
sidebar_class_name: "get api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/post-node-container-exec.api.mdx b/docs/docs/gen/api/post-node-container-docker-exec.api.mdx
similarity index 93%
rename from docs/docs/gen/api/post-node-container-exec.api.mdx
rename to docs/docs/gen/api/post-node-container-docker-exec.api.mdx
index 7f283b94..2e4fb8d1 100644
--- a/docs/docs/gen/api/post-node-container-exec.api.mdx
+++ b/docs/docs/gen/api/post-node-container-docker-exec.api.mdx
@@ -1,11 +1,11 @@
---
-id: post-node-container-exec
+id: post-node-container-docker-exec
title: "Execute a command in a container"
description: "Execute a command inside a running container on the target node."
sidebar_label: "Execute a command in a container"
hide_title: true
hide_table_of_contents: true
-api: eJztWG1v2zYQ/isEsQ/JIMdO53SrgX5w2xTI1m5Bmq7YMs84i2eLjUSq5Mmxa+i/D0dZ8muTrOuAFsg3WT4e757n7kQ+C6nQx07npK2RPXk6w7ggFCBim2VglNDGa8UvXGGMNhMRW0OgDTphjaAEBYGbIAljFR79ZWQkCSZe9q7k89py+BoMTDBDQ8P++dmwcTHEGcZyEEmbowOO4UzJnjy3nn61ChsHHJaMpMe4cJrmsne1kM8QHLp+QQnv1bjsYZWCHJSDSObgIENC58MaAxnKnkysp/AYSc1Z50CJjKTDD4V2qGSPXIHRFjSXVZowQUOi9hAJhx7dFJVwtiDGZwppgeJgCGYeiSGk6WEkrBMpjDAVHlOMyTpxcI3zXjA9rECbtSzkuhVbhRM0LZyRg1aF5EJOIdUKiGOvg4wybZ4eR+GfYUWBLCPp4wQz4DU0z9nek9NmIiOZafMKzYThOi7LqAFDq38FQ8OJ0AoN6bFGJw7YF2d59uLwSLwuPAlP4EjcaEoEGAFpnoApMnQ6FnECDmJCJ7jAMpjXNSVSJOYqEkpPNPlIFEah87F1yC8tv+I1yTxP0Pj/gtz9weIq4rA4+7+voPWx3/qz03oyWD0Oj1qD77+TJVcc74Kenlk1Z8dbNZRg01hkxbJU6x6j8O8S3qM9TPCfaIj9Qp6nOg4t037v2fliNx07eo8xyUjmjhuMNAZMlhGsGYJzMJe7VN87Uk2Y+V0gy0jiDLI8Re7R1MtItlKQkWxz038ucezVTO8Mv6+U5kdIBZqpdtbwABJTcBpGKXqhjfjl9I+nv/dfvT0VY+syoNtyKSN5Y921NpOh0m5f1Wzu/64yFkq70PPzT6LXYCTbkOdhpxX1Vw1fg0iSpmC3MRkvqpKTZVmt9Lk1vqL6UefRbhWuWphpFRDHmBMqjuQLVdh7OxpqtQ+iCmbZk0URBs9uf7y3I3H2QhQeQ+XlzsbovaBEe7Fsrk3MTk46+FO302nhoyejVvdYdVvw4/HjVrf7+PHJSbfb6XQ6sgKmSMnvqZttxpusNqO7CA6EHa99HqvG0NasPpQb1G7i0nx47iweRqK25h25ZsKn5ygMLlK2oLu9vCEwCpwStqC8oNrRMvjaFbp7VHPjCp2z7haHONM05J5e86kN4QTdjtPTmSbBtvscxQmYCa5X0cjaFMHsdlqClKALHpqThMis4q+TEn7uCTP+IhFWIXIKd6d8GjLN0HuYoNBrJIgx6JQ7ZrtVG4I/3atcQ2eEmSy3F9cF+qm1z23KpwdtzcWyx5ct3+10drv8zIQRWveMyGGeWviSXX5PGPti7XdNdFVFlAAJG8eFc9X8WXX1y4AwTwCH5DROMRBY+MCgQgKd7pnSt3wElmsEjGxBqyD2bqsK5K0NEo98QTpDW1S9d8/SvmyS5AUbm5x0OsxazXEosx1Gj3cZfWugoMQ6/RGVaIn++Zm4xrloSuiB2G+B2B92iX1p3UgrhUa0xJnxxXisY81jJkeXae+1Nf6B3W+C3e5txy1jSYxtYR6G8DfB5sm+z2p1KFge+4IcUuskmwe/B3q/bnrLSGZIiWW9Kbc+IM/6R0+2WclqL+qjXNlueG0vtCrbWItRblrpSoOVMvWGaa2YW9enmkwSolwuhYdwog1GMlo+vKxvRz+/uwxnSy6Xi5WicFqnt3aJ371Xh8vxVc3WYOvaurxjsuYztiG0JUb9cLJdSXV8wJCR5CQruI+POkfhJsV4ZRDqeCki7dMN169C29QtVv3xhTTHCl/CGbXzFLThOAuX8lYVr1eSrWUke2vy33qAvXAhrRVJNuJFi8UIPL51aVny6w8FunnFeS0kBGVRac/PSvbGkPpt1Ww93YOL5XntUPzPkuJeTOqrr+GLb7CWPSkjeY3zdWWUBcLPyunr0wc/AwatZDkoI5kgKHSB4OqP51XKrUtevlq4M+EZvmpFP6grt9oO1kbR+W9vLnkcLOXDLAxC6eCG5UC4qYK0gYIwZcK7hUzBTAqYsG3lk4cHbM6erVkTstoLw2JRWVzaazRl2aBC/JuBKct/AOOVaH0=
+api: eJztWG1v2zYQ/isEsQ/JIMdO53SrgX5w2xTI1m5Bmq7YMs84i2eLjUSq5CmJa+i/D0dafm+SdR3QAvkmy8fj3fPcnchnJhX61OmStDWyJ49vMK0IBYjUFgUYJbTxWvELVxmjzUSk1hBog05YIyhDQeAmSMJYhQd/GZlIgomXvQv5wqaX6IavwcAECzQ07J+eDFV8izeYykEibYkOePcTJXvy1Hr61Sp83mwSfXBYMpEe08ppmsrexUw+Q3Do+hVlvFf02sMYvxzUg0SW4KBAQufDAgMFyp7MrKfwmEjNKZdAmUykww+Vdqhkj1yFyQYu5zFHmKAh0XhIhEOP7gqVcLYiBucK8grF3hDMNBFDyPP9RFgnchhhLjzmmJJ1Yu8Sp71guh8Ru2lZKHUrtQonaFp4Qw5aEcaZvIJcKyCOvQkyKbR5epiEf4YRf1kn0qcZFsBraFqyvSenzUQmstDmFZoJY3VY18kCDK3+FQwLWoRWaEiPNTqxx744y5MX+wfideVJeAJH4lpTJsAIyMsMTFWg06lIM3CQEjrB1VXAtCkokSMxV4lQeqLJJ6IyCp1PrUN+afkVr8mmZYbG/xfk7g8WVxGHxdn/fQGtj/3Wn53Wk8HycXjQGnz/nay54ngX9PTMqik73qihDBddRVbMS7VpMAr/zuE92MEE/4mG2C+UZa7T0DXt956dz7bTsaP3mJJMZOm4x0hjwGQewYohOAdTuU31vSPVhIXfBrJOJN5AUebIDZp7mchWDjKRbe77zyWOvZqrO8PvK6X5EXKB5ko7a3gAiStwGkY5eqGN+OX4j6e/91+9PRZj6wqg23KpE3lt3aU2k6HSblfVrO//LhoLpV3o+ekn0VtgJNtQlmGnJfUXC74GiSRNwW45E89ivcm6jst8aY2PPD/qPNouwWX/MqcC0hRLQsVhfKHyem9HQ6124RMxlj1ZVWHqbDfHezsSJy9E5TGUXelsit4LyrQX885aB+zoqIM/dTudFj56Mmp1D1W3BT8ePm51u48fHx11u51OpyMjMFVOfkfRbNK9yGo9urPgQNjxyocxdoW2ZvmJXON1HZfFV+fOymEkGmvekQsmfHcOwtQiZSu628sbAqPAKWErKitqHM2Db1yhu0cpL1yhc9bd4hBvNA25oVd8akM4Qbfl9PhGk2DbXY7SDMwEV6toZG2OYLbbLEPK0AUPi5OEKKziT5MSfuoJC/4cEcYQOYW7Uz4OmRboPUxQ6BUSxBh0zh2z2acLgj/RqFxAJ4SFrDdXNtW5c+Fzm/OhQVtzNu/uebN3O53t/j4xYXI23SJKmOYWvmR/3xPAvlj53VAc64cyIGHTtHIuTp5lP78M2HLvOySn8QoDdZUP3Ckk0PmO4XzL7J+vETCyFS2D2LmtqpC3Nkg86QXpAm0Vu+6eRX2+SJIXrG1y1Okwaw3BocC2GD3cZvStgYoy6/RHVKIl+qcn4hKnYlE/D8R+C8T+sE3sS+tGWik0oiVOjK/GY51qHjAlukJ7r63xD+x+E+x2bztoGUtibCvzMIS/CTaPdn1W43FgfuALEkijjawf+R7o/brprRNZIGWWlabS+oA8yx492Wb1qj1rDnF1e8FrOypL7ZlWdRsbHcpdRVVpsBSl3jC7kcBVaWqRUEZUyrnsEI60wUgm84eXzfXo53fn4XDJVXO21BOOmyxXrvDbt+pwNb5oSBtsXFrnN0xWfMY2hDaHqh+Otkuhjs8ZMpGcZET98KBzEK5SDFsBoZznEtIuyXD1LrTJ4GzZJl9Iboz4Et5Qu8xBG46zcjlvFem9kGwtE9lbEf/WAgwcs0G4mjbaJFvz6tlsBB7furyu+fWHCt00kt/oCUFgVNrzs5K9MeR+UzxbzXvvbH5+2xf/s7K4E5zmEmz4ChysZU/KRF7idFUgZZ3ws3L6+mTCz4BBK1kP6kRmCApdIDj+8Tym3Drn5cuFWxOf4Ysr+kFnudV2sDKaTn97c85zYa4iFmEwSgfXrArCdQzSBgrCuAnvZjIHM6lgwrbRJ08RWB9CG0MnZLUThtksWpzbSzR1vUCF+DcDU9f/AH7OaKI=
sidebar_class_name: "post api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/post-node-container-pull.api.mdx b/docs/docs/gen/api/post-node-container-docker-pull.api.mdx
similarity index 92%
rename from docs/docs/gen/api/post-node-container-pull.api.mdx
rename to docs/docs/gen/api/post-node-container-docker-pull.api.mdx
index 43b08b53..e967753b 100644
--- a/docs/docs/gen/api/post-node-container-pull.api.mdx
+++ b/docs/docs/gen/api/post-node-container-docker-pull.api.mdx
@@ -1,11 +1,11 @@
---
-id: post-node-container-pull
+id: post-node-container-docker-pull
title: "Pull a container image"
description: "Pull a container image on the target node."
sidebar_label: "Pull a container image"
hide_title: true
hide_table_of_contents: true
-api: eJztWNtu2zgQ/RWCTwkg31In2xWwD+kN8GIvQZqiD4lhjMWxxEQiVXKUxDX074uhZMW3bLuLLrAF+iZb5FzOOTPkaCUV+sTpkrQ1MpYXVZ4LEIk1BNqgE7qAFIU1gjIUBC5FEsYq7N8YGUmC1Mv4Wr5er5/9DgZSLNDQ7PxiMusMzYIhOY2kLdEBu5sodmg9/WEVdhY4AhlJj0nlNC1lfL2SrxAcuvOKMnbW2YwfnCaU03oayRIcFEjofNhhoEAZy8x6Co+R1JxeCZTJSDr8VGmHSsbkKox2MLhqsoQUDYm1hUg49OjuUQlnK9ImFfeQVyiOZmCWkZhBnh9HwjqRwxxz4THHhKwTR3e4jMPS4wazx56FUvcSqzBF08NHctBrgFzJe8i1AuLY10FGhTa/jKLwZtYwIOtI+iTDAngPLUte78lpk8pIFtr8hiZlsEY1Y8OW0NMrq5a8fifbDFuSyYqyyvP+AYAYcjTEu6Esc50EAge3nk2s9mOx81tMSEaydEw3aQzZNRo4EPJ2SJMQjsMFOjRJF5g4wn7aj8SNNKk2j3EOhJ5uJP+jbHKHrq/tINdzB245gLzUBuMX/dHLG9lCj49QlDl7bt82Jv41KbKu602wrmWnctIUHG3p+rIhgreFfb60xjfQnAxP9rlpgAi5Q5JgSaiYnW/Exq2dz7Q6RMfCugJIxrKqtNqjhxVza+di8kZUHlWgx9kEvReUaS9aufW3AD89HeLL8XDYw5Of573xSI178NPorDcen52dno7Hw+FwKBtQqpz8RlTgHCy5gAkLfyir7egugwFhFwJMK+wAYNd2+ntAdF3ii8rk1Ner2QU3xdAn+hx78PYMpPt2OCpUbYiTN9tw+QxOTs9iGM1Pkhdq3O8HBwTp19luCxpSQRmQeADfutv20sqfu4n+vJm+NoQpuk0paENn42dKlXcLbcR8SehDpEkGJsVNJObW5ghmz8LHDClDF6DsOBKFVXqhUQm/9ISF8ASEwTI6Z92XUXjLy0SB3nOAeoMqsQAdkNit3U4Gz5cvS2tCWOwX/lq3z+19bXM+ELQ1l23Zt11gPBweKHwTes66lEQJy9zCtyz+r4TxXGz8Xis+7G2UZZOkcm5XV+8CwtwYHJLTeI+BwKrRhkICnfuvcK6U5kfIRbtHwNxW9BTEQbeqCkeGQXqw7k6QLtBWTYVyfz8o8/0SapLkDVtOTodDZm3NcZDZHqOjfUY/GKgos05/RiV64vxiIu5wKToJ/SD2eyD2xT6x76yba6XQiJ6YGF8tFjrR3GZKdIX2Xlvjf7D7HbB7eqgRN8cIn5184w/H6o8m/P9ns45kgZRZnjBLG274YfSL5YCH18FqfdbXg26aHJTrydPdN2Pk9GkMfc+MNqRtDqNdEhlRKduhLNx2wiIZtQ/v1reoXz9ehXsHK+XyaSx7u86sm5F2JhS+XZqFDR7brM/DZeZp3uYzRUaSY28AHPWH/XCnZgQKCMps5+LDY/4uBasnnf/jDwMNLISPNChz0IbjqFzORhsmriWvlpGMN4b0zjwTxnRMo3At4+Wr1Rw8fnB5XfPfnyp0y4ake3Aa5gzK9Uoq7flZyXgBud8d7jdTOrpsD99j8R+P/AfRWI83hoebsFrGUkbyDpebXy7qaR3JDEGhC/k1r183WfSu2MjT9r1mVEfrHedhgPzbtdONqrn48/0Vy7f9ZlCEmpUOHvjrADw0odqAaqiK8N9K5mDSqhFwY5PFDtu1slMbIauDYKxWzYore4emrjtsiH8zMHX9FxHRfdc=
+api: eJztWNtu2zgQ/RWCTykg31In2xWwD+kN8GIvQZqiD4kRjMWxxEQiVXKUxDX074shZce3bruLLrAF+ibLnNs5Z0iOllKhz5yuSVsjU3nelKUAkVlDoA06oSvIUVgjqEBB4HIkYazC/rWRiSTIvUyv5Gub3aG7+R0M5FihoZuz88mNim+DCzlNpK3RAQeaKA5lPf1hFb5axYpOOAOZSI9Z4zQtZHq1lC8RHLqzhgoOFt2mD04Tymk7TWQNDiokdD4sN1ChTGVhPYXHRGqurQYqZCIdfmy0QyVTcg0mOwBcxhIhR0Ni5SERDj26e1TC2Ya0ycU9lA2Koxswi0TcQFk+S4R1ooQZlsJjiRlZJ47ucJGGpc8iYI89C7XuZVZhjqaHj+SgF1FcynsotQLi3FdJJpU2v4yS8M9NhF+2ifRZgRWwDS1qXu/JaZPLRFba/IYmZ6RGLWPDntDTS6sWvH6n2gI7hsmKuinL/gGAWAxoiK2hrkudBQ4Ht55dLPdzsbNbzEgmsnbMOGkM1UUZHEh5O6VJSMfhHB2abJ2YOMJ+3k/EtTS5No9pCYSeriW/iYLoazso9cyBWwygrLXB9Hl/9OJadtDjI1R1yZG7f6OLf02KbNt2E6wruRY6aQqBnhR9EVlgm2Dka2t8xOV4eLxPTEQhFA5ZhjWhYmq+ERW3dnaj1SEu5tZVQDKVTaPVHjcsl1s7E5PXovGoAjfOZui9oEJ70Wmtv4X2yckQX4yHwx4e/zzrjUdq3IOfRqe98fj09ORkPB4Oh0MZQWlK8htZgXOw4O4lrPyhqrazuwgOhJ0LMJ2qA4Drbae/B8R6i/iiLLn01WoOwdth2CT6nHuI9hlI9/1wVqi6FCevt+HyBRyfnKYwmh1nz9W43w8BCPKv8911M+SCCiDxAL4Ltx2l0z5vJfrTZvnaEOboNqWgDZ2OP9OnbC20EbMFoQ+ZZgWYHDeRmFlbIpg9Dx8KpAJdgHLNkais0nONSviFJ6yEJyAMntE5676MwhteJir0nhPUG1SJOeiAxG7jrmXwmd5lXU0Iq/2WX4n2oOErW/I5oK256Bq+6//xcHig5U3YalZNJGpYlBa+Zdt/JYBnYuP3SuvBNmrKZlnj3K6i3gZseUtwSE7jPQbqmqgKhQS69F8RXCnNj1CKzkbAzDb0lMTBsKoJJ4VBerDuTpCu0DaxN3lbPyjw/eaJRbLBVpCT4ZBZWxEcBLbH6Gif0fcGGiqs059QiZ44O5+IO1yItX5+EPs9EPt8n9i31s20UmhET0yMb+ZznWneYGp0lfZeW+N/sPsdsHtyaCOOBwifmnzRDwfqj034/89mm8gKqbA8W9Y2XOzDxJfKAQ+sg+XqlG8H6/F2EEeHQb0aOt19HCKnTxPoOyY2crc5h65rKYhq2Y1k4boTFsmke3i7ukb9+uEyXDxYMBdPQ9mbVYHrCWlnPuHrpZnbELEr/izcZp6mbT5aZCI594jjqD/sh0s1A1FBEGg3FR+e8HeZWD7J/R9/E4iwED7SoC5BG86jcSU7jYRcSV4tE5lujOhr95xKYIUJZF6mSbigsd1yOQOP713Ztvz6Y4NuEdm6B6dhxuhcLaXSnp+VTOdQ+t0Zf7O2o4vuMH4m/uPJ/yAsq0HH8JgTVstUykTe4WLzA0Y7bRNZICh0ob7496tYRe+SnTyZ721ObbKyOAuj5N+unW500fmf7y5Zx92ngyr0sHTwwB8J4CGmagOqoT3Cu6UsweRNVHL0yaqH7abZaZJQ1UEwlsu44tLeoWnbNTbEvxmYtv0L1wF9/A==
sidebar_class_name: "post api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/post-node-container-start.api.mdx b/docs/docs/gen/api/post-node-container-docker-start.api.mdx
similarity index 93%
rename from docs/docs/gen/api/post-node-container-start.api.mdx
rename to docs/docs/gen/api/post-node-container-docker-start.api.mdx
index d392628c..67b149d2 100644
--- a/docs/docs/gen/api/post-node-container-start.api.mdx
+++ b/docs/docs/gen/api/post-node-container-docker-start.api.mdx
@@ -1,11 +1,11 @@
---
-id: post-node-container-start
+id: post-node-container-docker-start
title: "Start a container"
description: "Start a stopped container on the target node."
sidebar_label: "Start a container"
hide_title: true
hide_table_of_contents: true
-api: eJztWFFv20YM/ivEYQ/JIDtO53SrgT147Qp4WLugSVFgmWfQOtq6RLpT76g0rqH/PvBky07srlnXAi2QJ59kkkd+H3kib6k0hdSbko2zaqDOGD0DQmBXlqQhdZbRWPLgLHBGwOjnxGCdpu5fViWKcR7U4EI9XUtOXqDFORVkeTI8HU1aExNXkkfZKKhxotqnkVYDdeoCv3SaWjPRE5WoQGnlDS/U4GKpfiH05IcVZ7Jla3nwzhsmNa7HiSrRY0FMPkQNiwWpgcpc4LhMlJE4S+RMJcrT28p40mrAvqLkDhjnTaw4J8uwtpCAp0D+mjR4V7Gxc7jGvCI4mKBdJDDBPD9MwHnIcUo5BMopZefh4IoWgyh62CB303FYmk7qNM3JduiGPXYaOJfqGnOjkcX3tZNJYezPx0n8Z9LwoOpEhTSjAkWHF6XIB/bGzlWiCmN/JzsXsI7rOmnBMPo/wdBSAkaTZTMz5OFAbEmUo2eHXXhRBYYQc+ed4QzQAuZlhrYqyJsU0gw9pkwe0GoocLFOLMiJhasEtJkbDglUVpMPqfMkL528Ep1sUWZkw/9B7v5gSRaJWxL93xfYeT/s/NnrPBlvlpNuZ/z9d6qWjPMUSmcDxd0f9R7Jz4cQbDDCNKWSSXdVEpOYLIsSlmVu0lgTR5dBNJe7DrvpJaVSGKWXCmLT7HvpphOj9wU2c75AVgNVVZH4OzmeEVy6KYyeQRVIAzsovUspBODMBBAIKbB4SjdYlLnYPjnp0U/9Xq9Dj55MO/1j3e/gj8ePO/3+48cnJ/1+r9frCdqeQpVz2PIKvceFZB9TEfZFddu7V9EAuBng1lGUmxmlizQnwFQEuztotOW+B4/d+NfSso+ccbHguxLAfkQ/Xh5RuaAQcH4PH84YuQqwkr8NdXo7dUiL5TRDO6dt36bO5YR2x/SbjDgjH8NqD1wonBY3NYRFYCrENFP0mbx3/uMe/ypia4fBbMEGMzS5ZHZdb58rFxtKxoliwzG4Frph5LFhe8RUqPqu+jqVPqz91OVy0jZ2YkGKlTpR/V5vtyRHNp4T6/yGzWfjMxblPdEcwtbzOgmjLnCGDC5NK++b42KTGc8j0FKwntgbuqbIYxUikZoYTR7usbnWRpaYw0oHcOoq3jixd1tdkWxtid85fwVsCnJVUzRyLG/tayzTnPzeymuCFIVbm5z0ekLcmuiYbTukHu+S+tpixZnz5j1p6MDwdARXtIA2jx6I/RaI/WGX2OfOT43WZKEDIxuq2cykRk6bknxhQog95QO73wK7/X9rj6xjmLnKfs7O6IHNL8bmyb4va9MbxG5FhqO2gXmg9OunNHatnDmZyEsXIvIyIg7UkUz8R8t1F1cftbweLY2uj0I7rvvrZvYeb2b3M+G1oW57gm9DyZhLtRrOYjcbhVSyWjxfTzC/vTmPfaWxMxfVV4EMY+e5uXeQL79KlDjSYHLc7XXjRCJBFRiTbTUMr2882njuArrcZO2nXI80ETLd8FGZo7HiReVzsdtAe6FEWiVqsHVJse3NII5tDcDjJDbSorVcTjHQa5/Xtbx+W5FfNLBfozc4FWQulkqbIGutBjPMw93hfju4g1erPukQvvDNx15Q1hOilfkwSquBUom6osX2BY7cY3xSTF/fNcYnwGC0qsd1ojJCTT4S3PwxjFcKWyo756tcVbTFffrH2blKFN6uwzt1F83v9We5bCTO3RXZum7dY3kWD+v6H7pgEhs=
+api: eJztWG1v20YM/ivEYR+SQbaVzulWA/vgtSvgYe2CJkWBZZ5B62jrEulOvaPSuIb++8BT/JLYXbOuBVognyzLJI98HpImb6k0hcybio2zaqBOGT0DQmBXVaQhc5bRWPLgLHBOwOjnxGCdpu5fViWKcR7U4Fw9c9kl+ckLtDinkixPhiejiW7fuoo8yhFBjRO1/jbSaqBOXOCXTtPT1VGtpeiJSlSgrPaGF2pwvlS/EHryw5pzObI1PnjnDZMaN+NEVeixJCYforjFktRA5S5wfEyUkSAr5FwlytPb2njSasC+puQOEmdtoDgny7CykICnQP6KNHhXs7FzuMKiJjiYoF0kMMGiOEzAeShwSgUEKihj5+HgkhaDKHrYwnbdcViZTuY0zcl26Jo9dlosl+oKC6ORxfeVk0lp7M9HSfxl0pKgmkSFLKcSRYcXlcgH9sbOVaJKY38nOxekjpomWYNh9H+CYc0KGE2WzcyQhwOxJVGOnh124UUdGEJMnHeGc0ALWFQ52rokbzLIcvSYMXlAq6HExSqroCAWrhLQZm44JFBbTT5kzpO8dPJKdPJFlZMN/we5+4MlWSRuSfR/n2Pn/bDzZ9p5Mt48Trqd8fffqUYyzlOonA0UT3+UPpKPDyHYYoRZRhWT7qpECRBkWZSwqgqTxbLoXQTRXO467KYXlElVVF6KiE177oWbTozeF9jM+RJZDVRdR+Lv5HhOcOGmMHoGdSAN7KDyLqMQgHMTQCCkwOIpXWNZFWL7+Diln/pp2qFHT6ad/pHud/DHo8edfv/x4+Pjfj9N01TQ9hTqgsOWV+g9LiT7mMqwL6rb3r2KBsDNALf6UGFmlC2yggAzEezuoLEu9z147Ma/kpZzpMHFgu9KAPsR/Xh5ROWSQsD5PXw4ZeQ6wI38baiz26lDWixnOdo5bfs2da4gtDum3+TEOfkY1rrnQum0uKkhLAJTKaaZos/kvfMf9/hXEVs5DGYLNpihKSSzm2a7r5xvKBknig3H4No2P4wktlSPmErV3NVd5dEHVJ+6QnpsaySWophoEtVP091iHNnYIVaZDZs/jM9YjvfEcQhb31fpF3WBc2RwWVZ73zaKTU48jxBLqXpib+iKIoN1iBRqYjRFuMfhWht5xAJudACnruaNE3uP1TXJ0Zb4nfOXwKYkV7flIg1561xjmebk99ZcG6Qo3DrkOE2FuBXLMc92SD3aJfW1xZpz58170tCB4ckILmkB6yR6IPZbIPaHXWKfOz81WpOFDoxsqGczkxnpMxX50oQQB8oHdr8Fdvv/NhhZxzBztf2cM9EDm1+MzeN9/6ztVBDnFFmL1qPLA6VfP6VxXuXcyTpeuRCRl+VwoHqy6PeWq/mt6a157bXbd29pdNML62XdX7XL93izuZ8KvS2D2/v7OqKcuVI321kcZ6OQSm4enq9WmN/enMXB0tiZi+o38Qzj6Lm5eJABQCVKHGmhOeqm3biSSGwlxpy72YZX9x3rsO7iutwk76dcjrQRMl1zryrQWPGi9oXYbRE+VyKtEjXYuqW45U2EWQTiAtciPU7iSC3qy+UUA732RdPI67c1+UWL/xV6g1OB6HyptAnyrNVghkW4u+ZvR3nw6mZuOoQvfAeyF53VrmhlU4zSaqBUoi5psX2VIzcanxTT13eh8QkwGK2acZOonFCTjwS3Pwzj5cKWyk6/lUuLdbGf/HF6phKFtwvyTgFG83v9WS5biTN3SbZp1u6xfBcPm+YfH+QTiw==
sidebar_class_name: "post api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/post-node-container-stop.api.mdx b/docs/docs/gen/api/post-node-container-docker-stop.api.mdx
similarity index 92%
rename from docs/docs/gen/api/post-node-container-stop.api.mdx
rename to docs/docs/gen/api/post-node-container-docker-stop.api.mdx
index f6ac7ca8..8485685b 100644
--- a/docs/docs/gen/api/post-node-container-stop.api.mdx
+++ b/docs/docs/gen/api/post-node-container-docker-stop.api.mdx
@@ -1,11 +1,11 @@
---
-id: post-node-container-stop
+id: post-node-container-docker-stop
title: "Stop a container"
description: "Stop a running container on the target node. Optionally specify a timeout before the container is killed."
sidebar_label: "Stop a container"
hide_title: true
hide_table_of_contents: true
-api: eJztWG1v20YM/iuHwz4kg+zIrdOtAvrBTVsgw7oGSYoCyzyD1tHWJdKdekclcQ3994Enyy+x22ZdO7RAvskyySOfh6R4nEuFPnW6JG2NTOQZ2VKAcJUx2kxFag2BNuiENYIyFARuiiSMVdgVb4IW5PlM+BJTPZkJEKQLtBWJMU6sw6C0sqK9uNJ5jqr7l5GRJJh6mVzIo1Zg9BoMTLFAQ6PByfFoqTmyJTrg47wcRnL561jJRJ5YT39YhUszHIWMpMe0cppmMrmYy+cIDt2gooxPXBpObpwmlMN6GMkSHBRI6HzQMFCgTGRmPYXHSGqGqATKZCQdvq+0QyUTchVGd3A8b3CCKRoSrYVIOPTorlEJZytigK8hr1DsjcDMIjGCPN+PhHUihzHmwmOOKVkn9q5wlgTR/Qa4246FUndSq3CKpoO35KDToDmX15BrBcS+t05GhTbPelH4Z9RwKOtI+jTDAliHZiXLe3LaTGUkC21+RzNlsHp1HS3B0OpfwXC0Yl6hIT3R6MQe2+Ioj1/sd8XrypPwBI7EjaZMgBGQlxmYqkCnU5Fm4CAldAKMEgXM2nQSORJzFQmlp5p8JCqj0PnUOuSXll+xTjYrMzT+vyB3f7A4i9gtjv7vC+h8GHT+jDtPh6vHUbcz/PknWXPG8Sno6blVMza8CV5bXsJzUa6Ss7sB+wRyj1FIaDTEVqAsc52G8ji49Gxqvu28HV9iSjKSpeNiIo0BgUX1rglqQzhFJ+9Se4apNcoLsuIG9LLeubw5sTfqvite4ASqnIJ4L26oKLTRRVXIJI5kAbfN8+M45pOCtEx68f0Zs4UmLEqaBcriqIDbZ4/jWNZ1HUnSlON6QnKLOG3QZ4maIfWlNb7B4VH8aJuQVTYHRiBNsSRUzMdXgv/Sjkda7cqxiXUFkExkVYUavNNuMhSXdiyOX4jKo2KUS2dT9F5Qpr1Y5Bl7irdQlAGLw8MYf+3HcQcfPR13+j3V78AvvSedfv/Jk8PDfj+OGb0ADFO35hU4BzNuBISF3xXVpnenwYCwEwFr34JcTzCdpTkKSFmwu4XGsvPuwGM7/laaz+HsC723ywHsRvTznSooF+g9TO/hwxkBVV4s5DehTtcyBxyhYstpBmaK676Nrc0RzJbpdxlShi6Etfz0icIqdlMJP/OEBZsmDD6jc9Z93uOXLNY6LPQabGICmr/SsimMttdcrCgZ7qipQeCxYfuYsJD1XfU2lT6ufWRz/ug1dkI9LsqzH8fbFXlsQgNo8/tOk/xKRXlPNAdi7XebhEFXUAYkbJpWzjXtYpUZrwLQXLAOyWm8xsBj5QORCgl07u9xuFJ68bVY6AgY8xi2dGLnsapCPtog3Vh31c5u4Wjut/f4DJwvg2SFjUMO43i99YZs2yK1t03qWwMVZdbpD6hERwxOjsUVzsQyjx6I/RGIfbxN7CvrxlopNKIjjo2vJhOdau42JbpCex+m+wd2fwR2+5+ajowlMbGV+ZqT0QOb34zNw11f1mY24Dm33FgEPFD6/VMaplbKLO9GSusD8nxbT+QBL24O5u0UVx8seT2Ya1Uf+HZx4q6bLchwtUU5Y1ob5tZ3KctIMqKgG8R4mA1CMlo8vGovML+9Ow9jJafL6er++7INb+0S2ot5ejcT27xt4h2EAXW1KOIBQUaSHW6g63Xjbri4cOwFhJxcrC8W661l1Hdhn69y+/9ehTUgEt7SQZmDNhxA5XL2qSHvQvJRMpLJ2kZqPZIkXAwDhcMoTOqsNJ+PweNbl9c1v35foZs1xF6D0zBmTC/mUmnPz6uFwkdx2TtdDGL74htvuXZi0l5BDV9Ag7RMpIzkFc7Wl3W8s/qimL6/ldUXwKCVrId1JDMEhS4Q3Pxx1ITcOWf1leJWG2f4Go1B2HJ8Una41m9O3pydc80vNlpF6HbSwQ0vreCmcdKWzSY3mTfv5jIHM63CNVs2NrlDwGaDudNQQlQ7YZjPG4lze4WmrpeoEP9mYOr6Hz6Q/hg=
+api: eJztWG1v20YM/iuHwz4kg2zLrdOtBvohTVogw7oGSYoCy7yA1tHWNdKdekclcQ3994F3ll/itM26dmiBfJNlkkc+D0nxOJcKfeZ0RdoaOZSnZCsBwtXGaDMVmTUE2qAT1gjKURC4KZIwVmFXvA5aUBQz4SvM9GQmQJAu0dYkxjixDoPSyor24lIXBaruX0YmkmDq5fBcHtrsEt3FKzAwxRINXewfH12o+NZW6IAP8nKUyOWvIyWH8th6+sMqPGhPiJY4CplIj1ntNM3k8HwunyM4dPs15XxitD28dppQjppRIitwUCKh80HcQIlyKHPrKTwmUjM+FVAuE+nwfa0dKjkkV2NyC8SzCBJM0ZBoLSTCoUd3hUo4WxOjewVFjWLnAswsERdQFLuJsE4UMMZCeCwwI+vEziXOhkF0N6J207FQ6U5mFU7RdPCGHHQilHN5BYVWQOx762RSavOsn4R/LiKBskmkz3IsgXVoVrG8J6fNVCay1OZ3NFNGqt80yRIMrf4VDAcr2hUa0hONTuywLY7y6HC3K17VnoQncCSuNeUCjICiysHUJTqdiSwHBxmhE2CUKGHW5pIokJirRCg91eQTURuFzmfWIb+0/Ip18lmVo/H/Bbn7g8VZxG5x9H+fQ+fDfufPtPN0tHq86HZGP/8kG844PgU9PbdqxoY3wWtrS3iuyFVydjdgn0DhMZEMChpiK1BVhc5ChfTeeTY133bejt9hRjKRleN6Io0BgUXprglqQzhFJ29Te4qZNcoLsuIa9LLYubY5sTeKvisOcQJ1QUG8n0YqSm10WZdymCayhJv4/DhN+aQgLYf99P6M2VITlhXNAmVpUsLNs8dpKpumSSRpKlho1RxOIvT8d8N4+soaH0F4lD7aZmOVyoEOyDKsCBWT8ZWwf2fHF1rdlWAT60ogOZR1HQrwVq/JUbyzY3F0KGqPiiGunM3Qe0G59mKRZOwp3kBZBSD29lL8dZCmHXz0dNwZ9NWgA7/0n3QGgydP9vYGgzRl6AIwzNuaV+AczLgLEJb+rqg2vTsJBoSdCFj7ChR6gtksK1BAxoLdLTSWbfcOPLbjb6X5HE690Hi7HMDdiH6+TQXlEr2H6T18OCWg2ouF/CbU2VrmgCNUbDnLwUxx3bextQWC2TL9NkfK0YWwlp8+UVrFbirhZ56wZNOEwWd0zrrPe/yCxVqHhV6DTUxA8/dZxsJoG835ipLR7YLaDyRGqo8IS9nc1m3z6COqB7bgb100EipxUZiDNN2uxSMT6r7N7Fu98SuV4z1x3Bdrv9v0C7qCciBhs6x2LjaKVU68DBBzqTokp/EKA4O1DxQqJNCFv8fhSunFR2KhI2DMo9fSiTuPVTXy0Qbp2rrLdl4LR3ObvUf3P1sGyQobh+yl6XrHDXm2RWp/m9Q3BmrKrdMfUImO2D8+Epc4E8skeiD2RyD28TaxL60ba6XQiI44Mr6eTHSmuc9U6ErtfZjrH9j9EdgdfGouMpbExNbma85ED2x+Mzb37vqyxqmAJ9xq4/L/QOn3T2mYVym3vBWprA/I8yV9KHu8rOnN2/mt6S157cUtSG+uVdPz7c7EXcUdyGi1QDlldiOB62uUZUA5UdANYjzNBiGZLB5etjeY396ehbmSs+Zkdft90Ua5dgXtpzy+m4mNb2PY+2FCXa2JeE6QiWSHI4L9btoNNxeGoISQmovlxWKztQz+NvrzVYr/31uwCCLhDfWqArThAGpXsE+Rw3PJR8lEDtf2URuRBCJZIFwRA5ejJMzsrD2fj8HjG1c0Db9+X6ObRYavwGkYM7jnc6m05+fVXuGjAO2cLAazXfGNl113gtNeRg1fRYO0HEqZyEucre/seHX1RTF9f5urL4BBK9mMmkTmCApdIDj+cRBD7pyx+kpxq60zfFFjP+w7Pik7Wus/x69Pz7j4F4utMnQ/6eCad1dwHZ20VdzpDufx3VwWYKZ1uHDLaJNbBWx2mludJUR1JwzzeZQ4s5dommaJCvFvBqZp/gEfcf49
sidebar_class_name: "post api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/post-node-container.api.mdx b/docs/docs/gen/api/post-node-container-docker.api.mdx
similarity index 92%
rename from docs/docs/gen/api/post-node-container.api.mdx
rename to docs/docs/gen/api/post-node-container-docker.api.mdx
index 5d948d63..5dd3eeaf 100644
--- a/docs/docs/gen/api/post-node-container.api.mdx
+++ b/docs/docs/gen/api/post-node-container-docker.api.mdx
@@ -1,11 +1,11 @@
---
-id: post-node-container
+id: post-node-container-docker
title: "Create a container"
description: "Create a new container on the target node. Returns a job ID for tracking the asynchronous operation."
sidebar_label: "Create a container"
hide_title: true
hide_table_of_contents: true
-api: eJztWG1v28gR/iuL/ZQAlEzZcppjkQ9O4hRur43hOHdoHUMYkSNxY3KXtzuUrQr874fZFSnqxbGvuBZXIN/4MrP77Lw8szMrmaFLrapIGS0T+c4iEAoQGu9FajSB0miF0YJyFAR2jiS0yXAorpBqq50A8dVMxcV7MTNWkIX0Tum5Fwe31GlujTa1E6ZCC7zL8IuWkSSYO5ncyHftHpO/g4Y5lqhpcnZ5Mek2n3SaTt5Gsnu7yGQiL42jf5gMu2VkJB2mtVW0lMnNSr5FsGjPasp5t27R5N4qQnnb3EayAgslElrnNTSUKBOZG0f+MZKKLVMB5TKSFn+plcVMJmRrjHbMdx0MBHPUJNoVImHRoV1gJqypia2zgKJG8WICehmJCRTFy0gYKwqYYiEcFpiSseLFHS4TL/oyGO1hYKBSg9RkOEc9wAeyMAiWXMkFFCoDYuwtyKhU+s0o8n8mwXmyiaRLcyyBdWhZsbwjq/RcRrJU+kfUczbWqGHb8Ero6K3Jliy/EyxdfKQcNsposbHl8ICx2PyoiVeCqipU6pWOvjpebrWPy0y/YkoykpVlt5NCf1JVwhwPwX8MnlcQFmdoUacoXuBwPozEF6nnSj8kBRA6+iJfMmZ8gLIqeNn+z//Y+LJponVIPYX3o3+AQrB4yKYcN0m4Da5cDjw+9mdqyhJ01tsBrIXlAYN4OUFG2FoLpfc3UISl24fa9La+CYaRkRz4MwCWRgszm/1Z3rKcXjwJ5FwvlDWac10swCqYFugYz9/O//nmp7MfP5/z8UugZ0O6/Hh1/eZ1/DqWkXx//vbzX95wxHlAlbHknoR0aSyJEqpK6bmHwtk7Yd1kw0T82iLzCfksbAwr8chej8cnyXh84nEtTFGX+DSyn7ycKE2tqYcMKO8jA8p/O7KjDAiSowXYo0JN/ZuHBjWZiSOw1FthakyBoPfw/Zwj5Wg5qrzKdlAJVZaYKSAslgJm1COLoXiPM6gLcqzL/grQs/A1kAanz4ZGbta5fxtJUuQTocvyULquAmHJpgmarjLaBSsfx8fP4jBIU6wIMw6+34mxvprpRGWHKCD4TCayrlW2Z9vrHNvqWjv0mVtZk6JzgnLlxJqet6nh9DTG1+M4HuDxD9PBeJSNB/Cn0avBePzq1enpeBzHcSyDcdj4BwJwN3i6U22j+1SXJdilUDqcwhtvamoSsM0q28boKuuTjMjHb6WFmYVLBdfWIeM/bNBHa0CGmtRM7RIpjKbH6Uk2xtPZK/lsrt6sy/KPU/MzS9WFL1DexdPlt2h/qyZxKSdfdJ6EW1vLZLtJS6+4vbattV5zhM8F/E327dKHVImOoKy2Vz+Oj8eDeDQYnV6P4uQkTuL4X36rHPR8a6sniSbHzW1SlCZjr2bCLR1h2R6Mic5aY58+wjmLiRKdYx+oXpSJGaiCeWCXhLoIPsRDV2vOkc2uWptwj2jVBb0zBd/9lNH9VZpIjuN4n7sutL92tCwgKlgWBn5P3nqmCc9E771NVK8rKAcSJk05ALPtiPjgretvI0hW4QK982rnvZchgSoOlLC9zbNMrS9Oa501CXUgDm6b1chba6R7Y+981Jo6EAtf8Xr7Kk04953FPjuFQ7LC1ianccxea73sQ2zPo6N9j37WUFNurPo3ZmIgzi4vxB0uRRdE3x37/+DYk33HfjB2qrIMtRiIC+3q2UyliimmQlsq53x3+927f3zvnh4i4lBCQgXU8+3a/d2lf2yXNpEskXLD06TK+E7fj3oSecRzrqNVW+ybo3RryGQXYWJ0u5k4fWJnBn/1504d/pyokuv5i7/peCEZrR8+tL3AX3++9ncODpKrzQTmvD1UNwLZnVGsZ1fdDbQ3G/hW277u2h9vo7su+nA322tmH2kqt3tK39jxXG1mvHXWzjnzl67NHJDrn4wk2zn4eTSMh751YUeV4BNofeRucNl30laUrDap+D8ccwbHEz7QUVWA0oy+tgXDCWF2I3kfGcmkN3HcHOI28rdNllutpuDwsy2ahj//UqNdhvhrZyh+fpkpx8+ZTGZQuN0RZd8KL67W94qX4r88uDxohrbp1NxyemmZSBnJO1z2568NTyRyhAytP1/4/S6cYnDNi2zU9yi2iVqNM9/Wf1P2tscFlx8/XXNmriefpWciaeGe55pwH6CaKsylk1X4tpIF6HkdcjOs2YR5Sp8GdtLen+qgMVarIHFt7lA3TWcb4nc2TNP8Cg1HNdY=
+api: eJztWG1v2zgS/isEP7WAbMuJ0+3q0A9pmy6yL9cgTXdxlwbGWBpbbCRSJUdOfIb++2JIW5Zf0mQPe4ddoN/0wiGfeXuGM0uZoUutqkgZLRP5xiIQChAa70RqNIHSaIXRgnIUBHaGJLTJsC8ukWqrnQDx2UzE+VsxNVaQhfRW6ZlfDm6h09wabWonTIUW+JT+Jy0jSTBzMrmWb016i3b8C2iYYYmaxqcX5+MsfG1lnLyJZPt2nslEXhhH/zQZvlmDDDvJSDpMa6toIZPrpXyNYNGe1pTzaWHf5M4qQnnT3ESyAgslElrnl2soUSYyN478YyQVm6UCymUkLX6plcVMJmRrjHZsdxWsAzPUJNY7RMKiQzvHTFhTE5tmDkWN4tkY9CISYyiK55EwVhQwwUI4LDAlY8WzW1wkfunzYLH7noFK9VKT4Qx1D+/JQi+YcSnnUKgMiLGvQUal0q+Gkf8zDp6TTSRdmmMJLEOLitc7skrPZCRLpX9GPWNLDRu2De+Ejl6bbMHrdyKlDY6UY0YZLTa27B8wFkcTauKdoKoKlXqhwWfH2y33cZnJZ0xJRrKy7HlS6DVVJczwEPyH4HkBYXGKFnWK4hn2Z/1IfJJ6pvR9UgCho0/yOWPGeyirgrft/vyvjS+bJlqF1GN43/sHKAQvD6mU4yYDt8GVi57Hx/5MTVmCzjongLWwOGAQv06QEbbWQun9AxRh6fahNp2jr4NhZCR7XgfA0mhhptN/yBtep+ePAjnTc2WN5lwXc7AKJgU6xvPT2b9e/Xr688czVr8EejKki/eXV69exi9jGcm3Z68//vCKI84Dqowl9yikC2NJlFBVSs88FM7eMcsmrYH86xqZT8gnYWNYiUf2cjQ6TkajY49rboq6xMeR/erXidLUmjrIgPIuMqD8jyMbZECQDOZgB4Wa+DcPDWoyY0dgqbPDxJgCQe/h+y1HytFyVHmR7aASqiwxU0BYLARMqUMWffEWp1AX5FiW/RWgZ+FrIA1Onw2NXK9y/yaSpMgnQuD8ULQuA1vJpglirjLaBRMfxUdPIjBIU6wIM468P4muPpvJWGWH8j84TCayrlW2Z9irHNd1tXbo07ayJkXnBOXKiRU3b/PCyUmML0dx3MOj7ye90TAb9eC74YveaPTixcnJaBTHcSyDcdjyB6JvN3JarbbRfajLEuxCKB208MabmJoEbFPKtjHasvooHbL669XCTMN1ggtrn/EfNuiDBSBDTWqqdlkUhpOj9Dgb4cn0hXwyUW/25fUP8/IT69S5r07exZPF1zh/qyBxHSdfcR6FW1vLTLvJSS+4vbettV4RhM8F/EP2bdOHVImOoKy2dz+Kj0a9eNgbnlwN4+Q4TuL43/6oHPRs66hHWSbHzT1SlCZjr2bCLRxhuVaMWc5aYx9X4YyXiRKdYx+oTpSJKaiCeWCXgdoI3iOhyxXhyGZXZp1th0Tqgt6Ygq98yujuFk0kR3G8z1rn2t821vkvKlgUBv5Mxnqi8U5F532dol5WUA4kTJpy6GXbsfDO29VfQpCswjl6t9XO+y1DAlUcqFx7h2eZWt2XVjIr+mlBHDw2q5GP1kh3xt76eDV1oBS+2XXOVZpw5ruJfV4KSrLA1iEnccxeW7vYB9eeR4f7Hv2ooabcWPUfzERPnF6ci1tciDaCvjn27+DY433HvjN2orIMteiJc+3q6VSlismlQlsq53xf+827f33vnhwi4lA8Qu3Ts+2q/c2lf22XNpEskXLDc6TK+AbfT3gSOeDZ1mC5LvPNoPXrINvMl+w8zItuNsOmD+zT4LbuyKlVIyeq5Gr64q86fpGMVg/v1s3Aj79d+UsHx8rlZv5yttatHYDsTihWk6v2CtqZDHytaV/17A830W0PfbiX7bSyD7SU2x2lb+t4qjY13jorH536W9dmCshlUEaS7RzcPezHfd+7sL9K8Hm0UrmdWba+2g2W5SYj/48TzuB4wnsaVAUozehrWzCcEG3Xks+RkUw688YtJULI3UT+3skCy+UEHH60RdPw5y812kUIxPUoxY8xM+X4OZPJFAq3O6nsmuPZ5eqe8Vz8j+eXB+2xbj81N59+tUykjOQtLrpj2IYHEzlChtbrF36/CVr0rniTjfge5TbRWuLUN/hfXXvT4YaL9x+uOEVXA9DSM5O0cMfjTbgLUE0VJtTJMnxbygL0rA5JGvZswlilywc7+e+1OmiM5TKsuDK3qJumtQ3xOxumaX4Hl/U1+w==
sidebar_class_name: "post api-method"
info_path: gen/api/agent-management-api
custom_edit_url: null
@@ -33,7 +33,7 @@ import TabItem from "@theme/TabItem";
diff --git a/docs/docs/gen/api/sidebar.ts b/docs/docs/gen/api/sidebar.ts
index 241fd909..df7cc564 100644
--- a/docs/docs/gen/api/sidebar.ts
+++ b/docs/docs/gen/api/sidebar.ts
@@ -86,45 +86,45 @@ const sidebar: SidebarsConfig = {
},
{
type: "category",
- label: "Node/Container",
+ label: "Node/Docker",
link: {
type: "doc",
- id: "gen/api/container-management-api-container-operations",
+ id: "gen/api/docker-management-api-docker-operations",
},
items: [
{
type: "doc",
- id: "gen/api/post-node-container",
+ id: "gen/api/post-node-container-docker",
label: "Create a container",
className: "api-method post",
},
{
type: "doc",
- id: "gen/api/get-node-container",
+ id: "gen/api/get-node-container-docker",
label: "List containers",
className: "api-method get",
},
{
type: "doc",
- id: "gen/api/get-node-container-by-id",
+ id: "gen/api/get-node-container-docker-by-id",
label: "Inspect a container",
className: "api-method get",
},
{
type: "doc",
- id: "gen/api/delete-node-container-by-id",
+ id: "gen/api/delete-node-container-docker-by-id",
label: "Remove a container",
className: "api-method delete",
},
{
type: "doc",
- id: "gen/api/post-node-container-start",
+ id: "gen/api/post-node-container-docker-start",
label: "Start a container",
className: "api-method post",
},
{
type: "doc",
- id: "gen/api/post-node-container-stop",
+ id: "gen/api/post-node-container-docker-stop",
label: "Stop a container",
className: "api-method post",
},
@@ -132,15 +132,15 @@ const sidebar: SidebarsConfig = {
},
{
type: "category",
- label: "Node/Container/Exec",
+ label: "Node/Docker/Exec",
link: {
type: "doc",
- id: "gen/api/container-management-api-container-exec",
+ id: "gen/api/docker-management-api-docker-exec",
},
items: [
{
type: "doc",
- id: "gen/api/post-node-container-exec",
+ id: "gen/api/post-node-container-docker-exec",
label: "Execute a command in a container",
className: "api-method post",
},
@@ -148,15 +148,15 @@ const sidebar: SidebarsConfig = {
},
{
type: "category",
- label: "Node/Container/Image",
+ label: "Node/Docker/Image",
link: {
type: "doc",
- id: "gen/api/container-management-api-container-image",
+ id: "gen/api/docker-management-api-docker-image",
},
items: [
{
type: "doc",
- id: "gen/api/post-node-container-pull",
+ id: "gen/api/post-node-container-docker-pull",
label: "Pull a container image",
className: "api-method post",
},
diff --git a/docs/docs/sidebar/architecture/system-architecture.md b/docs/docs/sidebar/architecture/system-architecture.md
index 1707422e..284f1b82 100644
--- a/docs/docs/sidebar/architecture/system-architecture.md
+++ b/docs/docs/sidebar/architecture/system-architecture.md
@@ -65,14 +65,14 @@ The API server is built on [Echo][] with handlers generated from an OpenAPI spec
via [oapi-codegen][] (`*.gen.go` files). Domain handlers are organized into
subpackages:
-| Package | Responsibility |
-| ------------------------- | -------------------------------------------------------------------------------- |
-| `internal/api/node/` | Node endpoints (hostname, status, disk, memory, load, network/dns, command/exec) |
-| `internal/api/container/` | Container endpoints (create, list, inspect, start, stop, remove, exec, pull) |
-| `internal/api/job/` | Job queue endpoints (get, list, delete, retry, status) |
-| `internal/api/health/` | Health check endpoints (liveness, readiness, status) |
-| `internal/api/common/` | Shared middleware, error handling, collection responses |
-| (metrics) | Prometheus endpoint (`/metrics`) via OpenTelemetry |
+| Package | Responsibility |
+| ---------------------- | ----------------------------------------------------------------------------------- |
+| `internal/api/node/` | Node endpoints (hostname, status, disk, memory, load, network/dns, command/exec) |
+| `internal/api/docker/` | Docker container endpoints (create, list, inspect, start, stop, remove, exec, pull) |
+| `internal/api/job/` | Job queue endpoints (get, list, delete, retry, status) |
+| `internal/api/health/` | Health check endpoints (liveness, readiness, status) |
+| `internal/api/common/` | Shared middleware, error handling, collection responses |
+| (metrics) | Prometheus endpoint (`/metrics`) via OpenTelemetry |
All state-changing operations are dispatched as jobs through the job client
layer rather than executed inline. Responses follow a uniform collection
@@ -99,17 +99,17 @@ For the full deep dive see [Job System Architecture](job-architecture.md).
Providers implement the actual system operations behind a common interface. Each
provider is selected at runtime through a platform-aware factory pattern.
-| Domain | Providers |
-| ------------------- | ------------------------------------------------- |
-| `node/host` | Hostname, uptime, OS info |
-| `node/disk` | Disk usage statistics |
-| `node/mem` | Memory usage statistics |
-| `node/load` | Load average statistics |
-| `network/dns` | DNS configuration (get/update) |
-| `network/ping` | Ping execution and statistics |
-| `command/exec` | Direct command execution |
-| `command/shell` | Shell command execution |
-| `container/runtime` | Container lifecycle (create, start, stop, remove) |
+| Domain | Providers |
+| ---------------- | -------------------------------------------------------- |
+| `node/host` | Hostname, uptime, OS info |
+| `node/disk` | Disk usage statistics |
+| `node/mem` | Memory usage statistics |
+| `node/load` | Load average statistics |
+| `network/dns` | DNS configuration (get/update) |
+| `network/ping` | Ping execution and statistics |
+| `command/exec` | Direct command execution |
+| `command/shell` | Shell command execution |
+| `docker/runtime` | Docker container lifecycle (create, start, stop, remove) |
Providers are stateless and platform-specific (e.g., a Ubuntu DNS provider vs. a
generic Linux DNS provider). Adding a new operation means implementing the
diff --git a/docs/docs/sidebar/features/container-management.md b/docs/docs/sidebar/features/container-management.md
index c63dc478..685eec02 100644
--- a/docs/docs/sidebar/features/container-management.md
+++ b/docs/docs/sidebar/features/container-management.md
@@ -61,8 +61,8 @@ Container operations follow the same request flow as all OSAPI operations:
You can target a specific host, broadcast to all hosts with `_all`, or route by
label. See [CLI Reference](../usage/cli/client/container/container.mdx) for
usage and examples, or the
-[API Reference](/gen/api/container-management-api-container-operations) for the
-REST endpoints.
+[API Reference](/gen/api/docker-management-api-docker-operations) for the REST
+endpoints.
### Runtime Drivers
@@ -92,23 +92,23 @@ authentication settings.
## Permissions
-| Endpoint | Permission |
-| -------------------------------------------- | ------------------- |
-| `POST /node/{hostname}/container` (create) | `container:write` |
-| `GET /node/{hostname}/container` (list) | `container:read` |
-| `GET /node/{hostname}/container/{id}` | `container:read` |
-| `POST /node/{hostname}/container/{id}/start` | `container:write` |
-| `POST /node/{hostname}/container/{id}/stop` | `container:write` |
-| `DELETE /node/{hostname}/container/{id}` | `container:write` |
-| `POST /node/{hostname}/container/{id}/exec` | `container:execute` |
-| `POST /node/{hostname}/container/pull` | `container:write` |
-
-The `admin` role includes `container:read`, `container:write`, and
-`container:execute`. The `write` role includes `container:read` and
-`container:write`. The `read` role includes only `container:read`.
+| Endpoint | Permission |
+| --------------------------------------------------- | ---------------- |
+| `POST /node/{hostname}/container/docker` (create) | `docker:write` |
+| `GET /node/{hostname}/container/docker` (list) | `docker:read` |
+| `GET /node/{hostname}/container/docker/{id}` | `docker:read` |
+| `POST /node/{hostname}/container/docker/{id}/start` | `docker:write` |
+| `POST /node/{hostname}/container/docker/{id}/stop` | `docker:write` |
+| `DELETE /node/{hostname}/container/docker/{id}` | `docker:write` |
+| `POST /node/{hostname}/container/docker/{id}/exec` | `docker:execute` |
+| `POST /node/{hostname}/container/docker/pull` | `docker:write` |
+
+The `admin` role includes `docker:read`, `docker:write`, and `docker:execute`.
+The `write` role includes `docker:read` and `docker:write`. The `read` role
+includes only `docker:read`.
Container exec is a privileged operation similar to command execution. Only the
-`admin` role includes `container:execute` by default. Grant it to other roles or
+`admin` role includes `docker:execute` by default. Grant it to other roles or
tokens explicitly when needed:
```yaml
@@ -116,11 +116,11 @@ api:
server:
security:
roles:
- container-ops:
+ docker-ops:
permissions:
- - container:read
- - container:write
- - container:execute
+ - docker:read
+ - docker:write
+ - docker:execute
- health:read
```
@@ -128,51 +128,69 @@ Or grant it directly on a token:
```bash
osapi token generate -r write -u user@example.com \
- -p container:execute
+ -p docker:execute
```
-## Orchestrator DSL
+## Orchestrator
-The [orchestrator](../sdk/orchestrator/orchestrator.md) SDK supports container
-operations through the
-[Container Targeting](../sdk/orchestrator/features/container-targeting.md)
-feature. Use `Plan.Docker()` and `Plan.In()` to create containers and run
-existing providers inside them without rewriting any code:
+The [orchestrator](../sdk/orchestrator/orchestrator.md) SDK can compose
+container operations as a DAG using `TaskFunc`. Pull, create, exec, inspect, and
+cleanup steps chain together with dependencies and guards:
```go
-plan := orchestrator.NewPlan(client, orchestrator.WithDockerExecFn(execFn))
-web := plan.Docker("web-server", "nginx:alpine")
-
-create := plan.TaskFunc("create", func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- return c.Container.Create(ctx, "_any", gen.ContainerCreateRequest{
- Image: "nginx:alpine",
- Name: ptr("web-server"),
- })
-})
-
-plan.In(web).TaskFunc("check-config", func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- // Runs inside the container via docker exec + provider run
- return c.Container.Exec(ctx, "_any", "web-server", gen.ContainerExecRequest{
- Command: []string{"nginx", "-t"},
- })
-}).DependsOn(create)
+plan := orchestrator.NewPlan(client, orchestrator.OnError(orchestrator.Continue))
+
+pull := plan.TaskFunc("pull-image",
+ func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
+ _, err := c.Docker.Pull(ctx, "_any", gen.DockerPullRequest{
+ Image: "nginx:alpine",
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &orchestrator.Result{Changed: true}, nil
+ },
+)
+
+create := plan.TaskFunc("create-container",
+ func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
+ autoStart := true
+ _, err := c.Docker.Create(ctx, "_any", gen.DockerCreateRequest{
+ Image: "nginx:alpine",
+ Name: ptr("web-server"),
+ AutoStart: &autoStart,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &orchestrator.Result{Changed: true}, nil
+ },
+)
+create.DependsOn(pull)
+
+exec := plan.TaskFunc("check-config",
+ func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
+ _, err := c.Docker.Exec(ctx, "_any", "web-server",
+ gen.DockerExecRequest{Command: []string{"nginx", "-t"}})
+ if err != nil {
+ return nil, err
+ }
+ return &orchestrator.Result{Changed: true}, nil
+ },
+)
+exec.DependsOn(create)
```
-The transport changes from HTTP to `docker exec` + `provider run`, but the SDK
-interface is identical. See the
-[container targeting feature page](../sdk/orchestrator/features/container-targeting.md)
-for details and the
-[operations reference](../sdk/orchestrator/orchestrator.md#operations) for all
-container operations.
+See
+[`examples/sdk/orchestrator/features/container-targeting.go`](https://github.com/retr0h/osapi/blob/main/examples/sdk/orchestrator/features/container-targeting.go)
+for a complete working example.
## Related
- [CLI Reference](../usage/cli/client/container/container.mdx) -- container
management commands
-- [API Reference](/gen/api/container-management-api-container-operations) --
- REST API documentation
-- [Orchestrator Container Targeting](../sdk/orchestrator/features/container-targeting.md)
- -- DSL for running providers inside containers
+- [API Reference](/gen/api/docker-management-api-docker-operations) -- REST API
+ documentation
- [Job System](job-system.md) -- how async job processing works
- [Authentication & RBAC](authentication.md) -- permissions and roles
- [Architecture](../architecture/architecture.md) -- system design overview
diff --git a/docs/docs/sidebar/sdk/orchestrator/features/container-targeting.md b/docs/docs/sidebar/sdk/orchestrator/features/container-targeting.md
index b0e8d246..2657d721 100644
--- a/docs/docs/sidebar/sdk/orchestrator/features/container-targeting.md
+++ b/docs/docs/sidebar/sdk/orchestrator/features/container-targeting.md
@@ -4,140 +4,120 @@ sidebar_position: 14
# Container Targeting
-Create containers and run provider operations inside them using the same typed
-SDK methods. The transport changes from HTTP to `docker exec` + `provider run`,
-but the interface is identical.
+Orchestrate container lifecycle operations -- pull, create, exec, inspect, stop,
+and remove -- as a DAG of `TaskFunc` steps using the standard SDK client.
## Setup
-Provide a `WithDockerExecFn` option when creating the plan. The exec function
-calls the Docker SDK's `ContainerExecCreate` / `ContainerExecAttach` APIs to run
-commands inside containers.
+Container operations use the same `client.Docker` service as any other SDK call.
+No special plan options are needed:
```go
-plan := orchestrator.NewPlan(client, orchestrator.WithDockerExecFn(execFn))
+plan := orchestrator.NewPlan(client, orchestrator.OnError(orchestrator.Continue))
```
-## Docker Target
+## Building the DAG
-`Plan.Docker()` creates a `DockerTarget` bound to a container name and image. It
-implements the `RuntimeTarget` interface:
+Chain container operations with `DependsOn` to enforce ordering. Independent
+operations at the same level run in parallel:
```go
-web := plan.Docker("web-server", "nginx:alpine")
-```
-
-`RuntimeTarget` is pluggable — Docker is the first implementation. Future
-runtimes (LXD, Podman) implement the same interface.
-
-## Scoped Plans
-
-`Plan.In()` returns a `ScopedPlan` that routes provider operations through the
-target's `ExecProvider` method:
-
-```go
-plan.In(web).TaskFunc("run-inside",
- func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- // This executes inside the container via:
- // docker exec web-server /osapi provider run --data ''
- return &orchestrator.Result{Changed: true}, nil
- },
-)
-```
-
-The `ScopedPlan` supports `TaskFunc` and `TaskFuncWithResults`, with the same
-dependency, guard, and error strategy features as the parent plan.
-
-## Full Example
-
-A typical workflow creates a container, runs operations inside it, then cleans
-up:
-
-```go
-plan := orchestrator.NewPlan(client, orchestrator.WithDockerExecFn(execFn))
-web := plan.Docker("my-app", "ubuntu:24.04")
-
pull := plan.TaskFunc("pull-image",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- resp, err := c.Container.Pull(ctx, "_any", gen.ContainerPullRequest{
+ _, err := c.Docker.Pull(ctx, "_any", gen.DockerPullRequest{
Image: "ubuntu:24.04",
})
if err != nil {
return nil, err
}
- return &orchestrator.Result{Changed: true, Data: map[string]any{
- "image_id": resp.Data.Results[0].ImageID,
- }}, nil
+ return &orchestrator.Result{Changed: true}, nil
},
)
create := plan.TaskFunc("create-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
autoStart := true
- resp, err := c.Container.Create(ctx, "_any", gen.ContainerCreateRequest{
+ resp, err := c.Docker.Create(ctx, "_any", gen.DockerCreateRequest{
Image: "ubuntu:24.04",
Name: ptr("my-app"),
AutoStart: &autoStart,
+ Command: &[]string{"sleep", "600"},
})
if err != nil {
return nil, err
}
- return &orchestrator.Result{Changed: true, Data: map[string]any{
- "container_id": resp.Data.Results[0].ID,
- }}, nil
+ r := resp.Data.Results[0]
+ return &orchestrator.Result{
+ Changed: true,
+ Data: map[string]any{"id": r.ID},
+ }, nil
},
)
create.DependsOn(pull)
+```
+
+## Exec
+
+Execute commands inside running containers. Multiple exec tasks that depend on
+the same create step run in parallel:
-// Run a command inside the container
-checkOS := plan.In(web).TaskFunc("check-os",
+```go
+execHostname := plan.TaskFunc("exec-hostname",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- resp, err := c.Container.Exec(ctx, "_any", "my-app", gen.ContainerExecRequest{
- Command: []string{"cat", "/etc/os-release"},
- })
+ resp, err := c.Docker.Exec(ctx, "_any", "my-app",
+ gen.DockerExecRequest{Command: []string{"hostname"}})
if err != nil {
return nil, err
}
+ r := resp.Data.Results[0]
return &orchestrator.Result{
- Changed: false,
- Data: map[string]any{"stdout": resp.Data.Results[0].Stdout},
+ Changed: true,
+ Data: map[string]any{"stdout": r.Stdout},
}, nil
},
)
-checkOS.DependsOn(create)
+execHostname.DependsOn(create)
-cleanup := plan.TaskFunc("remove-container",
+execUname := plan.TaskFunc("exec-uname",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- force := true
- _, err := c.Container.Remove(ctx, "_any", "my-app",
- &gen.DeleteNodeContainerByIDParams{Force: &force})
+ resp, err := c.Docker.Exec(ctx, "_any", "my-app",
+ gen.DockerExecRequest{Command: []string{"uname", "-a"}})
if err != nil {
return nil, err
}
- return &orchestrator.Result{Changed: true}, nil
+ r := resp.Data.Results[0]
+ return &orchestrator.Result{
+ Changed: true,
+ Data: map[string]any{"stdout": r.Stdout},
+ }, nil
},
)
-cleanup.DependsOn(checkOS)
-
-report, err := plan.Run(context.Background())
+execUname.DependsOn(create)
```
-## RuntimeTarget Interface
+## Cleanup
+
+Use a cleanup task that depends on all operational tasks to ensure the container
+is removed even when some tasks fail (with `OnError(Continue)`):
```go
-type RuntimeTarget interface {
- Name() string
- Runtime() string // "docker", "lxd", "podman"
- ExecProvider(ctx context.Context, provider, operation string, data []byte) ([]byte, error)
-}
+cleanup := plan.TaskFunc("cleanup",
+ func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
+ force := true
+ _, err := c.Docker.Remove(ctx, "_any", "my-app",
+ &gen.DeleteNodeContainerDockerByIDParams{Force: &force})
+ if err != nil {
+ return nil, err
+ }
+ return &orchestrator.Result{Changed: true}, nil
+ },
+)
+cleanup.DependsOn(execHostname, execUname)
```
-`DockerTarget` implements this by running
-`docker exec /osapi provider run --data ''`.
-The host's `osapi` binary is volume-mounted into the container at creation time.
-
## Example
See
[`examples/sdk/orchestrator/features/container-targeting.go`](https://github.com/retr0h/osapi/blob/main/examples/sdk/orchestrator/features/container-targeting.go)
-for a complete working example.
+for a complete working example with hooks, error handling, and a deliberately
+failing task.
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-create.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-create.md
similarity index 92%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-create.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-create.md
index 2816c9e7..eaf0b6cf 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-create.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-create.md
@@ -2,7 +2,7 @@
sidebar_position: 16
---
-# container.create.execute
+# docker.create.execute
Create a new container from a specified image.
@@ -12,7 +12,7 @@ Create a new container from a specified image.
task := plan.TaskFunc("create-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
autoStart := true
- resp, err := c.Container.Create(ctx, "_any", gen.ContainerCreateRequest{
+ resp, err := c.Docker.Create(ctx, "_any", gen.DockerCreateRequest{
Image: "nginx:alpine",
Name: ptr("my-nginx"),
AutoStart: &autoStart,
@@ -52,7 +52,7 @@ duplicate creation.
## Permissions
-Requires `container:write` permission.
+Requires `docker:write` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-exec.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-exec.md
similarity index 90%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-exec.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-exec.md
index 817c8232..78b740db 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-exec.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-exec.md
@@ -2,7 +2,7 @@
sidebar_position: 22
---
-# container.exec.execute
+# docker.exec.execute
Execute a command inside a running container.
@@ -11,7 +11,7 @@ Execute a command inside a running container.
```go
task := plan.TaskFunc("exec-in-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- resp, err := c.Container.Exec(ctx, "_any", "my-nginx", gen.ContainerExecRequest{
+ resp, err := c.Docker.Exec(ctx, "_any", "my-nginx", gen.DockerExecRequest{
Command: []string{"nginx", "-t"},
})
if err != nil {
@@ -50,7 +50,7 @@ Accepts any valid target: `_any`, `_all`, a hostname, or a label selector
## Permissions
-Requires `container:execute` permission.
+Requires `docker:execute` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-inspect.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-inspect.md
similarity index 89%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-inspect.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-inspect.md
index 2dace5e7..8b7322cb 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-inspect.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-inspect.md
@@ -2,7 +2,7 @@
sidebar_position: 18
---
-# container.inspect.get
+# docker.inspect.get
Retrieve detailed information about a specific container.
@@ -11,7 +11,7 @@ Retrieve detailed information about a specific container.
```go
task := plan.TaskFunc("inspect-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- resp, err := c.Container.Inspect(ctx, "_any", "my-nginx")
+ resp, err := c.Docker.Inspect(ctx, "_any", "my-nginx")
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ Accepts any valid target: `_any`, `_all`, a hostname, or a label selector
## Permissions
-Requires `container:read` permission.
+Requires `docker:read` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-list.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-list.md
similarity index 85%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-list.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-list.md
index 515f2763..39478a13 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-list.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-list.md
@@ -2,7 +2,7 @@
sidebar_position: 17
---
-# container.list.get
+# docker.list.get
List containers on the target host, optionally filtered by state.
@@ -11,8 +11,8 @@ List containers on the target host, optionally filtered by state.
```go
task := plan.TaskFunc("list-containers",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- state := gen.GetNodeContainerParamsStateRunning
- resp, err := c.Container.List(ctx, "_any", &gen.GetNodeContainerParams{
+ state := gen.GetNodeContainerDockerParamsStateRunning
+ resp, err := c.Docker.List(ctx, "_any", &gen.GetNodeContainerDockerParams{
State: &state,
})
if err != nil {
@@ -41,7 +41,7 @@ Accepts any valid target: `_any`, `_all`, a hostname, or a label selector
## Permissions
-Requires `container:read` permission.
+Requires `docker:read` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-pull.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-pull.md
similarity index 89%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-pull.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-pull.md
index d1edcf6f..dcb6cd05 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-pull.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-pull.md
@@ -2,7 +2,7 @@
sidebar_position: 23
---
-# container.pull.execute
+# docker.pull.execute
Pull a container image to the host.
@@ -11,7 +11,7 @@ Pull a container image to the host.
```go
task := plan.TaskFunc("pull-image",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- resp, err := c.Container.Pull(ctx, "_any", gen.ContainerPullRequest{
+ resp, err := c.Docker.Pull(ctx, "_any", gen.DockerPullRequest{
Image: "nginx:alpine",
})
if err != nil {
@@ -45,7 +45,7 @@ background.
## Permissions
-Requires `container:write` permission.
+Requires `docker:write` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-remove.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-remove.md
similarity index 84%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-remove.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-remove.md
index 4e394622..d1066cf0 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-remove.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-remove.md
@@ -2,7 +2,7 @@
sidebar_position: 21
---
-# container.remove.execute
+# docker.remove.execute
Remove a container from the host.
@@ -12,8 +12,8 @@ Remove a container from the host.
task := plan.TaskFunc("remove-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
force := true
- _, err := c.Container.Remove(ctx, "_any", "my-nginx",
- &gen.DeleteNodeContainerByIDParams{Force: &force})
+ _, err := c.Docker.Remove(ctx, "_any", "my-nginx",
+ &gen.DeleteNodeContainerDockerByIDParams{Force: &force})
if err != nil {
return nil, err
}
@@ -40,7 +40,7 @@ Accepts any valid target: `_any`, `_all`, a hostname, or a label selector
## Permissions
-Requires `container:write` permission.
+Requires `docker:write` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-start.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-start.md
similarity index 88%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-start.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-start.md
index 17ebc208..d92619cc 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-start.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-start.md
@@ -2,7 +2,7 @@
sidebar_position: 19
---
-# container.start.execute
+# docker.start.execute
Start a stopped container.
@@ -11,7 +11,7 @@ Start a stopped container.
```go
task := plan.TaskFunc("start-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- _, err := c.Container.Start(ctx, "_any", "my-nginx")
+ _, err := c.Docker.Start(ctx, "_any", "my-nginx")
if err != nil {
return nil, err
}
@@ -38,7 +38,7 @@ to check state first.
## Permissions
-Requires `container:write` permission.
+Requires `docker:write` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/operations/container-stop.md b/docs/docs/sidebar/sdk/orchestrator/operations/docker-stop.md
similarity index 88%
rename from docs/docs/sidebar/sdk/orchestrator/operations/container-stop.md
rename to docs/docs/sidebar/sdk/orchestrator/operations/docker-stop.md
index 6fca070f..2f6dfee1 100644
--- a/docs/docs/sidebar/sdk/orchestrator/operations/container-stop.md
+++ b/docs/docs/sidebar/sdk/orchestrator/operations/docker-stop.md
@@ -2,7 +2,7 @@
sidebar_position: 20
---
-# container.stop.execute
+# docker.stop.execute
Stop a running container.
@@ -12,7 +12,7 @@ Stop a running container.
task := plan.TaskFunc("stop-container",
func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
timeout := 30
- _, err := c.Container.Stop(ctx, "_any", "my-nginx", gen.ContainerStopRequest{
+ _, err := c.Docker.Stop(ctx, "_any", "my-nginx", gen.DockerStopRequest{
Timeout: &timeout,
})
if err != nil {
@@ -41,7 +41,7 @@ Accepts any valid target: `_any`, `_all`, a hostname, or a label selector
## Permissions
-Requires `container:write` permission.
+Requires `docker:write` permission.
## Example
diff --git a/docs/docs/sidebar/sdk/orchestrator/orchestrator.md b/docs/docs/sidebar/sdk/orchestrator/orchestrator.md
index db8aa61c..9111340c 100644
--- a/docs/docs/sidebar/sdk/orchestrator/orchestrator.md
+++ b/docs/docs/sidebar/sdk/orchestrator/orchestrator.md
@@ -40,30 +40,30 @@ report, err := plan.Run(context.Background())
Operations are the building blocks of orchestration plans. Each operation maps
to an OSAPI job type that agents execute.
-| Operation | Description | Idempotent | Category |
-| ------------------------------------------------------------ | ---------------------- | ---------- | --------- |
-| [`command.exec.execute`](operations/command-exec.md) | Execute a command | No | Command |
-| [`command.shell.execute`](operations/command-shell.md) | Execute a shell string | No | Command |
-| [`file.deploy.execute`](operations/file-deploy.md) | Deploy file to agent | Yes | File |
-| [`file.status.get`](operations/file-status.md) | Check file status | Read-only | File |
-| [`file.upload`](operations/file-upload.md) | Upload to Object Store | Yes | File |
-| [`network.dns.get`](operations/network-dns-get.md) | Get DNS configuration | Read-only | Network |
-| [`network.dns.update`](operations/network-dns-update.md) | Update DNS servers | Yes | Network |
-| [`network.ping.do`](operations/network-ping.md) | Ping a host | Read-only | Network |
-| [`node.hostname.get`](operations/node-hostname.md) | Get system hostname | Read-only | Node |
-| [`node.status.get`](operations/node-status.md) | Get node status | Read-only | Node |
-| [`node.disk.get`](operations/node-disk.md) | Get disk usage | Read-only | Node |
-| [`node.memory.get`](operations/node-memory.md) | Get memory stats | Read-only | Node |
-| [`node.uptime.get`](operations/node-uptime.md) | Get system uptime | Read-only | Node |
-| [`node.load.get`](operations/node-load.md) | Get load averages | Read-only | Node |
-| [`container.create.execute`](operations/container-create.md) | Create a container | No | Container |
-| [`container.list.get`](operations/container-list.md) | List containers | Read-only | Container |
-| [`container.inspect.get`](operations/container-inspect.md) | Inspect a container | Read-only | Container |
-| [`container.start.execute`](operations/container-start.md) | Start a container | No | Container |
-| [`container.stop.execute`](operations/container-stop.md) | Stop a container | No | Container |
-| [`container.remove.execute`](operations/container-remove.md) | Remove a container | No | Container |
-| [`container.exec.execute`](operations/container-exec.md) | Exec in a container | No | Container |
-| [`container.pull.execute`](operations/container-pull.md) | Pull a container image | No | Container |
+| Operation | Description | Idempotent | Category |
+| -------------------------------------------------------- | ---------------------- | ---------- | -------- |
+| [`command.exec.execute`](operations/command-exec.md) | Execute a command | No | Command |
+| [`command.shell.execute`](operations/command-shell.md) | Execute a shell string | No | Command |
+| [`file.deploy.execute`](operations/file-deploy.md) | Deploy file to agent | Yes | File |
+| [`file.status.get`](operations/file-status.md) | Check file status | Read-only | File |
+| [`file.upload`](operations/file-upload.md) | Upload to Object Store | Yes | File |
+| [`network.dns.get`](operations/network-dns-get.md) | Get DNS configuration | Read-only | Network |
+| [`network.dns.update`](operations/network-dns-update.md) | Update DNS servers | Yes | Network |
+| [`network.ping.do`](operations/network-ping.md) | Ping a host | Read-only | Network |
+| [`node.hostname.get`](operations/node-hostname.md) | Get system hostname | Read-only | Node |
+| [`node.status.get`](operations/node-status.md) | Get node status | Read-only | Node |
+| [`node.disk.get`](operations/node-disk.md) | Get disk usage | Read-only | Node |
+| [`node.memory.get`](operations/node-memory.md) | Get memory stats | Read-only | Node |
+| [`node.uptime.get`](operations/node-uptime.md) | Get system uptime | Read-only | Node |
+| [`node.load.get`](operations/node-load.md) | Get load averages | Read-only | Node |
+| [`docker.create.execute`](operations/docker-create.md) | Create a container | No | Docker |
+| [`docker.list.get`](operations/docker-list.md) | List containers | Read-only | Docker |
+| [`docker.inspect.get`](operations/docker-inspect.md) | Inspect a container | Read-only | Docker |
+| [`docker.start.execute`](operations/docker-start.md) | Start a container | No | Docker |
+| [`docker.stop.execute`](operations/docker-stop.md) | Stop a container | No | Docker |
+| [`docker.remove.execute`](operations/docker-remove.md) | Remove a container | No | Docker |
+| [`docker.exec.execute`](operations/docker-exec.md) | Exec in a container | No | Docker |
+| [`docker.pull.execute`](operations/docker-pull.md) | Pull a container image | No | Docker |
### Idempotency
diff --git a/docs/docs/sidebar/usage/cli/client/container/container.mdx b/docs/docs/sidebar/usage/cli/client/container/container.mdx
index 90020231..490b0fe8 100644
--- a/docs/docs/sidebar/usage/cli/client/container/container.mdx
+++ b/docs/docs/sidebar/usage/cli/client/container/container.mdx
@@ -1,7 +1,6 @@
# Container
-CLI for managing containers on target nodes -- create, list, inspect, start,
-stop, remove, exec, and pull.
+Container runtime management. Select a runtime below.
import DocCardList from '@theme/DocCardList';
diff --git a/docs/docs/sidebar/usage/cli/client/container/create.md b/docs/docs/sidebar/usage/cli/client/container/docker/create.md
similarity index 87%
rename from docs/docs/sidebar/usage/cli/client/container/create.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/create.md
index a6b739b4..b0f171d5 100644
--- a/docs/docs/sidebar/usage/cli/client/container/create.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/create.md
@@ -3,7 +3,7 @@
Create a new container on the target node from the specified image:
```bash
-$ osapi client container create --image nginx:latest
+$ osapi client container docker create --image nginx:latest
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -18,7 +18,7 @@ Create a named container with environment variables, port mappings, and volume
mounts:
```bash
-$ osapi client container create \
+$ osapi client container docker create \
--image nginx:latest \
--name my-nginx \
--env "PORT=8080" --env "DEBUG=true" \
@@ -29,7 +29,7 @@ $ osapi client container create \
Create a container without starting it immediately:
```bash
-$ osapi client container create \
+$ osapi client container docker create \
--image alpine:latest \
--name my-alpine \
--auto-start=false
@@ -38,7 +38,7 @@ $ osapi client container create \
Target a specific host:
```bash
-$ osapi client container create \
+$ osapi client container docker create \
--image redis:7 \
--name cache \
--target web-01
@@ -49,7 +49,7 @@ $ osapi client container create \
Use `--json` to get the full API response:
```bash
-$ osapi client container create --image nginx:latest --json
+$ osapi client container docker create --image nginx:latest --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/docker/docker.mdx b/docs/docs/sidebar/usage/cli/client/container/docker/docker.mdx
new file mode 100644
index 00000000..f83429de
--- /dev/null
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/docker.mdx
@@ -0,0 +1,8 @@
+# Docker
+
+CLI for managing Docker containers on target nodes -- create, list, inspect,
+start, stop, remove, exec, and pull.
+
+import DocCardList from '@theme/DocCardList';
+
+
diff --git a/docs/docs/sidebar/usage/cli/client/container/exec.md b/docs/docs/sidebar/usage/cli/client/container/docker/exec.md
similarity index 86%
rename from docs/docs/sidebar/usage/cli/client/container/exec.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/exec.md
index 5052e2ba..f7ea6f95 100644
--- a/docs/docs/sidebar/usage/cli/client/container/exec.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/exec.md
@@ -3,7 +3,7 @@
Execute a command inside a running container on the target node:
```bash
-$ osapi client container exec --id my-nginx --command "ls,-la,/"
+$ osapi client container docker exec --id my-nginx --command "ls,-la,/"
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -18,7 +18,7 @@ $ osapi client container exec --id my-nginx --command "ls,-la,/"
Execute with environment variables and a working directory:
```bash
-$ osapi client container exec \
+$ osapi client container docker exec \
--id my-app \
--command "python,-c,import os; print(os.environ['MY_VAR'])" \
--env "MY_VAR=hello" \
@@ -28,7 +28,7 @@ $ osapi client container exec \
Target a specific host:
```bash
-$ osapi client container exec \
+$ osapi client container docker exec \
--id my-nginx \
--command "nginx,-t" \
--target web-01
@@ -39,7 +39,7 @@ $ osapi client container exec \
Use `--json` to get the full API response:
```bash
-$ osapi client container exec --id my-nginx --command "ls" --json
+$ osapi client container docker exec --id my-nginx --command "ls" --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/inspect.md b/docs/docs/sidebar/usage/cli/client/container/docker/inspect.md
similarity index 81%
rename from docs/docs/sidebar/usage/cli/client/container/inspect.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/inspect.md
index 103fc450..64075e86 100644
--- a/docs/docs/sidebar/usage/cli/client/container/inspect.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/inspect.md
@@ -3,7 +3,7 @@
Get detailed information about a specific container:
```bash
-$ osapi client container inspect --id a1b2c3d4e5f6
+$ osapi client container docker inspect --id a1b2c3d4e5f6
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -22,13 +22,13 @@ $ osapi client container inspect --id a1b2c3d4e5f6
Inspect a container by name:
```bash
-$ osapi client container inspect --id my-nginx
+$ osapi client container docker inspect --id my-nginx
```
Target a specific host:
```bash
-$ osapi client container inspect --id my-nginx --target web-01
+$ osapi client container docker inspect --id my-nginx --target web-01
```
## JSON Output
@@ -36,7 +36,7 @@ $ osapi client container inspect --id my-nginx --target web-01
Use `--json` to get the full API response:
```bash
-$ osapi client container inspect --id a1b2c3d4e5f6 --json
+$ osapi client container docker inspect --id a1b2c3d4e5f6 --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/list.md b/docs/docs/sidebar/usage/cli/client/container/docker/list.md
similarity index 77%
rename from docs/docs/sidebar/usage/cli/client/container/list.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/list.md
index 4ecb5af4..e2eaf08b 100644
--- a/docs/docs/sidebar/usage/cli/client/container/list.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/list.md
@@ -3,7 +3,7 @@
List containers on the target node:
```bash
-$ osapi client container list
+$ osapi client container docker list
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -17,21 +17,21 @@ $ osapi client container list
Filter by state:
```bash
-$ osapi client container list --state running
-$ osapi client container list --state stopped
-$ osapi client container list --state all
+$ osapi client container docker list --state running
+$ osapi client container docker list --state stopped
+$ osapi client container docker list --state all
```
Limit the number of results:
```bash
-$ osapi client container list --limit 5
+$ osapi client container docker list --limit 5
```
Target a specific host:
```bash
-$ osapi client container list --target web-01
+$ osapi client container docker list --target web-01
```
## JSON Output
@@ -39,7 +39,7 @@ $ osapi client container list --target web-01
Use `--json` to get the full API response:
```bash
-$ osapi client container list --json
+$ osapi client container docker list --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/pull.md b/docs/docs/sidebar/usage/cli/client/container/docker/pull.md
similarity index 72%
rename from docs/docs/sidebar/usage/cli/client/container/pull.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/pull.md
index 09eafdac..9136c20f 100644
--- a/docs/docs/sidebar/usage/cli/client/container/pull.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/pull.md
@@ -3,7 +3,7 @@
Pull a container image on the target node:
```bash
-$ osapi client container pull --image nginx:latest
+$ osapi client container docker pull --image nginx:latest
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -16,26 +16,26 @@ $ osapi client container pull --image nginx:latest
Pull a specific image version:
```bash
-$ osapi client container pull --image alpine:3.18
+$ osapi client container docker pull --image alpine:3.18
```
Pull from a custom registry:
```bash
-$ osapi client container pull \
+$ osapi client container docker pull \
--image registry.example.com/myapp:v1.2.3
```
Target a specific host:
```bash
-$ osapi client container pull --image redis:7 --target web-01
+$ osapi client container docker pull --image redis:7 --target web-01
```
Pull on all hosts:
```bash
-$ osapi client container pull --image nginx:latest --target _all
+$ osapi client container docker pull --image nginx:latest --target _all
```
## JSON Output
@@ -43,7 +43,7 @@ $ osapi client container pull --image nginx:latest --target _all
Use `--json` to get the full API response:
```bash
-$ osapi client container pull --image nginx:latest --json
+$ osapi client container docker pull --image nginx:latest --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/remove.md b/docs/docs/sidebar/usage/cli/client/container/docker/remove.md
similarity index 77%
rename from docs/docs/sidebar/usage/cli/client/container/remove.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/remove.md
index 61b17458..32aa2cef 100644
--- a/docs/docs/sidebar/usage/cli/client/container/remove.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/remove.md
@@ -3,7 +3,7 @@
Remove a container from the target node:
```bash
-$ osapi client container remove --id a1b2c3d4e5f6
+$ osapi client container docker remove --id a1b2c3d4e5f6
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -14,13 +14,13 @@ $ osapi client container remove --id a1b2c3d4e5f6
Force removal of a running container:
```bash
-$ osapi client container remove --id my-nginx --force
+$ osapi client container docker remove --id my-nginx --force
```
Target a specific host:
```bash
-$ osapi client container remove --id my-nginx --target web-01
+$ osapi client container docker remove --id my-nginx --target web-01
```
## JSON Output
@@ -28,7 +28,7 @@ $ osapi client container remove --id my-nginx --target web-01
Use `--json` to get the full API response:
```bash
-$ osapi client container remove --id a1b2c3d4e5f6 --json
+$ osapi client container docker remove --id a1b2c3d4e5f6 --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/start.md b/docs/docs/sidebar/usage/cli/client/container/docker/start.md
similarity index 76%
rename from docs/docs/sidebar/usage/cli/client/container/start.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/start.md
index 2c44b8fa..b3e1c8a3 100644
--- a/docs/docs/sidebar/usage/cli/client/container/start.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/start.md
@@ -3,7 +3,7 @@
Start a stopped container on the target node:
```bash
-$ osapi client container start --id a1b2c3d4e5f6
+$ osapi client container docker start --id a1b2c3d4e5f6
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -14,13 +14,13 @@ $ osapi client container start --id a1b2c3d4e5f6
Start a container by name:
```bash
-$ osapi client container start --id my-nginx
+$ osapi client container docker start --id my-nginx
```
Target a specific host:
```bash
-$ osapi client container start --id my-nginx --target web-01
+$ osapi client container docker start --id my-nginx --target web-01
```
## JSON Output
@@ -28,7 +28,7 @@ $ osapi client container start --id my-nginx --target web-01
Use `--json` to get the full API response:
```bash
-$ osapi client container start --id a1b2c3d4e5f6 --json
+$ osapi client container docker start --id a1b2c3d4e5f6 --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/cli/client/container/stop.md b/docs/docs/sidebar/usage/cli/client/container/docker/stop.md
similarity index 78%
rename from docs/docs/sidebar/usage/cli/client/container/stop.md
rename to docs/docs/sidebar/usage/cli/client/container/docker/stop.md
index b7ec7e60..69dc0f6e 100644
--- a/docs/docs/sidebar/usage/cli/client/container/stop.md
+++ b/docs/docs/sidebar/usage/cli/client/container/docker/stop.md
@@ -3,7 +3,7 @@
Stop a running container on the target node:
```bash
-$ osapi client container stop --id a1b2c3d4e5f6
+$ osapi client container docker stop --id a1b2c3d4e5f6
Job ID: 550e8400-e29b-41d4-a716-446655440000
@@ -14,13 +14,13 @@ $ osapi client container stop --id a1b2c3d4e5f6
Stop with a custom timeout (seconds to wait before killing):
```bash
-$ osapi client container stop --id my-nginx --timeout 30
+$ osapi client container docker stop --id my-nginx --timeout 30
```
Target a specific host:
```bash
-$ osapi client container stop --id my-nginx --target web-01
+$ osapi client container docker stop --id my-nginx --target web-01
```
## JSON Output
@@ -28,7 +28,7 @@ $ osapi client container stop --id my-nginx --target web-01
Use `--json` to get the full API response:
```bash
-$ osapi client container stop --id a1b2c3d4e5f6 --json
+$ osapi client container docker stop --id a1b2c3d4e5f6 --json
```
## Flags
diff --git a/docs/docs/sidebar/usage/configuration.md b/docs/docs/sidebar/usage/configuration.md
index f9b17a78..a75970a7 100644
--- a/docs/docs/sidebar/usage/configuration.md
+++ b/docs/docs/sidebar/usage/configuration.md
@@ -141,11 +141,11 @@ OSAPI uses fine-grained `resource:verb` permissions for access control. Each API
endpoint requires a specific permission. Built-in roles expand to a default set
of permissions:
-| Role | Permissions |
-| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `admin` | `agent:read`, `agent:write`, `node:read`, `network:read`, `network:write`, `job:read`, `job:write`, `health:read`, `audit:read`, `command:execute`, `file:read`, `file:write`, `container:read`, `container:write`, `container:execute` |
-| `write` | `agent:read`, `node:read`, `network:read`, `network:write`, `job:read`, `job:write`, `health:read`, `file:read`, `file:write`, `container:read`, `container:write` |
-| `read` | `agent:read`, `node:read`, `network:read`, `job:read`, `health:read`, `file:read`, `container:read` |
+| Role | Permissions |
+| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `admin` | `agent:read`, `agent:write`, `node:read`, `network:read`, `network:write`, `job:read`, `job:write`, `health:read`, `audit:read`, `command:execute`, `file:read`, `file:write`, `docker:read`, `docker:write`, `docker:execute` |
+| `write` | `agent:read`, `node:read`, `network:read`, `network:write`, `job:read`, `job:write`, `health:read`, `file:read`, `file:write`, `docker:read`, `docker:write` |
+| `read` | `agent:read`, `node:read`, `network:read`, `job:read`, `health:read`, `file:read`, `docker:read` |
### Custom Roles
@@ -243,7 +243,7 @@ api:
# Permissions: agent:read, agent:write, node:read, network:read,
# network:write, job:read, job:write, health:read,
# audit:read, command:execute, file:read, file:write,
- # container:read, container:write, container:execute
+ # docker:read, docker:write, docker:execute
# roles:
# ops:
# permissions:
diff --git a/docs/plans/2026-03-11-container-runtime-design.md b/docs/plans/2026-03-11-container-runtime-design.md
index e897cec6..df415651 100644
--- a/docs/plans/2026-03-11-container-runtime-design.md
+++ b/docs/plans/2026-03-11-container-runtime-design.md
@@ -1,29 +1,21 @@
-# Container Runtime and Provider Execution Context
+# Container Runtime Management
## Problem
-OSAPI providers execute operations directly on the host OS. As we build new
-providers (user management, cron, etc.), there is no way to develop, test, or
-run them against an isolated environment. Additionally, there is no way to
-manage containers on a host or compose workflows that span both the host and
-containers running on it.
+OSAPI manages Linux system configuration but has no way to manage containers
+running on a host. As containerized workloads become standard, operators need to
+create, start, stop, inspect, and execute commands in containers through the
+same API and CLI they use for everything else.
We need:
1. Container lifecycle management (Docker first, LXD/Podman later) as a new API
domain
-2. A mechanism to run existing providers inside a container without rewriting
- them
-3. An orchestrator DSL layer to compose host and container operations in a
- single plan
## Decision
Add a `container` API domain with a pluggable runtime driver interface. Docker
-is the first implementation using the Go SDK. Introduce a `provider run` CLI
-subcommand that executes a single provider operation as a standalone process
-with JSON I/O. The orchestrator DSL uses `docker exec` + `provider run` to
-transparently run providers inside containers.
+is the first implementation using the Go SDK.
## Architecture
@@ -193,106 +185,6 @@ The `Server` struct does not store handler references as fields. Handlers are
constructed via `GetXxxHandler()` methods and returned as closures, consistent
with all existing domains.
-### Provider Run Subcommand
-
-A new `osapi provider run` CLI subcommand executes a single provider operation
-as a standalone process with JSON I/O. This is the bridge that allows providers
-to run inside containers.
-
-```
-osapi provider run --data ''
-```
-
-This subcommand is hidden from `--help` output. It is a machine interface
-consumed by the orchestrator's Docker exec layer, not a user-facing command.
-
-**Behavior:**
-
-1. Parse provider name, operation, and JSON data from flags
-2. Look up the provider in a runtime registry
-3. Deserialize JSON into the typed parameter struct
-4. Instantiate the provider using the local platform factory
-5. Call the operation method
-6. Serialize result to JSON on stdout
-7. Exit 0 on success, non-zero on failure (error message as JSON on stderr)
-
-**Provider registry:**
-
-```go
-type Registration struct {
- Name string
- Operations map[string]OperationSpec
-}
-
-type OperationSpec struct {
- NewParams func() any
- Run func(ctx context.Context, params any) (any, error)
-}
-```
-
-Each provider registers its operations and parameter types. The `provider run`
-command looks up the provider and operation, creates the param type, unmarshals
-JSON into it, calls `Run`, and marshals the result.
-
-The SDK already has typed methods and parameter structs. The `provider run`
-subcommand only needs JSON-in/JSON-out because the SDK handles type safety on
-the caller side.
-
-### Orchestrator DSL
-
-The orchestrator DSL adds container targeting through `Docker()` and `In()`
-methods on the `Plan` instance:
-
-```go
-p := orchestrator.NewPlan(client)
-web := p.Docker("web-server", "ubuntu:24.04")
-
-create := p.TaskFunc("create container", func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- return c.Container.Create(ctx, target, container.CreateParams{
- Image: "ubuntu:24.04",
- Name: "web-server",
- })
-})
-
-p.In(web).TaskFunc("add user", func(ctx context.Context, c *client.Client) (*orchestrator.Result, error) {
- // c here is container-scoped — calls route through docker exec
- return c.User.Create(ctx, user.CreateParams{
- Username: "deploy",
- Shell: "/bin/bash",
- })
-}).DependsOn(create)
-```
-
-**How `In(target)` works:**
-
-1. `p.Docker(name, image)` returns a `RuntimeTarget` handle that knows it is a
- Docker container with that name and image
-2. At container creation, the orchestrator volume-mounts the host's `osapi`
- binary into the container
-3. `p.In(target)` returns a scoped plan context where SDK client method calls
- are intercepted
-4. Instead of HTTP requests to the API server, the scoped client serializes
- params to JSON and executes
- `docker exec /osapi provider run --data ''`
- through the Docker driver's `Exec` method
-5. JSON stdout is deserialized back into the typed result struct
-
-The developer works with the same typed SDK methods. The transport changes from
-HTTP to Docker exec + provider run, but the interface is identical.
-
-**`RuntimeTarget` interface** (for future LXD/Podman support):
-
-```go
-type RuntimeTarget interface {
- Name() string
- Runtime() string // "docker", "lxd", "podman"
- ExecProvider(ctx context.Context, provider, operation string, data []byte) ([]byte, error)
-}
-```
-
-`p.Docker()` and (future) `p.LXD()` return different implementations of the same
-interface. `p.In()` accepts any `RuntimeTarget`.
-
### Configuration
No new configuration sections are needed in `osapi.yaml`. The Docker driver
@@ -338,7 +230,6 @@ internal/api/
└── handler_public_test.go # +TestGetContainerHandler
cmd/
-├── provider_run.go # provider run subcommand (hidden)
├── client_container.go # parent command
├── client_container_create.go # CLI per endpoint
├── client_container_list.go
@@ -349,12 +240,7 @@ cmd/
├── client_container_exec.go
└── client_container_pull.go
-pkg/sdk/
-├── client/container.go # SDK service wrapper
-└── orchestrator/
- ├── runtime_target.go # RuntimeTarget interface
- ├── docker_target.go # Docker implementation
- └── plan_in.go # In() scoped context
+pkg/sdk/client/container.go # SDK service wrapper
```
### Documentation
@@ -388,10 +274,21 @@ just go::vet # lint passes
| API nesting | Under `/node/{hostname}` | Containers run on a node, consistent with existing API conventions |
| Separate `execute` permission | `container:execute` | Running commands in containers is a distinct privilege from lifecycle ops |
| Graceful absence | Nil provider, descriptive error | Agents without Docker still work for all other providers |
-| Provider run subcommand | JSON-in/JSON-out, hidden | Machine interface consumed by SDK; type safety lives in SDK |
-| Provider registry | Runtime registration | No code generation needed; new providers just register themselves |
-| Volume-mount binary | Mount host osapi into container | Any base image works; no custom OSAPI container image required |
-| DSL via `In(target)` | Scoped client, same SDK types | Developers use identical API; only transport changes |
| `{id}` parameter | String with pattern, not UUID | Docker IDs are hex strings/names, not UUIDs |
| Remove force flag | Query parameter, no body | Consistent with existing DELETE endpoints |
| Pull behavior | Async via job system | Large pulls can take minutes; blocking HTTP is unreliable |
+
+## What Was Removed
+
+The original design included two additional layers that have been dropped:
+
+- **`provider run` CLI subcommand** — A hidden command to run OSAPI providers
+ inside containers via `docker exec`. Removed because we are not running OSAPI
+ inside containers.
+- **Orchestrator DSL `In(target)` / `Docker()`** — Scoped plan context that
+ intercepted SDK client calls and routed them through `docker exec` +
+ `provider run`. Removed because it depended on `provider run`.
+
+Container operations are managed through the standard API/CLI/SDK path, the same
+as every other OSAPI domain. The orchestrator can compose container operations
+with host operations using `TaskFunc` — no special DSL extensions needed.
diff --git a/docs/plans/2026-03-11-container-runtime.md b/docs/plans/2026-03-11-container-runtime.md
index 77fc6b6b..c37c3229 100644
--- a/docs/plans/2026-03-11-container-runtime.md
+++ b/docs/plans/2026-03-11-container-runtime.md
@@ -4,21 +4,17 @@
> (if subagents available) or superpowers:executing-plans to implement this
> plan. Steps use checkbox (`- [ ]`) syntax for tracking.
-**Goal:** Add container lifecycle management (Docker), a `provider run`
-subcommand for running providers inside containers, and an orchestrator DSL
-layer for composing host and container operations.
+**Goal:** Add container lifecycle management (Docker) as a new API domain with
+create, start, stop, remove, list, inspect, exec, and pull operations.
**Architecture:** A `runtime.Driver` interface abstracts container runtimes with
Docker as the first implementation via the Go SDK. Container lifecycle is
-exposed as a new API domain under `/node/{hostname}/container`. A hidden
-`provider run` CLI subcommand executes individual provider operations with JSON
-I/O, enabling the orchestrator DSL's `In(target)` to transparently run providers
-inside containers via `docker exec`.
+exposed as a new API domain under `/node/{hostname}/container`.
**Tech Stack:** Go, Docker Go SDK (`github.com/docker/docker/client`),
oapi-codegen, Echo, testify/suite, NATS JetStream
-**Spec:** `docs/superpowers/specs/2026-03-11-container-runtime-design.md`
+**Spec:** `docs/plans/2026-03-11-container-runtime-design.md`
---
@@ -1363,554 +1359,9 @@ git commit -m "feat(container): add container CLI commands"
---
-## Chunk 6: Provider Run Subcommand
+## Chunk 6: Documentation and Verification
-### Task 13: Provider Registry
-
-**Files:**
-
-- Create: `internal/provider/registry/registry.go`
-- Create: `internal/provider/registry/registry_public_test.go`
-
-- [ ] **Step 1: Write failing tests**
-
-Test: register a provider, look it up, look up nonexistent provider.
-
-```go
-package registry_test
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/suite"
-
- "github.com/retr0h/osapi/internal/provider/registry"
-)
-
-type RegistryPublicTestSuite struct {
- suite.Suite
-}
-
-func (s *RegistryPublicTestSuite) TestLookup() {
- tests := []struct {
- name string
- provider string
- operation string
- register bool
- expectFound bool
- }{
- {
- name: "registered provider found",
- provider: "host",
- operation: "hostname",
- register: true,
- expectFound: true,
- },
- {
- name: "unregistered provider not found",
- provider: "nonexistent",
- operation: "get",
- register: false,
- expectFound: false,
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- r := registry.New()
- if tt.register {
- r.Register(registry.Registration{
- Name: tt.provider,
- Operations: map[string]registry.OperationSpec{
- tt.operation: {
- NewParams: func() any { return nil },
- Run: func(_ context.Context, _ any) (any, error) {
- return "result", nil
- },
- },
- },
- })
- }
- spec, ok := r.Lookup(tt.provider, tt.operation)
- s.Equal(tt.expectFound, ok)
- if tt.expectFound {
- s.NotNil(spec)
- }
- })
- }
-}
-
-func TestRegistryPublicTestSuite(t *testing.T) {
- suite.Run(t, new(RegistryPublicTestSuite))
-}
-```
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run:
-`go test -run TestRegistryPublicTestSuite -v ./internal/provider/registry/...`
-Expected: FAIL
-
-- [ ] **Step 3: Implement the registry**
-
-```go
-// Package registry provides a runtime registry for provider operations.
-package registry
-
-import "context"
-
-// OperationSpec defines how to create params and run an operation.
-type OperationSpec struct {
- NewParams func() any
- Run func(ctx context.Context, params any) (any, error)
-}
-
-// Registration describes a provider and its operations.
-type Registration struct {
- Name string
- Operations map[string]OperationSpec
-}
-
-// Registry holds provider registrations.
-type Registry struct {
- providers map[string]Registration
-}
-
-// New creates a new empty registry.
-func New() *Registry {
- return &Registry{
- providers: make(map[string]Registration),
- }
-}
-
-// Register adds a provider registration.
-func (r *Registry) Register(
- reg Registration,
-) {
- r.providers[reg.Name] = reg
-}
-
-// Lookup finds an operation spec by provider and operation name.
-func (r *Registry) Lookup(
- provider string,
- operation string,
-) (*OperationSpec, bool) {
- reg, ok := r.providers[provider]
- if !ok {
- return nil, false
- }
-
- spec, ok := reg.Operations[operation]
- if !ok {
- return nil, false
- }
-
- return &spec, true
-}
-```
-
-- [ ] **Step 4: Run test to verify it passes**
-
-Run:
-`go test -run TestRegistryPublicTestSuite -v ./internal/provider/registry/...`
-Expected: PASS
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add internal/provider/registry/
-git commit -m "feat(container): add provider runtime registry"
-```
-
----
-
-### Task 14: Provider Run CLI Subcommand
-
-**Files:**
-
-- Create: `cmd/provider_run.go`
-
-- [ ] **Step 1: Write the provider run command**
-
-Create `cmd/provider_run.go`. This is a hidden command (`Hidden: true` on the
-Cobra command). It:
-
-1. Takes positional args: `provider` and `operation`
-2. Takes `--data` flag for JSON input
-3. Builds a registry, registers all known providers
-4. Looks up the provider/operation
-5. Unmarshals JSON into params via `spec.NewParams()`
-6. Calls `spec.Run()`
-7. Marshals result to JSON on stdout
-8. Exits with code 0 on success, 1 on failure
-
-```go
-package cmd
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "os"
-
- "github.com/spf13/cobra"
-
- "github.com/retr0h/osapi/internal/provider/registry"
-)
-
-var providerRunData string
-
-var providerRunCmd = &cobra.Command{
- Use: "run [provider] [operation]",
- Short: "Run a provider operation (internal)",
- Hidden: true,
- Args: cobra.ExactArgs(2),
- Run: func(cmd *cobra.Command, args []string) {
- providerName := args[0]
- operationName := args[1]
-
- reg := buildProviderRegistry()
- spec, ok := reg.Lookup(providerName, operationName)
- if !ok {
- errJSON, _ := json.Marshal(map[string]string{
- "error": fmt.Sprintf("unknown provider/operation: %s/%s", providerName, operationName),
- })
- fmt.Fprintln(os.Stderr, string(errJSON))
- os.Exit(1)
- }
-
- params := spec.NewParams()
- if providerRunData != "" && params != nil {
- if err := json.Unmarshal([]byte(providerRunData), params); err != nil {
- errJSON, _ := json.Marshal(map[string]string{"error": err.Error()})
- fmt.Fprintln(os.Stderr, string(errJSON))
- os.Exit(1)
- }
- }
-
- result, err := spec.Run(context.Background(), params)
- if err != nil {
- errJSON, _ := json.Marshal(map[string]string{"error": err.Error()})
- fmt.Fprintln(os.Stderr, string(errJSON))
- os.Exit(1)
- }
-
- output, _ := json.Marshal(result)
- fmt.Println(string(output))
- },
-}
-
-var providerCmd = &cobra.Command{
- Use: "provider",
- Short: "Provider operations (internal)",
- Hidden: true,
-}
-
-func init() {
- providerRunCmd.Flags().StringVar(&providerRunData, "data", "", "JSON input data")
- providerCmd.AddCommand(providerRunCmd)
- rootCmd.AddCommand(providerCmd)
-}
-```
-
-- [ ] **Step 2: Write buildProviderRegistry function**
-
-This function creates a `registry.Registry` and registers all known providers
-using the platform factory. Initially register just the `host` provider as a
-proof of concept. More providers get registered as they are built.
-
-- [ ] **Step 3: Verify build**
-
-Run: `go build ./...` Expected: compiles
-
-- [ ] **Step 4: Verify hidden from help**
-
-Run: `go run main.go --help` Expected: `provider` does NOT appear in the command
-list
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add cmd/provider_run.go
-git commit -m "feat(container): add hidden provider run subcommand"
-```
-
----
-
-## Chunk 7: Orchestrator DSL
-
-### Task 15: RuntimeTarget Interface
-
-**Files:**
-
-- Create: `pkg/sdk/orchestrator/runtime_target.go`
-- Create: `pkg/sdk/orchestrator/runtime_target_public_test.go`
-
-- [ ] **Step 1: Write the RuntimeTarget interface**
-
-```go
-// Package orchestrator provides DAG-based task orchestration.
-package orchestrator
-
-import "context"
-
-// RuntimeTarget represents a container runtime target that can execute
-// provider operations. Implementations exist for Docker (now) and
-// LXD/Podman (later).
-type RuntimeTarget interface {
- // Name returns the target name (container name).
- Name() string
- // Runtime returns the runtime type ("docker", "lxd", "podman").
- Runtime() string
- // ExecProvider executes a provider operation inside the target.
- ExecProvider(ctx context.Context, provider, operation string, data []byte) ([]byte, error)
-}
-```
-
-- [ ] **Step 2: Commit**
-
-```bash
-git add pkg/sdk/orchestrator/runtime_target.go
-git commit -m "feat(container): add RuntimeTarget interface"
-```
-
----
-
-### Task 16: Docker RuntimeTarget Implementation
-
-**Files:**
-
-- Create: `pkg/sdk/orchestrator/docker_target.go`
-- Create: `pkg/sdk/orchestrator/docker_target_public_test.go`
-
-- [ ] **Step 1: Write failing test**
-
-Test that `DockerTarget` implements `RuntimeTarget`, returns correct name and
-runtime type, and that `ExecProvider` constructs the correct exec call.
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run:
-`go test -run TestDockerTargetPublicTestSuite -v ./pkg/sdk/orchestrator/...`
-Expected: FAIL
-
-- [ ] **Step 3: Implement DockerTarget**
-
-Note: The orchestrator lives in `pkg/sdk/` which should not import `internal/`
-packages directly. Instead of importing `runtime.Driver`, we inject an `ExecFn`
-function type that the caller wires to the Docker driver.
-
-```go
-package orchestrator
-
-import (
- "context"
- "fmt"
-)
-
-// ExecFn executes a command inside a container and returns stdout/stderr/exit code.
-// This is injected by the caller, typically wired to runtime.Driver.Exec.
-type ExecFn func(ctx context.Context, containerID string, command []string) (stdout, stderr string, exitCode int, err error)
-
-// DockerTarget implements RuntimeTarget for Docker containers.
-type DockerTarget struct {
- name string
- image string
- execFn ExecFn
-}
-
-// NewDockerTarget creates a new Docker runtime target.
-func NewDockerTarget(
- name string,
- image string,
- execFn ExecFn,
-) *DockerTarget {
- return &DockerTarget{
- name: name,
- image: image,
- execFn: execFn,
- }
-}
-
-// Name returns the container name.
-func (t *DockerTarget) Name() string {
- return t.name
-}
-
-// Runtime returns "docker".
-func (t *DockerTarget) Runtime() string {
- return "docker"
-}
-
-// Image returns the container image.
-func (t *DockerTarget) Image() string {
- return t.image
-}
-
-// ExecProvider runs a provider operation inside this container via docker exec.
-func (t *DockerTarget) ExecProvider(
- ctx context.Context,
- provider string,
- operation string,
- data []byte,
-) ([]byte, error) {
- cmd := []string{"/osapi", "provider", "run", provider, operation}
- if len(data) > 0 {
- cmd = append(cmd, "--data", string(data))
- }
-
- stdout, stderr, exitCode, err := t.execFn(ctx, t.name, cmd)
- if err != nil {
- return nil, fmt.Errorf("exec provider in container %s: %w", t.name, err)
- }
-
- if exitCode != 0 {
- return nil, fmt.Errorf("provider %s/%s failed (exit %d): %s",
- provider, operation, exitCode, stderr)
- }
-
- return []byte(stdout), nil
-}
-```
-
-The caller (e.g., `cmd/` or the user's orchestrator code) wires the `ExecFn` by
-closing over the Docker driver:
-
-```go
-execFn := func(ctx context.Context, id string, cmd []string) (string, string, int, error) {
- result, err := dockerDriver.Exec(ctx, id, runtime.ExecParams{Command: cmd})
- if err != nil {
- return "", "", -1, err
- }
- return result.Stdout, result.Stderr, result.ExitCode, nil
-}
-target := orchestrator.NewDockerTarget("web", "ubuntu:24.04", execFn)
-```
-
-- [ ] **Step 4: Run test to verify it passes**
-
-Run:
-`go test -run TestDockerTargetPublicTestSuite -v ./pkg/sdk/orchestrator/...`
-Expected: PASS
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add pkg/sdk/orchestrator/docker_target.go \
- pkg/sdk/orchestrator/docker_target_public_test.go
-git commit -m "feat(container): add Docker RuntimeTarget implementation"
-```
-
----
-
-### Task 17: Plan.Docker() and Plan.In() Methods
-
-**Files:**
-
-- Create: `pkg/sdk/orchestrator/plan_in.go`
-- Create: `pkg/sdk/orchestrator/plan_in_public_test.go`
-
-- [ ] **Step 1: Write failing tests**
-
-Test that `p.Docker()` returns a `*DockerTarget` with correct name/image. Test
-that `p.In()` returns a `ScopedPlan` and that `TaskFunc` on the scoped plan adds
-a task to the parent plan.
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run: `go test -run TestPlanInPublicTestSuite -v ./pkg/sdk/orchestrator/...`
-Expected: FAIL
-
-- [ ] **Step 3: Implement Docker() and In()**
-
-```go
-package orchestrator
-
-// Docker creates a DockerTarget bound to this plan's container exec function.
-// Panics if no ExecFn was provided via WithDockerExecFn option.
-func (p *Plan) Docker(
- name string,
- image string,
-) *DockerTarget {
- if p.dockerExecFn == nil {
- panic("orchestrator: Plan.Docker() called without WithDockerExecFn option")
- }
- return NewDockerTarget(name, image, p.dockerExecFn)
-}
-
-// In returns a ScopedPlan that routes provider operations through the
-// given RuntimeTarget (e.g., a Docker container).
-type ScopedPlan struct {
- plan *Plan
- target RuntimeTarget
-}
-
-// In creates a scoped plan context for the given runtime target.
-func (p *Plan) In(
- target RuntimeTarget,
-) *ScopedPlan {
- return &ScopedPlan{
- plan: p,
- target: target,
- }
-}
-
-// TaskFunc creates a task on the parent plan that executes within the
-// scoped runtime target context.
-func (sp *ScopedPlan) TaskFunc(
- name string,
- fn TaskFn,
-) *Task {
- // Wrap the function to inject the runtime target context
- return sp.plan.TaskFunc(name, fn)
-}
-
-// TaskFuncWithResults creates a task with results on the parent plan.
-func (sp *ScopedPlan) TaskFuncWithResults(
- name string,
- fn TaskFnWithResults,
-) *Task {
- return sp.plan.TaskFuncWithResults(name, fn)
-}
-```
-
-Note: The full client-interception layer (where SDK calls automatically route
-through `docker exec` + `provider run`) is more complex. This initial
-implementation provides the `In()` scoping mechanism. The interception layer
-that replaces the HTTP transport with Docker exec is the next evolution — for
-now, task functions inside `In()` can manually use `target.ExecProvider()` to
-run providers in the container.
-
-- [ ] **Step 4: Run test to verify it passes**
-
-Run: `go test -run TestPlanInPublicTestSuite -v ./pkg/sdk/orchestrator/...`
-Expected: PASS
-
-- [ ] **Step 5: Add dockerExecFn field to Plan**
-
-Modify `pkg/sdk/orchestrator/plan.go` to add an optional `dockerExecFn ExecFn`
-field to `PlanConfig` and a `WithDockerExecFn(fn ExecFn)` plan option. The
-`Plan.Docker()` method reads from `p.config.dockerExecFn`.
-
-- [ ] **Step 6: Run full orchestrator tests**
-
-Run: `go test -v ./pkg/sdk/orchestrator/...` Expected: all tests pass
-
-- [ ] **Step 7: Commit**
-
-```bash
-git add pkg/sdk/orchestrator/plan_in.go \
- pkg/sdk/orchestrator/plan_in_public_test.go \
- pkg/sdk/orchestrator/plan.go
-git commit -m "feat(container): add Plan.Docker() and Plan.In() DSL methods"
-```
-
----
-
-## Chunk 8: Documentation and Verification
-
-### Task 18: Documentation
+### Task 13: Documentation
**Files:**
@@ -1966,7 +1417,7 @@ git commit -m "docs: add container management documentation"
---
-### Task 19: Integration Test Smoke Suite
+### Task 14: Integration Test Smoke Suite
**Files:**
@@ -1997,7 +1448,7 @@ git commit -m "test(container): add integration test smoke suite"
---
-### Task 20: Final Verification
+### Task 15: Final Verification
- [ ] **Step 1: Regenerate all specs and code**
@@ -2026,10 +1477,10 @@ Run coverage and check that every new package has 100% line coverage:
```bash
go test -race -coverprofile=.coverage/cover.out -v ./...
grep -v -f .coverignore .coverage/cover.out > .coverage/cover.tmp && mv .coverage/cover.tmp .coverage/cover.out
-go tool cover -func=.coverage/cover.out | grep -E 'container|registry' | grep -v '100.0%'
+go tool cover -func=.coverage/cover.out | grep 'container' | grep -v '100.0%'
```
-Expected: **no output** (all container and registry packages at 100%).
+Expected: **no output** (all container packages at 100%).
If any lines are uncovered, add tests before proceeding. The `.coverignore`
already excludes `/cmd/`, `/gen/`, `main.go`, and `/mocks/`, so handler tests in
diff --git a/docs/plans/2026-03-13-container-runtime-rename-design.md b/docs/plans/2026-03-13-container-runtime-rename-design.md
new file mode 100644
index 00000000..35b44359
--- /dev/null
+++ b/docs/plans/2026-03-13-container-runtime-rename-design.md
@@ -0,0 +1,190 @@
+# Container Runtime: Docker-Specific Domain Design
+
+## Problem
+
+The current container domain uses a generic `container` name with an
+auto-detecting runtime driver. This is wrong — the user decides which runtime to
+use, not the agent. Docker, LXD, and Podman are fundamentally different systems
+with different concepts, options, and behaviors. A shared abstraction would be
+lowest-common-denominator or leak everywhere.
+
+## Decision
+
+Rename the `container` domain to `docker`. Each future runtime (LXD, Podman)
+becomes its own independent domain — no shared interface, no shared types, no
+abstraction tax.
+
+The CLI groups runtimes under a `container` parent command for discoverability.
+API paths mirror this with `/container/docker/`.
+
+## Architecture
+
+### Naming Convention
+
+| Layer | Current | New |
+| ------------ | ------------------------------ | ----------------------------------- |
+| API paths | `/node/{hostname}/container` | `/node/{hostname}/container/docker` |
+| Permissions | `container:read/write/execute` | `docker:read/write/execute` |
+| CLI | `client container list` | `client container docker list` |
+| SDK | `client.Container.Pull()` | `client.Docker.Pull()` |
+| Job category | `container` | `docker` |
+| Provider pkg | `internal/provider/container/` | `internal/provider/docker/` |
+| API pkg | `internal/api/container/` | `internal/api/docker/` |
+
+### API Endpoints
+
+| Method | Path | Operation | Permission |
+| -------- | ---------------------------------------------- | --------- | ---------------- |
+| `POST` | `/node/{hostname}/container/docker` | Create | `docker:write` |
+| `GET` | `/node/{hostname}/container/docker` | List | `docker:read` |
+| `GET` | `/node/{hostname}/container/docker/{id}` | Inspect | `docker:read` |
+| `POST` | `/node/{hostname}/container/docker/{id}/start` | Start | `docker:write` |
+| `POST` | `/node/{hostname}/container/docker/{id}/stop` | Stop | `docker:write` |
+| `DELETE` | `/node/{hostname}/container/docker/{id}` | Remove | `docker:write` |
+| `POST` | `/node/{hostname}/container/docker/{id}/exec` | Exec | `docker:execute` |
+| `POST` | `/node/{hostname}/container/docker/pull` | Pull | `docker:write` |
+
+### CLI
+
+```
+osapi client container docker list [--target HOST] [--state STATE] [--limit N]
+osapi client container docker create --target HOST --image IMAGE [--name NAME] ...
+osapi client container docker inspect --target HOST --id ID
+osapi client container docker start --target HOST --id ID
+osapi client container docker stop --target HOST --id ID [--timeout SECONDS]
+osapi client container docker remove --target HOST --id ID [--force]
+osapi client container docker exec --target HOST --id ID --command CMD...
+osapi client container docker pull --target HOST --image IMAGE
+```
+
+The `container` command is a parent with `` for grouping. Each
+runtime is a subcommand. Future runtimes add `client container lxd`,
+`client container podman`, etc.
+
+### Role Updates
+
+| Role | Permissions |
+| ------- | ----------------------------------------------- |
+| `admin` | `docker:read`, `docker:write`, `docker:execute` |
+| `write` | `docker:read`, `docker:write` |
+| `read` | `docker:read` |
+
+### Package Layout
+
+```
+internal/provider/docker/
+├── docker.go # Provider struct, New()
+├── types.go # CreateParams, Container, etc.
+├── docker_test.go # Tests
+└── (no runtime/ subdirectory)
+
+internal/api/docker/
+├── gen/
+│ ├── api.yaml # OpenAPI spec
+│ ├── cfg.yaml # oapi-codegen config
+│ └── generate.go # go:generate directive
+├── types.go # Domain struct, interfaces
+├── docker.go # New(), interface check
+├── docker_create.go # Create handler
+├── docker_list.go # List handler
+├── docker_inspect.go # Inspect handler
+├── docker_start.go # Start handler
+├── docker_stop.go # Stop handler
+├── docker_remove.go # Remove handler
+├── docker_exec.go # Exec handler
+├── docker_pull.go # Pull handler
+└── *_public_test.go # Tests
+
+internal/api/
+├── handler_docker.go # GetDockerHandler() method
+└── handler.go # +RegisterHandlers() wiring
+
+cmd/
+├── client_container.go # parent: `container` subcommand
+├── client_container_docker.go # parent: `docker` subcommand
+├── client_container_docker_create.go
+├── client_container_docker_list.go
+├── client_container_docker_inspect.go
+├── client_container_docker_start.go
+├── client_container_docker_stop.go
+├── client_container_docker_remove.go
+├── client_container_docker_exec.go
+└── client_container_docker_pull.go
+
+pkg/sdk/client/
+├── docker.go # DockerService
+└── docker_types.go # DockerResult, etc.
+
+internal/agent/
+├── processor_docker.go # docker case + dispatch
+└── types.go # dockerProvider field
+```
+
+### No Shared Runtime Interface
+
+The `runtime.Driver` interface in
+`internal/provider/container/runtime/driver.go` is removed. The Docker provider
+defines its own types directly. When LXD is added, it gets its own provider
+package (`internal/provider/lxd/`) with its own types — LXD concepts (instances,
+profiles, projects) don't map to Docker concepts (images, containers, layers).
+
+Each runtime is fully independent:
+
+- Own API domain, paths, and OpenAPI schemas
+- Own CLI subcommands under `client container `
+- Own SDK service (`client.Docker`, `client.Lxd`)
+- Own permissions (`docker:read`, `lxd:read`)
+- Own provider package with own types
+- Own orchestrator helpers
+
+### Orchestrator DSL
+
+Convenience methods on `*Plan` in `pkg/sdk/orchestrator/` wrap `client.Docker.*`
+calls so users don't write boilerplate TaskFunc bodies:
+
+```go
+plan.DockerPull("pull-image", target, "ubuntu:24.04")
+plan.DockerCreate("create-app", target, gen.DockerCreateRequest{...})
+plan.DockerExec("run-cmd", target, "my-app", gen.DockerExecRequest{...})
+plan.DockerInspect("check", target, "my-app")
+plan.DockerStart("start", target, "my-app")
+plan.DockerStop("stop", target, "my-app", gen.DockerStopRequest{...})
+plan.DockerRemove("cleanup", target, "my-app", &gen.DeleteNodeDockerByIDParams{...})
+```
+
+Each returns `*Task` for chaining (`DependsOn`, `OnlyIfChanged`, etc.). Future
+runtimes add `plan.LxdLaunch(...)`, `plan.LxdExec(...)` — no shared interface.
+
+### Documentation
+
+- `docs/docs/sidebar/features/container-management.md` — update to describe
+ Docker as the first runtime, explain the per-runtime model
+- CLI docs: restructure under `container/docker/`
+- SDK orchestrator docs: update container-targeting to use `plan.DockerPull`
+ etc.
+
+## What This Changes
+
+This is a mechanical rename + restructure of the existing fully-built container
+domain. No behavior changes. The scope is:
+
+1. Rename ~40+ files across all layers (API, CLI, SDK, agent, provider, job
+ types, tests, docs)
+2. Remove `internal/provider/container/runtime/driver.go` shared interface
+3. Flatten `internal/provider/container/runtime/docker/` →
+ `internal/provider/docker/`
+4. Add `container` parent CLI command
+5. Add orchestrator DSL helpers
+6. Update all docs
+
+## Key Design Decisions
+
+| Decision | Choice | Rationale |
+| ---------------------------- | ------------------- | ------------------------------------------------------ |
+| User chooses runtime | Yes | Agent shouldn't guess; Docker/LXD/Podman are different |
+| Separate domains per runtime | Yes | No useful shared abstraction across runtimes |
+| CLI nesting | `container docker` | Groups runtimes for discoverability |
+| API path nesting | `/container/docker` | Mirrors CLI structure |
+| No shared interface | Yes | LXD concepts don't map to Docker concepts |
+| Flat provider packages | Yes | No shared parent code to justify nesting |
+| Orchestrator helpers | Methods on Plan | Eliminates TaskFunc boilerplate |
diff --git a/docs/plans/2026-03-13-container-runtime-rename.md b/docs/plans/2026-03-13-container-runtime-rename.md
new file mode 100644
index 00000000..e73ac941
--- /dev/null
+++ b/docs/plans/2026-03-13-container-runtime-rename.md
@@ -0,0 +1,976 @@
+# Container → Docker Domain Rename Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to
+> implement this plan task-by-task.
+
+**Goal:** Rename the generic `container` domain to `docker`, nest under a
+`container` parent in CLI/API paths, remove the shared `runtime.Driver`
+interface, and add orchestrator DSL helpers.
+
+**Architecture:** Mechanical rename across all layers (API, provider, agent,
+job, CLI, SDK, permissions, docs, tests) from `container` to `docker`. API paths
+change from `/node/{hostname}/container` to `/node/{hostname}/container/docker`.
+CLI changes from `client container list` to `client container docker list`. The
+shared `runtime.Driver` interface is removed — Docker provider owns its types
+directly. New orchestrator DSL methods (`plan.DockerPull`, etc.) wrap SDK client
+calls.
+
+**Tech Stack:** Go, Echo, oapi-codegen, Cobra, testify/suite, Docker Go SDK
+
+**Spec:** `docs/plans/2026-03-13-container-runtime-rename-design.md`
+
+---
+
+## Chunk 1: OpenAPI Spec + Permissions
+
+### Task 1: Rename OpenAPI Spec
+
+**Files:**
+
+- Modify: `internal/api/container/gen/api.yaml`
+
+**Step 1:** Rename the directory:
+
+```bash
+git mv internal/api/container internal/api/docker
+```
+
+**Step 2:** Edit `internal/api/docker/gen/api.yaml`:
+
+- Change all paths from `/node/{hostname}/container` to
+ `/node/{hostname}/container/docker`
+- Change all security scopes from `container:read/write/execute` to
+ `docker:read/write/execute`
+- Rename all schema names from `Container*` to `Docker*` (e.g.,
+ `ContainerCreateRequest` → `DockerCreateRequest`, `ContainerResponse` →
+ `DockerResponse`)
+- Rename all operation IDs from `*Container*` to `*Docker*`
+- Update tag names and descriptions from "Container" to "Docker"
+- Update the `ContainerId` parameter to `DockerId`
+
+**Step 3:** Update `internal/api/docker/gen/cfg.yaml`:
+
+- Change output filename from `container.gen.go` to `docker.gen.go`
+- Update package name if needed
+
+**Step 4:** Update `internal/api/docker/gen/generate.go`:
+
+- Update the `go:generate` directive path if needed
+
+**Step 5:** Regenerate:
+
+```bash
+go generate ./internal/api/docker/gen/...
+```
+
+**Step 6:** Verify generation succeeded — `docker.gen.go` should exist:
+
+```bash
+ls internal/api/docker/gen/docker.gen.go
+```
+
+**Step 7:** Delete old generated file if it still exists:
+
+```bash
+rm -f internal/api/docker/gen/container.gen.go
+```
+
+**Step 8:** Commit:
+
+```bash
+git add internal/api/docker/ internal/api/container/
+git commit -m "refactor: rename container OpenAPI spec to docker"
+```
+
+---
+
+### Task 2: Rename Permissions
+
+**Files:**
+
+- Modify: `internal/authtoken/permissions.go`
+
+**Step 1:** Rename the permission constants:
+
+- `PermContainerRead` → `PermDockerRead` with value `"docker:read"`
+- `PermContainerWrite` → `PermDockerWrite` with value `"docker:write"`
+- `PermContainerExecute` → `PermDockerExecute` with value `"docker:execute"`
+
+**Step 2:** Update the `AllPermissions` slice to use the new names.
+
+**Step 3:** Update the default role mappings (admin, write, read) to use the new
+permission constants.
+
+**Step 4:** Search for any other files referencing the old permission constants:
+
+```bash
+grep -rn 'PermContainer\|container:read\|container:write\|container:execute' \
+ --include='*.go' . | grep -v '.gen.go' | grep -v '_test.go'
+```
+
+Fix all references found (likely in `internal/api/docker/` handlers and
+`cmd/api_helpers.go`).
+
+**Step 5:** Verify it compiles:
+
+```bash
+go build ./internal/authtoken/... ./internal/api/docker/...
+```
+
+**Step 6:** Run permission tests:
+
+```bash
+go test ./internal/authtoken/... -count=1
+```
+
+**Step 7:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container permissions to docker"
+```
+
+---
+
+## Chunk 2: Provider Layer
+
+### Task 3: Flatten and Rename Provider
+
+**Files:**
+
+- Rename: `internal/provider/container/` → `internal/provider/docker/`
+- Remove: `internal/provider/container/runtime/driver.go` (shared interface)
+
+**Step 1:** Move the Docker driver implementation up and rename:
+
+```bash
+git mv internal/provider/container internal/provider/docker
+```
+
+**Step 2:** The directory structure should become:
+
+```
+internal/provider/docker/
+├── provider.go
+├── types.go
+├── provider_public_test.go
+├── mocks/
+├── runtime/
+│ ├── driver.go ← DELETE this (shared interface)
+│ ├── docker/
+│ │ ├── docker.go
+│ │ └── docker_public_test.go
+│ └── mocks/
+```
+
+Move `runtime/docker/docker.go` types and implementation into the parent
+package, or keep `runtime/docker/` as the actual Docker SDK driver. The provider
+in `provider.go` already wraps the driver, so the structure can stay — just
+update the package import paths from `internal/provider/container/...` to
+`internal/provider/docker/...`.
+
+**Step 3:** Delete the shared `runtime.Driver` interface:
+
+```bash
+rm internal/provider/docker/runtime/driver.go
+```
+
+**Step 4:** Update the Docker driver (`runtime/docker/docker.go`) to define its
+own interface or use concrete types instead of the removed `runtime.Driver`. The
+provider in `provider.go` should type-assert or use the concrete Docker driver
+type.
+
+**Step 5:** Update all import paths in the provider package from
+`internal/provider/container` to `internal/provider/docker`.
+
+**Step 6:** Update package declarations — `package container` → `package docker`
+in `provider.go`, `types.go`, etc.
+
+**Step 7:** Rename the `Provider` interface methods and types if they use
+`Container` prefix (check `types.go`).
+
+**Step 8:** Update mock generation directives in `mocks/generate.go`.
+
+**Step 9:** Regenerate mocks:
+
+```bash
+go generate ./internal/provider/docker/mocks/...
+go generate ./internal/provider/docker/runtime/mocks/...
+```
+
+**Step 10:** Verify it compiles:
+
+```bash
+go build ./internal/provider/docker/...
+```
+
+**Step 11:** Run tests:
+
+```bash
+go test ./internal/provider/docker/... -count=1
+```
+
+**Step 12:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container provider to docker"
+```
+
+---
+
+## Chunk 3: Job Types
+
+### Task 4: Rename Job Types and Operations
+
+**Files:**
+
+- Modify: `internal/job/types.go`
+- Modify: `internal/job/client/modify_container.go` (rename to
+ `modify_docker.go`)
+- Modify: `internal/job/client/modify_container_public_test.go` (rename to
+ `modify_docker_public_test.go`)
+
+**Step 1:** In `internal/job/types.go`, rename all container operation
+constants:
+
+- `OperationContainerCreate` → `OperationDockerCreate` with value
+ `"docker.create.execute"`
+- `OperationContainerStart` → `OperationDockerStart` with value
+ `"docker.start.execute"`
+- `OperationContainerStop` → `OperationDockerStop` with value
+ `"docker.stop.execute"`
+- `OperationContainerRemove` → `OperationDockerRemove` with value
+ `"docker.remove.execute"`
+- `OperationContainerList` → `OperationDockerList` with value
+ `"docker.list.get"`
+- `OperationContainerInspect` → `OperationDockerInspect` with value
+ `"docker.inspect.get"`
+- `OperationContainerExec` → `OperationDockerExec` with value
+ `"docker.exec.execute"`
+- `OperationContainerPull` → `OperationDockerPull` with value
+ `"docker.pull.execute"`
+
+**Step 2:** Rename all data types:
+
+- `ContainerCreateData` → `DockerCreateData`
+- `ContainerStopData` → `DockerStopData`
+- `ContainerRemoveData` → `DockerRemoveData`
+- `ContainerListData` → `DockerListData`
+- `ContainerExecData` → `DockerExecData`
+- `ContainerPullData` → `DockerPullData`
+
+**Step 3:** Rename the job client file:
+
+```bash
+git mv internal/job/client/modify_container.go \
+ internal/job/client/modify_docker.go
+git mv internal/job/client/modify_container_public_test.go \
+ internal/job/client/modify_docker_public_test.go
+```
+
+**Step 4:** Update function names in the renamed files (e.g., `ModifyContainer*`
+→ `ModifyDocker*` or whatever the current pattern is).
+
+**Step 5:** Search for all remaining references to old constant/type names:
+
+```bash
+grep -rn 'OperationContainer\|ContainerCreateData\|ContainerStopData\|ContainerRemoveData\|ContainerListData\|ContainerExecData\|ContainerPullData' \
+ --include='*.go' . | grep -v '.gen.go'
+```
+
+Fix all references found.
+
+**Step 6:** Verify it compiles:
+
+```bash
+go build ./internal/job/...
+```
+
+**Step 7:** Run tests:
+
+```bash
+go test ./internal/job/... -count=1
+```
+
+**Step 8:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container job types to docker"
+```
+
+---
+
+## Chunk 4: Agent Layer
+
+### Task 5: Rename Agent Processor and Wiring
+
+**Files:**
+
+- Rename: `internal/agent/processor_container.go` →
+ `internal/agent/processor_docker.go`
+- Rename: `internal/agent/processor_container_test.go` →
+ `internal/agent/processor_docker_test.go`
+- Modify: `internal/agent/types.go`
+- Modify: `internal/agent/agent.go`
+- Modify: `internal/agent/factory.go`
+- Modify: `internal/agent/processor.go`
+- Modify: `internal/agent/factory_test.go`
+- Modify: `internal/agent/factory_public_test.go`
+
+**Step 1:** Rename processor files:
+
+```bash
+git mv internal/agent/processor_container.go \
+ internal/agent/processor_docker.go
+git mv internal/agent/processor_container_test.go \
+ internal/agent/processor_docker_test.go
+```
+
+**Step 2:** In `processor_docker.go`:
+
+- Rename `processContainerOperation` → `processDockerOperation`
+- Rename `processContainerCreate` → `processDockerCreate` (and all 8 process
+ methods)
+- Change `a.containerProvider` → `a.dockerProvider`
+- Update import from `internal/provider/container` to `internal/provider/docker`
+
+**Step 3:** In `processor.go`:
+
+- Change `case "container":` → `case "docker":`
+- Change `a.processContainerOperation` → `a.processDockerOperation`
+
+**Step 4:** In `types.go`:
+
+- Change `containerProvider containerProv.Provider` →
+ `dockerProvider dockerProv.Provider`
+- Update the import alias from `containerProv` to `dockerProv`
+
+**Step 5:** In `agent.go`:
+
+- Update parameter name from `containerProvider` to `dockerProvider`
+- Update field assignment
+
+**Step 6:** In `factory.go`:
+
+- Rename `containerProvider` variable to `dockerProvider`
+- Update import from `internal/provider/container` to `internal/provider/docker`
+- Update the return value
+
+**Step 7:** In `factory_test.go` and `factory_public_test.go`:
+
+- Update variable names and comments
+
+**Step 8:** In `processor_docker_test.go`:
+
+- Update all function names and references
+
+**Step 9:** Verify it compiles:
+
+```bash
+go build ./internal/agent/...
+```
+
+**Step 10:** Run tests:
+
+```bash
+go test ./internal/agent/... -count=1
+```
+
+**Step 11:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container agent wiring to docker"
+```
+
+---
+
+## Chunk 5: API Handlers
+
+### Task 6: Rename API Handler Files and Wiring
+
+**Files:**
+
+- Modify: all files in `internal/api/docker/` (already moved in Task 1)
+- Rename: `internal/api/handler_container.go` → `internal/api/handler_docker.go`
+- Modify: `internal/api/handler.go`
+- Modify: `internal/api/types.go`
+- Modify: `internal/api/handler_public_test.go`
+- Modify: `cmd/api_helpers.go`
+
+**Step 1:** In `internal/api/docker/`:
+
+- Rename all files: `container_create.go` → `docker_create.go`, etc. (8 handler
+ files + 8 test files)
+- Update package declaration from `package container` to `package docker`
+- Rename the `Container` struct to `Docker`
+- Update `New()` to return `*Docker`
+- Rename handler methods (e.g., `PostNodeContainer` → `PostNodeContainerDocker`)
+- Update all gen import aliases from `containerGen` to `dockerGen`
+- Update compile-time interface check
+- Update references to old job operation constants
+- Update references to old data types
+
+**Step 2:** Rename and update `internal/api/docker/types.go`:
+
+- Rename the struct and any interfaces
+
+**Step 3:** Rename and update `internal/api/docker/convert.go`:
+
+- Update function names and types
+
+**Step 4:** Rename and update `internal/api/docker/validate.go`:
+
+- Update function names
+
+**Step 5:** Rename server wiring:
+
+```bash
+git mv internal/api/handler_container.go internal/api/handler_docker.go
+```
+
+**Step 6:** In `handler_docker.go`:
+
+- Rename `GetContainerHandler` → `GetDockerHandler`
+- Update imports from `internal/api/container` to `internal/api/docker`
+- Update scope references from `container:*` to `docker:*`
+
+**Step 7:** In `types.go`, rename the handler field and option function.
+
+**Step 8:** In `handler.go`, update the `RegisterHandlers` call.
+
+**Step 9:** In `handler_public_test.go`, rename `TestGetContainerHandler` →
+`TestGetDockerHandler`.
+
+**Step 10:** In `cmd/api_helpers.go`, update `GetContainerHandler` →
+`GetDockerHandler`.
+
+**Step 11:** Regenerate the combined spec and SDK client:
+
+```bash
+just generate
+go generate ./pkg/sdk/client/gen/...
+```
+
+**Step 12:** Verify it compiles:
+
+```bash
+go build ./...
+```
+
+**Step 13:** Run tests:
+
+```bash
+go test ./internal/api/docker/... ./internal/api/... -count=1
+```
+
+**Step 14:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container API handlers to docker"
+```
+
+---
+
+## Chunk 6: CLI
+
+### Task 7: Restructure CLI Commands
+
+**Files:**
+
+- Modify: `cmd/client_container.go` (becomes parent with just ``
+ grouping)
+- Create: `cmd/client_container_docker.go` (new `docker` subcommand)
+- Rename: all `cmd/client_container_*.go` → `cmd/client_container_docker_*.go`
+
+**Step 1:** Update `cmd/client_container.go` to be a thin parent command:
+
+```go
+var clientContainerCmd = &cobra.Command{
+ Use: "container",
+ Short: "Container runtime management",
+ Long: `Manage containers using runtime-specific subcommands.`,
+}
+
+func init() {
+ clientCmd.AddCommand(clientContainerCmd)
+}
+```
+
+**Step 2:** Create `cmd/client_container_docker.go`:
+
+```go
+var clientContainerDockerCmd = &cobra.Command{
+ Use: "docker",
+ Short: "Docker container operations",
+ Long: `Manage Docker containers on target nodes.`,
+}
+
+func init() {
+ clientContainerCmd.AddCommand(clientContainerDockerCmd)
+}
+```
+
+**Step 3:** Rename all subcommand files:
+
+```bash
+git mv cmd/client_container_create.go cmd/client_container_docker_create.go
+git mv cmd/client_container_list.go cmd/client_container_docker_list.go
+git mv cmd/client_container_inspect.go cmd/client_container_docker_inspect.go
+git mv cmd/client_container_start.go cmd/client_container_docker_start.go
+git mv cmd/client_container_stop.go cmd/client_container_docker_stop.go
+git mv cmd/client_container_remove.go cmd/client_container_docker_remove.go
+git mv cmd/client_container_exec.go cmd/client_container_docker_exec.go
+git mv cmd/client_container_pull.go cmd/client_container_docker_pull.go
+```
+
+**Step 4:** In each renamed file:
+
+- Change parent command registration from `clientContainerCmd.AddCommand(...)`
+ to `clientContainerDockerCmd.AddCommand(...)`
+- Rename cobra command variables from `clientContainer*Cmd` to
+ `clientContainerDocker*Cmd`
+- Update SDK client calls from `c.Container.*` to `c.Docker.*`
+- Update generated type references from `gen.Container*` to `gen.Docker*`
+- Update `gen.GetNodeContainerParams*` to `gen.GetNodeDockerParams*` (or
+ whatever the regenerated names are)
+
+**Step 5:** Verify the CLI compiles:
+
+```bash
+go build ./cmd/...
+```
+
+**Step 6:** Verify the command tree looks right:
+
+```bash
+go run main.go client container --help
+go run main.go client container docker --help
+```
+
+**Step 7:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: nest docker CLI under client container docker"
+```
+
+---
+
+## Chunk 7: SDK Client
+
+### Task 8: Rename SDK Client Service
+
+**Files:**
+
+- Rename: `pkg/sdk/client/container.go` → `pkg/sdk/client/docker.go`
+- Rename: `pkg/sdk/client/container_types.go` → `pkg/sdk/client/docker_types.go`
+- Rename: `pkg/sdk/client/container_public_test.go` →
+ `pkg/sdk/client/docker_public_test.go`
+- Rename: `pkg/sdk/client/container_types_test.go` →
+ `pkg/sdk/client/docker_types_test.go`
+- Modify: `pkg/sdk/client/osapi.go`
+
+**Step 1:** Rename files:
+
+```bash
+git mv pkg/sdk/client/container.go pkg/sdk/client/docker.go
+git mv pkg/sdk/client/container_types.go pkg/sdk/client/docker_types.go
+git mv pkg/sdk/client/container_public_test.go \
+ pkg/sdk/client/docker_public_test.go
+git mv pkg/sdk/client/container_types_test.go \
+ pkg/sdk/client/docker_types_test.go
+```
+
+**Step 2:** In `docker.go`:
+
+- Rename `ContainerService` → `DockerService`
+- Update all method bodies to use the regenerated `gen.Docker*` type names
+- Update error message prefixes
+
+**Step 3:** In `docker_types.go`:
+
+- Rename all types: `ContainerResult` → `DockerResult`, `ContainerListResult` →
+ `DockerListResult`, etc.
+- Rename all converter functions: `containerResultCollectionFromGen` →
+ `dockerResultCollectionFromGen`, etc.
+
+**Step 4:** In `osapi.go`:
+
+- Change field `Container *ContainerService` → `Docker *DockerService`
+- Update initialization: `c.Container = &ContainerService{...}` →
+ `c.Docker = &DockerService{...}`
+- Update comment
+
+**Step 5:** In test files, update all type and method references.
+
+**Step 6:** Search for remaining `Container` references in the SDK:
+
+```bash
+grep -rn 'Container' pkg/sdk/client/ --include='*.go' | grep -v '.gen.go'
+```
+
+Fix all remaining references.
+
+**Step 7:** Verify it compiles:
+
+```bash
+go build ./pkg/sdk/client/...
+```
+
+**Step 8:** Run tests:
+
+```bash
+go test ./pkg/sdk/client/... -count=1
+```
+
+**Step 9:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container SDK client to docker"
+```
+
+---
+
+## Chunk 8: Orchestrator DSL Helpers
+
+### Task 9: Add Orchestrator Docker Methods
+
+**Files:**
+
+- Create: `pkg/sdk/orchestrator/docker.go`
+- Create: `pkg/sdk/orchestrator/docker_public_test.go`
+
+**Step 1:** Write the test file `docker_public_test.go` with a test suite
+covering each helper method. Use table-driven tests. Mock the client responses
+or test that the correct TaskFunc is created:
+
+```go
+func (s *DockerPublicTestSuite) TestDockerPull() {
+ tests := []struct {
+ name string
+ target string
+ image string
+ validateFunc func(task *orchestrator.Task)
+ }{
+ {
+ name: "creates task with correct name",
+ target: "_any",
+ image: "ubuntu:24.04",
+ validateFunc: func(task *orchestrator.Task) {
+ s.Equal("pull-image", task.Name())
+ },
+ },
+ }
+ // ...
+}
+```
+
+Test each method: `DockerPull`, `DockerCreate`, `DockerExec`, `DockerInspect`,
+`DockerStart`, `DockerStop`, `DockerRemove`, `DockerList`.
+
+**Step 2:** Run tests to verify they fail:
+
+```bash
+go test ./pkg/sdk/orchestrator/... -count=1 -run TestDocker
+```
+
+**Step 3:** Implement `docker.go` with methods on `*Plan`:
+
+```go
+// DockerPull creates a task that pulls a Docker image on the target host.
+func (p *Plan) DockerPull(
+ name string,
+ target string,
+ image string,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Pull(ctx, target, gen.DockerPullRequest{
+ Image: image,
+ })
+ if err != nil {
+ return nil, err
+ }
+ r := resp.Data.Results[0]
+ return &Result{
+ Changed: true,
+ Data: map[string]any{
+ "image_id": r.ImageID,
+ "tag": r.Tag,
+ "size": r.Size,
+ },
+ }, nil
+ })
+}
+```
+
+Follow the same pattern for all 8 operations. Each method:
+
+- Takes the task name, target, and operation-specific params
+- Returns `*Task` for chaining
+- Wraps the SDK client call in a `TaskFunc`
+- Sets `Changed: true` for mutations, `Changed: false` for reads (inspect, list)
+- Populates `Data` with relevant result fields
+
+Methods to implement:
+
+- `DockerPull(name, target, image string) *Task`
+- `DockerCreate(name, target string, body gen.DockerCreateRequest) *Task`
+- `DockerStart(name, target, id string) *Task`
+- `DockerStop(name, target, id string, body gen.DockerStopRequest) *Task`
+- `DockerRemove(name, target, id string, params *gen.DeleteNodeContainerDockerByIDParams) *Task`
+- `DockerExec(name, target, id string, body gen.DockerExecRequest) *Task`
+- `DockerInspect(name, target, id string) *Task`
+- `DockerList(name, target string, params *gen.GetNodeContainerDockerParams) *Task`
+
+**Step 4:** Run tests to verify they pass:
+
+```bash
+go test ./pkg/sdk/orchestrator/... -count=1
+```
+
+**Step 5:** Commit:
+
+```bash
+git add -A && git commit -m "feat: add orchestrator Docker DSL helpers"
+```
+
+---
+
+### Task 10: Rewrite Container Targeting Example
+
+**Files:**
+
+- Modify: `examples/sdk/orchestrator/features/container-targeting.go`
+
+**Step 1:** Rewrite the example to use the new DSL helpers:
+
+```go
+plan := orchestrator.NewPlan(apiClient,
+ orchestrator.WithHooks(hooks),
+ orchestrator.OnError(orchestrator.Continue),
+)
+
+pull := plan.DockerPull("pull-image", target, containerImage)
+
+create := plan.DockerCreate("create-container", target,
+ gen.DockerCreateRequest{
+ Image: containerImage,
+ Name: ptr(containerName),
+ AutoStart: &autoStart,
+ Command: &[]string{"sleep", "600"},
+ },
+)
+create.DependsOn(pull)
+
+plan.DockerExec("exec-hostname", target, containerName,
+ gen.DockerExecRequest{Command: []string{"hostname"}},
+).DependsOn(create)
+
+plan.DockerInspect("inspect", target, containerName).DependsOn(create)
+
+plan.DockerRemove("cleanup", target, containerName,
+ &gen.DeleteNodeContainerDockerByIDParams{Force: &force},
+).DependsOn(create)
+```
+
+**Step 2:** Update SDK client example too: `examples/sdk/client/container.go` —
+update to use `c.Docker.*` and `gen.Docker*` types.
+
+**Step 3:** Verify examples compile:
+
+```bash
+go build ./examples/...
+```
+
+**Step 4:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: update examples to use docker DSL"
+```
+
+---
+
+## Chunk 9: Integration Tests
+
+### Task 11: Rename Integration Tests
+
+**Files:**
+
+- Rename: `test/integration/container_test.go` →
+ `test/integration/docker_test.go`
+
+**Step 1:** Rename the file:
+
+```bash
+git mv test/integration/container_test.go test/integration/docker_test.go
+```
+
+**Step 2:** Update the test to:
+
+- Use `c.Docker.*` instead of `c.Container.*`
+- Use `gen.Docker*` types instead of `gen.Container*`
+- Update CLI commands from `container list` to `container docker list`
+- Rename suite/test names from `Container*` to `Docker*`
+
+**Step 3:** Verify it compiles:
+
+```bash
+go build ./test/integration/...
+```
+
+**Step 4:** Commit:
+
+```bash
+git add -A && git commit -m "refactor: rename container integration tests to docker"
+```
+
+---
+
+## Chunk 10: Documentation
+
+### Task 12: Update Documentation
+
+**Files:**
+
+- Modify: `docs/docs/sidebar/features/container-management.md` — update to
+ describe Docker as first runtime, update all paths/permissions/CLI examples
+- Rename: CLI docs from `docs/.../container/` to restructure under
+ `docs/.../container/docker/`
+- Modify: SDK orchestrator docs to reference Docker methods
+- Modify: `docs/docs/sidebar/usage/configuration.md` — update permission tables
+- Modify: `docs/docs/sidebar/architecture/system-architecture.md` — update
+ endpoint tables
+- Modify: `docs/docusaurus.config.ts` — update navbar links
+- Modify: `CLAUDE.md` — update permission tables in role descriptions
+
+**Step 1:** Update `container-management.md`:
+
+- Update title, description
+- Update all path examples from `/container` to `/container/docker`
+- Update permissions table from `container:*` to `docker:*`
+- Update CLI examples from `client container list` to
+ `client container docker list`
+- Update role descriptions
+
+**Step 2:** Restructure CLI docs:
+
+- Current: `docs/.../cli/client/container/container.mdx` (parent)
+- New: `docs/.../cli/client/container/container.mdx` stays as parent grouping
+- Create: `docs/.../cli/client/container/docker/` directory
+- Move per-operation docs into the docker subdirectory
+- Update all command examples
+
+**Step 3:** Update SDK orchestrator operation docs:
+
+- Rename `container-create.md` → `docker-create.md`, etc.
+- Update code examples to use `plan.DockerCreate(...)` etc.
+
+**Step 4:** Update configuration.md permission tables.
+
+**Step 5:** Update system-architecture.md endpoint tables.
+
+**Step 6:** Regenerate API docs:
+
+```bash
+just docs::generate-api
+```
+
+**Step 7:** Commit:
+
+```bash
+git add -A && git commit -m "docs: update documentation for docker domain rename"
+```
+
+---
+
+## Chunk 11: Verify
+
+### Task 13: Full Verification
+
+**Step 1:** Regenerate everything:
+
+```bash
+just generate
+```
+
+**Step 2:** Build:
+
+```bash
+go build ./...
+```
+
+**Step 3:** Run all unit tests:
+
+```bash
+just go::unit
+```
+
+**Step 4:** Run lint:
+
+```bash
+just go::vet
+```
+
+**Step 5:** Search for any remaining `container` references that should be
+`docker` (excluding the `container` parent command which is intentional):
+
+```bash
+grep -rn 'container:read\|container:write\|container:execute' \
+ --include='*.go' . | grep -v '.gen.go'
+grep -rn 'ContainerService\|ContainerResult\|ContainerCreateData' \
+ --include='*.go' . | grep -v '.gen.go'
+grep -rn 'OperationContainer' --include='*.go' .
+grep -rn 'containerProvider' --include='*.go' .
+grep -rn 'processContainer' --include='*.go' .
+```
+
+All should return empty.
+
+**Step 6:** Verify CLI works:
+
+```bash
+go run main.go client container --help
+go run main.go client container docker --help
+```
+
+**Step 7:** Commit any final fixes:
+
+```bash
+git add -A && git commit -m "chore: final verification cleanup"
+```
+
+---
+
+## Files Modified
+
+| Repo | File | Change |
+| ----- | --------------------------------------------------------------- | -------------------------------------- |
+| osapi | `internal/api/container/` → `internal/api/docker/` | Full directory rename + content update |
+| osapi | `internal/api/handler_container.go` → `handler_docker.go` | Rename + update |
+| osapi | `internal/api/handler.go` | Update registration |
+| osapi | `internal/api/types.go` | Rename handler field |
+| osapi | `internal/api/handler_public_test.go` | Rename test |
+| osapi | `internal/provider/container/` → `internal/provider/docker/` | Full directory rename |
+| osapi | `internal/provider/container/runtime/driver.go` | DELETE |
+| osapi | `internal/agent/processor_container.go` → `processor_docker.go` | Rename + update |
+| osapi | `internal/agent/types.go` | Rename field |
+| osapi | `internal/agent/agent.go` | Rename parameter |
+| osapi | `internal/agent/factory.go` | Rename variable |
+| osapi | `internal/agent/processor.go` | Update case |
+| osapi | `internal/job/types.go` | Rename 8 constants + 6 types |
+| osapi | `internal/job/client/modify_container.go` → `modify_docker.go` | Rename + update |
+| osapi | `internal/authtoken/permissions.go` | Rename 3 constants |
+| osapi | `cmd/client_container.go` | Simplify to parent |
+| osapi | `cmd/client_container_docker.go` | NEW parent for docker |
+| osapi | `cmd/client_container_*.go` → `client_container_docker_*.go` | Rename 8 files |
+| osapi | `cmd/api_helpers.go` | Update handler call |
+| osapi | `pkg/sdk/client/container.go` → `docker.go` | Rename + update |
+| osapi | `pkg/sdk/client/container_types.go` → `docker_types.go` | Rename + update |
+| osapi | `pkg/sdk/client/osapi.go` | Rename field |
+| osapi | `pkg/sdk/orchestrator/docker.go` | NEW — DSL helpers |
+| osapi | `pkg/sdk/orchestrator/docker_public_test.go` | NEW — tests |
+| osapi | `examples/sdk/orchestrator/features/container-targeting.go` | Rewrite with DSL |
+| osapi | `examples/sdk/client/container.go` | Update SDK calls |
+| osapi | `test/integration/container_test.go` → `docker_test.go` | Rename + update |
+| osapi | `docs/` (multiple) | Update paths, permissions, examples |
diff --git a/examples/sdk/client/container.go b/examples/sdk/client/container.go
index 67091f18..dbaa2cb8 100644
--- a/examples/sdk/client/container.go
+++ b/examples/sdk/client/container.go
@@ -50,7 +50,7 @@ func main() {
target := "_any"
// Pull an image.
- pull, err := c.Container.Pull(ctx, target, gen.ContainerPullRequest{
+ pull, err := c.Docker.Pull(ctx, target, gen.DockerPullRequest{
Image: "nginx:alpine",
})
if err != nil {
@@ -65,7 +65,7 @@ func main() {
// Create a container.
name := "osapi-example"
autoStart := true
- create, err := c.Container.Create(ctx, target, gen.ContainerCreateRequest{
+ create, err := c.Docker.Create(ctx, target, gen.DockerCreateRequest{
Image: "nginx:alpine",
Name: &name,
AutoStart: &autoStart,
@@ -83,7 +83,7 @@ func main() {
// List running containers.
state := gen.Running
- list, err := c.Container.List(ctx, target, &gen.GetNodeContainerParams{
+ list, err := c.Docker.List(ctx, target, &gen.GetNodeContainerDockerParams{
State: &state,
})
if err != nil {
@@ -98,7 +98,7 @@ func main() {
}
// Inspect the container.
- inspect, err := c.Container.Inspect(ctx, target, containerID)
+ inspect, err := c.Docker.Inspect(ctx, target, containerID)
if err != nil {
log.Fatalf("inspect: %v", err)
}
@@ -109,7 +109,7 @@ func main() {
}
// Exec a command inside the container.
- exec, err := c.Container.Exec(ctx, target, containerID, gen.ContainerExecRequest{
+ exec, err := c.Docker.Exec(ctx, target, containerID, gen.DockerExecRequest{
Command: []string{"cat", "/etc/hostname"},
})
if err != nil {
@@ -123,7 +123,7 @@ func main() {
// Stop the container.
timeout := 5
- stop, err := c.Container.Stop(ctx, target, containerID, gen.ContainerStopRequest{
+ stop, err := c.Docker.Stop(ctx, target, containerID, gen.DockerStopRequest{
Timeout: &timeout,
})
if err != nil {
@@ -137,9 +137,14 @@ func main() {
// Remove the container.
force := true
- remove, err := c.Container.Remove(ctx, target, containerID, &gen.DeleteNodeContainerByIdParams{
- Force: &force,
- })
+ remove, err := c.Docker.Remove(
+ ctx,
+ target,
+ containerID,
+ &gen.DeleteNodeContainerDockerByIDParams{
+ Force: &force,
+ },
+ )
if err != nil {
log.Fatalf("remove: %v", err)
}
diff --git a/examples/sdk/orchestrator/features/container-targeting.go b/examples/sdk/orchestrator/features/container-targeting.go
index 1e809c62..745b1f7d 100644
--- a/examples/sdk/orchestrator/features/container-targeting.go
+++ b/examples/sdk/orchestrator/features/container-targeting.go
@@ -18,24 +18,19 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-// Package main demonstrates running provider operations inside Docker
-// containers using the orchestrator SDK's typed ContainerProvider.
-//
-// The example exercises every read-only provider, command execution,
-// error handling for failing commands, and a deliberately failing task
-// to show how the orchestrator reports each status.
+// Package main demonstrates orchestrating Docker container lifecycle
+// operations using the DSL helpers. The plan composes pull, create,
+// exec, inspect, and cleanup as a DAG.
//
// Expected output statuses:
//
-// changed — setup tasks (ensure-clean, pull, create, deploy) and command exec
-// unchanged — all read-only providers (host, mem, load, disk)
-// failed — deliberately-fails task (returns an error)
-// skipped — none (OnError(Continue) lets independent tasks proceed)
+// changed — pull, create, exec, cleanup
+// unchanged — inspect (read-only)
+// failed — deliberately-fails (returns an error)
//
// Prerequisites:
// - A running OSAPI stack (API server + agent + NATS)
// - Docker available on the agent host
-// - Go toolchain (the example builds osapi for linux automatically)
//
// Run with: OSAPI_TOKEN="" go run container-targeting.go
package main
@@ -45,9 +40,6 @@ import (
"fmt"
"log"
"os"
- osexec "os/exec"
- "runtime"
- "strings"
"time"
"github.com/retr0h/osapi/pkg/sdk/client"
@@ -56,7 +48,7 @@ import (
)
const (
- containerName = "example-provider-container"
+ containerName = "example-orchestrator-container"
containerImage = "ubuntu:24.04"
)
@@ -97,401 +89,73 @@ func main() {
},
}
- // WithDockerExecFn bridges the orchestrator's Docker DSL to the
- // OSAPI Container.Exec REST API. Every ExecProvider call flows
- // through: SDK → REST API → NATS → agent → docker exec.
- dockerExecFn := func(
- ctx context.Context,
- containerID string,
- command []string,
- ) (stdout, stderr string, exitCode int, err error) {
- resp, execErr := apiClient.Container.Exec(
- ctx,
- target,
- containerID,
- gen.ContainerExecRequest{Command: command},
- )
- if execErr != nil {
- return "", "", -1, execErr
- }
-
- r := resp.Data.Results[0]
-
- return r.Stdout, r.Stderr, r.ExitCode, nil
- }
-
plan := orchestrator.NewPlan(apiClient,
orchestrator.WithHooks(hooks),
- orchestrator.WithDockerExecFn(dockerExecFn),
orchestrator.OnError(orchestrator.Continue),
)
- // ── Setup: pull + create + deploy osapi ──────────────────────
-
- pull := plan.TaskFunc(
- "pull-image",
- func(
- ctx context.Context,
- c *client.Client,
- ) (*orchestrator.Result, error) {
- resp, err := c.Container.Pull(ctx, target, gen.ContainerPullRequest{
- Image: containerImage,
- })
- if err != nil {
- return nil, fmt.Errorf("pull: %w", err)
- }
-
- r := resp.Data.Results[0]
-
- return &orchestrator.Result{
- Changed: true,
- Data: map[string]any{"image_id": r.ImageID},
- }, nil
- },
- )
+ // ── Pre-cleanup: remove leftover container from previous run ─
+ // Swallow errors — the container may not exist.
- autoStart := true
- create := plan.TaskFunc(
- "create-container",
+ force := true
+ preCleanup := plan.TaskFunc("pre-cleanup",
func(
ctx context.Context,
c *client.Client,
) (*orchestrator.Result, error) {
- resp, err := c.Container.Create(ctx, target, gen.ContainerCreateRequest{
- Image: containerImage,
- Name: ptr(containerName),
- AutoStart: &autoStart,
- Command: &[]string{"sleep", "600"},
- })
- if err != nil {
- // Container already exists — carry on.
- return &orchestrator.Result{}, nil
- }
-
- r := resp.Data.Results[0]
-
- return &orchestrator.Result{
- Changed: true,
- Data: map[string]any{"id": r.ID, "name": r.Name},
- }, nil
- },
- )
- create.DependsOn(pull)
-
- // Build osapi for linux and docker cp it into the container.
- // In production you would bake the binary into the image.
- deploy := plan.TaskFunc(
- "deploy-osapi",
- func(
- _ context.Context,
- _ *client.Client,
- ) (*orchestrator.Result, error) {
- tmpBin := "/tmp/osapi-container"
-
- build := osexec.Command(
- "go", "build", "-o", tmpBin, "github.com/retr0h/osapi",
+ _, _ = c.Docker.Remove(ctx, target, containerName,
+ &gen.DeleteNodeContainerDockerByIDParams{Force: &force},
)
- build.Dir = findProjectRoot()
- build.Env = append(os.Environ(), "GOOS=linux", "GOARCH="+runtime.GOARCH)
- if out, err := build.CombinedOutput(); err != nil {
- return nil, fmt.Errorf("build osapi: %s: %w", string(out), err)
- }
-
- cp := osexec.Command("docker", "cp", tmpBin, containerName+":/osapi")
- if out, err := cp.CombinedOutput(); err != nil {
- return nil, fmt.Errorf("docker cp: %s: %w", string(out), err)
- }
-
- _ = os.Remove(tmpBin)
-
- return &orchestrator.Result{Changed: true}, nil
- },
- )
- deploy.DependsOn(create)
-
- // ── Provider: typed ContainerProvider bound to the target ──────
-
- dockerTarget := plan.Docker(containerName, containerImage)
- provider := orchestrator.NewContainerProvider(dockerTarget)
- scoped := plan.In(dockerTarget)
-
- // ── Host provider: 9 read-only operations (unchanged) ─────────
-
- getHostname := scoped.TaskFunc(
- "host/get-hostname",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetHostname(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" hostname = %s\n", v)
-
- return &orchestrator.Result{Data: map[string]any{"hostname": v}}, nil
- },
- )
- getHostname.DependsOn(deploy)
-
- getOSInfo := scoped.TaskFunc(
- "host/get-os-info",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- info, err := provider.GetOSInfo(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" os = %s %s\n", info.Distribution, info.Version)
-
- return &orchestrator.Result{
- Changed: info.Changed,
- Data: map[string]any{
- "distribution": info.Distribution,
- "version": info.Version,
- },
- }, nil
- },
- )
- getOSInfo.DependsOn(deploy)
-
- getArch := scoped.TaskFunc(
- "host/get-architecture",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetArchitecture(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" architecture = %s\n", v)
-
- return &orchestrator.Result{Data: map[string]any{"architecture": v}}, nil
- },
- )
- getArch.DependsOn(deploy)
-
- getKernel := scoped.TaskFunc(
- "host/get-kernel-version",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetKernelVersion(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" kernel = %s\n", v)
-
- return &orchestrator.Result{Data: map[string]any{"kernel": v}}, nil
- },
- )
- getKernel.DependsOn(deploy)
-
- getUptime := scoped.TaskFunc(
- "host/get-uptime",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetUptime(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" uptime = %s\n", v)
- return &orchestrator.Result{Data: map[string]any{"uptime": v.String()}}, nil
+ return &orchestrator.Result{Changed: false}, nil
},
)
- getUptime.DependsOn(deploy)
-
- getFQDN := scoped.TaskFunc(
- "host/get-fqdn",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetFQDN(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" fqdn = %s\n", v)
- return &orchestrator.Result{Data: map[string]any{"fqdn": v}}, nil
- },
- )
- getFQDN.DependsOn(deploy)
-
- getCPUCount := scoped.TaskFunc(
- "host/get-cpu-count",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetCPUCount(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" cpu_count = %d\n", v)
+ // ── Pull image ───────────────────────────────────────────────
- return &orchestrator.Result{Data: map[string]any{"cpu_count": v}}, nil
- },
- )
- getCPUCount.DependsOn(deploy)
-
- getSvcMgr := scoped.TaskFunc(
- "host/get-service-manager",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetServiceManager(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" service_mgr = %s\n", v)
+ pull := plan.DockerPull("pull-image", target, containerImage)
+ pull.DependsOn(preCleanup)
- return &orchestrator.Result{Data: map[string]any{"service_manager": v}}, nil
- },
- )
- getSvcMgr.DependsOn(deploy)
-
- getPkgMgr := scoped.TaskFunc(
- "host/get-package-manager",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- v, err := provider.GetPackageManager(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" package_mgr = %s\n", v)
+ // ── Create container ─────────────────────────────────────────
- return &orchestrator.Result{Data: map[string]any{"package_manager": v}}, nil
+ autoStart := true
+ create := plan.DockerCreate("create-container", target,
+ gen.DockerCreateRequest{
+ Image: containerImage,
+ Name: ptr(containerName),
+ AutoStart: &autoStart,
+ Command: &[]string{"sleep", "600"},
},
)
- getPkgMgr.DependsOn(deploy)
+ create.DependsOn(pull)
- // ── Memory, load, disk providers (unchanged) ──────────────────
+ // ── Exec: run commands inside the container ──────────────────
- getMemStats := scoped.TaskFunc(
- "mem/get-stats",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- stats, err := provider.GetMemStats(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" mem_total = %d MB\n", stats.Total/1024/1024)
- fmt.Printf(" mem_available = %d MB\n", stats.Available/1024/1024)
-
- return &orchestrator.Result{
- Changed: stats.Changed,
- Data: map[string]any{
- "total": stats.Total,
- "available": stats.Available,
- },
- }, nil
- },
+ execHostname := plan.DockerExec("exec-hostname", target, containerName,
+ gen.DockerExecRequest{Command: []string{"hostname"}},
)
- getMemStats.DependsOn(deploy)
-
- getLoadStats := scoped.TaskFunc(
- "load/get-average-stats",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- stats, err := provider.GetLoadStats(ctx)
- if err != nil {
- return nil, err
- }
- fmt.Printf(" load1 = %.2f\n", stats.Load1)
- fmt.Printf(" load5 = %.2f\n", stats.Load5)
- fmt.Printf(" load15 = %.2f\n", stats.Load15)
-
- return &orchestrator.Result{
- Changed: stats.Changed,
- Data: map[string]any{
- "load1": stats.Load1, "load5": stats.Load5, "load15": stats.Load15,
- },
- }, nil
- },
- )
- getLoadStats.DependsOn(deploy)
-
- getDiskUsage := scoped.TaskFunc(
- "disk/get-usage",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- disks, err := provider.GetDiskUsage(ctx)
- if err != nil {
- return nil, err
- }
- for _, d := range disks {
- fmt.Printf(" disk %-8s total=%d MB used=%d MB\n",
- d.Name, d.Total/1024/1024, d.Used/1024/1024)
- }
+ execHostname.DependsOn(create)
- return &orchestrator.Result{Data: map[string]any{"mounts": len(disks)}}, nil
- },
+ execUname := plan.DockerExec("exec-uname", target, containerName,
+ gen.DockerExecRequest{Command: []string{"uname", "-a"}},
)
- getDiskUsage.DependsOn(deploy)
-
- // ── Command provider: exec + shell (changed) ──────────────────
-
- execUname := scoped.TaskFunc(
- "command/exec-uname",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- r, err := provider.Exec(ctx, orchestrator.ExecParams{
- Command: "uname",
- Args: []string{"-a"},
- })
- if err != nil {
- return nil, err
- }
- fmt.Printf(" uname -a = %s", r.Stdout)
+ execUname.DependsOn(create)
- return &orchestrator.Result{
- Changed: r.Changed,
- Data: map[string]any{"exit_code": r.ExitCode},
- }, nil
+ execOS := plan.DockerExec("exec-os-release", target, containerName,
+ gen.DockerExecRequest{
+ Command: []string{"sh", "-c", "head -2 /etc/os-release"},
},
)
- execUname.DependsOn(deploy)
-
- // Reads /etc/os-release inside the container to prove we are
- // running inside Ubuntu 24.04, not the host OS.
- shellOSRelease := scoped.TaskFunc(
- "command/shell-os-release",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- r, err := provider.Shell(ctx, orchestrator.ShellParams{
- Command: "head -2 /etc/os-release && echo container-hostname=$(hostname)",
- })
- if err != nil {
- return nil, err
- }
- fmt.Printf(" os-release =\n%s", r.Stdout)
+ execOS.DependsOn(create)
- return &orchestrator.Result{
- Changed: r.Changed,
- Data: map[string]any{"exit_code": r.ExitCode},
- }, nil
- },
- )
- shellOSRelease.DependsOn(deploy)
+ // ── Inspect: read-only, reports unchanged ────────────────────
- // ── Command that exits non-zero: handled gracefully ───────────
- //
- // The command provider returns the exit code in the result.
- // The task inspects it and reports unchanged (no system mutation)
- // rather than failing the task.
-
- execFails := scoped.TaskFunc(
- "command/exec-nonzero",
- func(ctx context.Context, _ *client.Client) (*orchestrator.Result, error) {
- r, err := provider.Exec(ctx, orchestrator.ExecParams{
- Command: "ls",
- Args: []string{"/does-not-exist"},
- })
- if err != nil {
- return nil, err
- }
+ inspect := plan.DockerInspect("inspect-container", target, containerName)
+ inspect.DependsOn(create)
- fmt.Printf(" exit_code = %d\n", r.ExitCode)
- fmt.Printf(" stderr = %s", r.Stderr)
-
- return &orchestrator.Result{
- Changed: r.Changed,
- Data: map[string]any{
- "exit_code": r.ExitCode,
- "stderr": r.Stderr,
- },
- }, nil
- },
- )
- execFails.DependsOn(deploy)
-
- // ── Deliberately failing task: shows StatusFailed ──────────────
- //
- // Returning an error from the task function marks it as failed.
- // With OnError(Continue), independent tasks keep running but
- // any task that DependsOn this one would be skipped.
+ // ── Deliberately failing task: shows StatusFailed ─────────────
- deliberatelyFails := scoped.TaskFunc(
- "deliberately-fails",
+ deliberatelyFails := plan.TaskFunc("deliberately-fails",
func(
_ context.Context,
_ *client.Client,
@@ -499,47 +163,18 @@ func main() {
return nil, fmt.Errorf("this task always fails to demonstrate error reporting")
},
)
- deliberatelyFails.DependsOn(deploy)
+ deliberatelyFails.DependsOn(create)
- // ── Cleanup ───────────────────────────────────────────────────
- //
- // Depends on all provider tasks EXCEPT deliberately-fails so
- // that cleanup is not skipped when OnError(Continue) is active.
+ // ── Cleanup ──────────────────────────────────────────────────
+ // Depends on all tasks that use the container so it runs last.
- cleanup := plan.TaskFunc(
- "cleanup",
- func(
- ctx context.Context,
- c *client.Client,
- ) (*orchestrator.Result, error) {
- force := true
- _, err := c.Container.Remove(
- ctx,
- target,
- containerName,
- &gen.DeleteNodeContainerByIDParams{Force: &force},
- )
- if err != nil {
- return nil, fmt.Errorf("remove: %w", err)
- }
-
- return &orchestrator.Result{Changed: true}, nil
- },
- )
- cleanup.DependsOn(
- getHostname, getOSInfo, getArch, getKernel, getUptime,
- getFQDN, getCPUCount, getSvcMgr, getPkgMgr,
- getMemStats, getLoadStats, getDiskUsage,
- execUname, shellOSRelease, execFails,
- )
-
- // Suppress unused variable warning — deliberately-fails has no
- // dependents by design.
- _ = deliberatelyFails
+ plan.DockerRemove("cleanup", target, containerName,
+ &gen.DeleteNodeContainerDockerByIDParams{Force: &force},
+ ).DependsOn(execHostname, execUname, execOS, inspect)
- // ── Run ───────────────────────────────────────────────────────
+ // ── Run ──────────────────────────────────────────────────────
- fmt.Println("=== Container Provider Example ===")
+ fmt.Println("=== Docker Orchestration Example ===")
fmt.Println()
report, err := plan.Run(context.Background())
@@ -553,21 +188,3 @@ func main() {
report.Duration.Truncate(time.Millisecond),
)
}
-
-// findProjectRoot walks up from the current directory to find go.mod.
-func findProjectRoot() string {
- dir, _ := os.Getwd()
-
- for {
- if _, err := os.Stat(dir + "/go.mod"); err == nil {
- return dir
- }
-
- idx := strings.LastIndex(dir, "/")
- if idx <= 0 {
- return "."
- }
-
- dir = dir[:idx]
- }
-}
diff --git a/internal/agent/agent.go b/internal/agent/agent.go
index cec8d9e8..28594c96 100644
--- a/internal/agent/agent.go
+++ b/internal/agent/agent.go
@@ -30,7 +30,7 @@ import (
"github.com/retr0h/osapi/internal/job/client"
"github.com/retr0h/osapi/internal/provider"
"github.com/retr0h/osapi/internal/provider/command"
- containerProv "github.com/retr0h/osapi/internal/provider/container"
+ dockerProv "github.com/retr0h/osapi/internal/provider/docker"
fileProv "github.com/retr0h/osapi/internal/provider/file"
"github.com/retr0h/osapi/internal/provider/network/dns"
"github.com/retr0h/osapi/internal/provider/network/netinfo"
@@ -57,28 +57,28 @@ func New(
netinfoProvider netinfo.Provider,
commandProvider command.Provider,
fileProvider fileProv.Provider,
- containerProvider containerProv.Provider,
+ dockerProvider dockerProv.Provider,
registryKV jetstream.KeyValue,
factsKV jetstream.KeyValue,
) *Agent {
a := &Agent{
- logger: logger,
- appConfig: appConfig,
- appFs: appFs,
- jobClient: jobClient,
- streamName: streamName,
- hostProvider: hostProvider,
- diskProvider: diskProvider,
- memProvider: memProvider,
- loadProvider: loadProvider,
- dnsProvider: dnsProvider,
- pingProvider: pingProvider,
- netinfoProvider: netinfoProvider,
- commandProvider: commandProvider,
- fileProvider: fileProvider,
- containerProvider: containerProvider,
- registryKV: registryKV,
- factsKV: factsKV,
+ logger: logger,
+ appConfig: appConfig,
+ appFs: appFs,
+ jobClient: jobClient,
+ streamName: streamName,
+ hostProvider: hostProvider,
+ diskProvider: diskProvider,
+ memProvider: memProvider,
+ loadProvider: loadProvider,
+ dnsProvider: dnsProvider,
+ pingProvider: pingProvider,
+ netinfoProvider: netinfoProvider,
+ commandProvider: commandProvider,
+ fileProvider: fileProvider,
+ dockerProvider: dockerProvider,
+ registryKV: registryKV,
+ factsKV: factsKV,
}
// Wire agent facts into all providers so they can access the latest
@@ -94,7 +94,7 @@ func New(
netinfoProvider,
commandProvider,
fileProvider,
- containerProvider,
+ dockerProvider,
)
return a
diff --git a/internal/agent/factory.go b/internal/agent/factory.go
index cf22c687..8c727e46 100644
--- a/internal/agent/factory.go
+++ b/internal/agent/factory.go
@@ -26,8 +26,7 @@ import (
"github.com/retr0h/osapi/internal/exec"
"github.com/retr0h/osapi/internal/provider/command"
- containerProv "github.com/retr0h/osapi/internal/provider/container"
- "github.com/retr0h/osapi/internal/provider/container/runtime/docker"
+ dockerProv "github.com/retr0h/osapi/internal/provider/docker"
"github.com/retr0h/osapi/internal/provider/network/dns"
"github.com/retr0h/osapi/internal/provider/network/netinfo"
"github.com/retr0h/osapi/internal/provider/network/ping"
@@ -38,8 +37,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/platform"
)
-// factoryDockerNewFn is the function used to create a Docker driver (injectable for testing).
-var factoryDockerNewFn = docker.New
+// factoryDockerNewFn is the function used to create a Docker provider (injectable for testing).
+var factoryDockerNewFn = dockerProv.New
// ProviderFactory creates platform-specific providers for the agent.
type ProviderFactory struct {
@@ -65,7 +64,7 @@ func (f *ProviderFactory) CreateProviders() (
ping.Provider,
netinfo.Provider,
command.Provider,
- containerProv.Provider,
+ dockerProv.Provider,
) {
plat := platform.Detect()
@@ -148,20 +147,20 @@ func (f *ProviderFactory) CreateProviders() (
// Create command provider (cross-platform, uses exec.Manager)
commandProvider := command.New(f.logger, execManager)
- // Create container provider (conditional on Docker availability)
- var containerProvider containerProv.Provider
- dockerDriver, err := factoryDockerNewFn()
+ // Create Docker provider (conditional on Docker availability)
+ var dockerProvider dockerProv.Provider
+ dockerClient, err := factoryDockerNewFn()
if err == nil {
- if pingErr := dockerDriver.Ping(context.Background()); pingErr == nil {
- containerProvider = containerProv.New(dockerDriver)
+ if pingErr := dockerClient.Ping(context.Background()); pingErr == nil {
+ dockerProvider = dockerClient
} else {
- f.logger.Info("Docker not available, container operations disabled",
+ f.logger.Info("Docker not available, docker operations disabled",
slog.String("error", pingErr.Error()))
}
} else {
- f.logger.Info("Docker client creation failed, container operations disabled",
+ f.logger.Info("Docker client creation failed, docker operations disabled",
slog.String("error", err.Error()))
}
- return hostProvider, diskProvider, memProvider, loadProvider, dnsProvider, pingProvider, netinfoProvider, commandProvider, containerProvider
+ return hostProvider, diskProvider, memProvider, loadProvider, dnsProvider, pingProvider, netinfoProvider, commandProvider, dockerProvider
}
diff --git a/internal/agent/factory_public_test.go b/internal/agent/factory_public_test.go
index 5ea260ad..a27ae41a 100644
--- a/internal/agent/factory_public_test.go
+++ b/internal/agent/factory_public_test.go
@@ -74,7 +74,7 @@ func (s *FactoryPublicTestSuite) TestCreateProviders() {
s.NotNil(pingProvider)
s.NotNil(netinfoProvider)
s.NotNil(commandProvider)
- // containerProvider can be nil if Docker is not available
+ // dockerProvider can be nil if Docker is not available
})
}
}
diff --git a/internal/agent/factory_test.go b/internal/agent/factory_test.go
index 6655d154..52c62cec 100644
--- a/internal/agent/factory_test.go
+++ b/internal/agent/factory_test.go
@@ -32,7 +32,7 @@ import (
"github.com/shirou/gopsutil/v4/host"
"github.com/stretchr/testify/suite"
- "github.com/retr0h/osapi/internal/provider/container/runtime/docker"
+ dockerProv "github.com/retr0h/osapi/internal/provider/docker"
"github.com/retr0h/osapi/pkg/sdk/platform"
)
@@ -102,7 +102,7 @@ func (s *FactoryTestSuite) TestCreateProviders() {
}
},
setupDocker: func() {
- factoryDockerNewFn = func() (*docker.Driver, error) {
+ factoryDockerNewFn = func() (*dockerProv.Client, error) {
return nil, fmt.Errorf("docker not installed")
}
},
@@ -116,8 +116,8 @@ func (s *FactoryTestSuite) TestCreateProviders() {
}
},
setupDocker: func() {
- factoryDockerNewFn = func() (*docker.Driver, error) {
- return docker.NewWithClient(&testDockerClient{
+ factoryDockerNewFn = func() (*dockerProv.Client, error) {
+ return dockerProv.NewWithClient(&testDockerClient{
pingErr: errors.New("connection refused"),
}), nil
}
@@ -132,8 +132,8 @@ func (s *FactoryTestSuite) TestCreateProviders() {
}
},
setupDocker: func() {
- factoryDockerNewFn = func() (*docker.Driver, error) {
- return docker.NewWithClient(&testDockerClient{}), nil
+ factoryDockerNewFn = func() (*dockerProv.Client, error) {
+ return dockerProv.NewWithClient(&testDockerClient{}), nil
}
},
wantContainer: true,
@@ -155,7 +155,7 @@ func (s *FactoryTestSuite) TestCreateProviders() {
}
factory := NewProviderFactory(slog.Default())
- hostProvider, diskProvider, memProvider, loadProvider, dnsProvider, pingProvider, netinfoProvider, commandProvider, containerProvider := factory.CreateProviders()
+ hostProvider, diskProvider, memProvider, loadProvider, dnsProvider, pingProvider, netinfoProvider, commandProvider, dockerProvider := factory.CreateProviders()
s.NotNil(hostProvider)
s.NotNil(diskProvider)
@@ -167,7 +167,7 @@ func (s *FactoryTestSuite) TestCreateProviders() {
s.NotNil(commandProvider)
if tt.wantContainer {
- s.NotNil(containerProvider)
+ s.NotNil(dockerProvider)
}
})
}
diff --git a/internal/agent/processor.go b/internal/agent/processor.go
index 62a041da..73af45c8 100644
--- a/internal/agent/processor.go
+++ b/internal/agent/processor.go
@@ -54,8 +54,8 @@ func (a *Agent) processJobOperation(
return a.processCommandOperation(jobRequest)
case "file":
return a.processFileOperation(jobRequest)
- case "container":
- return a.processContainerOperation(jobRequest)
+ case "docker":
+ return a.processDockerOperation(jobRequest)
default:
return nil, fmt.Errorf("unsupported job category: %s", jobRequest.Category)
}
diff --git a/internal/agent/processor_container.go b/internal/agent/processor_docker.go
similarity index 65%
rename from internal/agent/processor_container.go
rename to internal/agent/processor_docker.go
index 5fe8c7da..31d9e7ad 100644
--- a/internal/agent/processor_container.go
+++ b/internal/agent/processor_docker.go
@@ -28,15 +28,15 @@ import (
"time"
"github.com/retr0h/osapi/internal/job"
- "github.com/retr0h/osapi/internal/provider/container/runtime"
+ dockerProv "github.com/retr0h/osapi/internal/provider/docker"
)
-// processContainerOperation handles container-related operations.
-func (a *Agent) processContainerOperation(
+// processDockerOperation handles docker-related operations.
+func (a *Agent) processDockerOperation(
jobRequest job.Request,
) (json.RawMessage, error) {
- if a.containerProvider == nil {
- return nil, fmt.Errorf("container runtime not available")
+ if a.dockerProvider == nil {
+ return nil, fmt.Errorf("docker runtime not available")
}
ctx := context.Background()
@@ -46,48 +46,48 @@ func (a *Agent) processContainerOperation(
switch baseOperation {
case "create":
- return a.processContainerCreate(ctx, jobRequest)
+ return a.processDockerCreate(ctx, jobRequest)
case "start":
- return a.processContainerStart(ctx, jobRequest)
+ return a.processDockerStart(ctx, jobRequest)
case "stop":
- return a.processContainerStop(ctx, jobRequest)
+ return a.processDockerStop(ctx, jobRequest)
case "remove":
- return a.processContainerRemove(ctx, jobRequest)
+ return a.processDockerRemove(ctx, jobRequest)
case "list":
- return a.processContainerList(ctx, jobRequest)
+ return a.processDockerList(ctx, jobRequest)
case "inspect":
- return a.processContainerInspect(ctx, jobRequest)
+ return a.processDockerInspect(ctx, jobRequest)
case "exec":
- return a.processContainerExec(ctx, jobRequest)
+ return a.processDockerExec(ctx, jobRequest)
case "pull":
- return a.processContainerPull(ctx, jobRequest)
+ return a.processDockerPull(ctx, jobRequest)
default:
- return nil, fmt.Errorf("unsupported container operation: %s", jobRequest.Operation)
+ return nil, fmt.Errorf("unsupported docker operation: %s", jobRequest.Operation)
}
}
-// processContainerCreate handles container creation.
-func (a *Agent) processContainerCreate(
+// processDockerCreate handles docker container creation.
+func (a *Agent) processDockerCreate(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
- var data job.ContainerCreateData
+ var data job.DockerCreateData
if err := json.Unmarshal(jobRequest.Data, &data); err != nil {
return nil, fmt.Errorf("unmarshal create data: %w", err)
}
// Map ports and volumes from job types to runtime types
- var ports []runtime.PortMapping
+ var ports []dockerProv.PortMapping
for _, p := range data.Ports {
- ports = append(ports, runtime.PortMapping{Host: p.Host, Container: p.Container})
+ ports = append(ports, dockerProv.PortMapping{Host: p.Host, Container: p.Container})
}
- var volumes []runtime.VolumeMapping
+ var volumes []dockerProv.VolumeMapping
for _, v := range data.Volumes {
- volumes = append(volumes, runtime.VolumeMapping{Host: v.Host, Container: v.Container})
+ volumes = append(volumes, dockerProv.VolumeMapping{Host: v.Host, Container: v.Container})
}
- result, err := a.containerProvider.Create(ctx, runtime.CreateParams{
+ result, err := a.dockerProvider.Create(ctx, dockerProv.CreateParams{
Image: data.Image,
Name: data.Name,
Command: data.Command,
@@ -103,8 +103,8 @@ func (a *Agent) processContainerCreate(
return json.Marshal(result)
}
-// processContainerStart handles starting a container.
-func (a *Agent) processContainerStart(
+// processDockerStart handles starting a docker container.
+func (a *Agent) processDockerStart(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
@@ -115,18 +115,16 @@ func (a *Agent) processContainerStart(
return nil, fmt.Errorf("unmarshal start data: %w", err)
}
- if err := a.containerProvider.Start(ctx, data.ID); err != nil {
+ result, err := a.dockerProvider.Start(ctx, data.ID)
+ if err != nil {
return nil, err
}
- result := map[string]interface{}{
- "message": "Container started successfully",
- }
return json.Marshal(result)
}
-// processContainerStop handles stopping a container.
-func (a *Agent) processContainerStop(
+// processDockerStop handles stopping a docker container.
+func (a *Agent) processDockerStop(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
@@ -144,18 +142,16 @@ func (a *Agent) processContainerStop(
timeout = &d
}
- if err := a.containerProvider.Stop(ctx, data.ID, timeout); err != nil {
+ result, err := a.dockerProvider.Stop(ctx, data.ID, timeout)
+ if err != nil {
return nil, err
}
- result := map[string]interface{}{
- "message": "Container stopped successfully",
- }
return json.Marshal(result)
}
-// processContainerRemove handles removing a container.
-func (a *Agent) processContainerRemove(
+// processDockerRemove handles removing a docker container.
+func (a *Agent) processDockerRemove(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
@@ -167,27 +163,25 @@ func (a *Agent) processContainerRemove(
return nil, fmt.Errorf("unmarshal remove data: %w", err)
}
- if err := a.containerProvider.Remove(ctx, data.ID, data.Force); err != nil {
+ result, err := a.dockerProvider.Remove(ctx, data.ID, data.Force)
+ if err != nil {
return nil, err
}
- result := map[string]interface{}{
- "message": "Container removed successfully",
- }
return json.Marshal(result)
}
-// processContainerList handles listing containers.
-func (a *Agent) processContainerList(
+// processDockerList handles listing docker containers.
+func (a *Agent) processDockerList(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
- var data job.ContainerListData
+ var data job.DockerListData
if err := json.Unmarshal(jobRequest.Data, &data); err != nil {
return nil, fmt.Errorf("unmarshal list data: %w", err)
}
- result, err := a.containerProvider.List(ctx, runtime.ListParams{
+ result, err := a.dockerProvider.List(ctx, dockerProv.ListParams{
State: data.State,
Limit: data.Limit,
})
@@ -198,8 +192,8 @@ func (a *Agent) processContainerList(
return json.Marshal(result)
}
-// processContainerInspect handles inspecting a container.
-func (a *Agent) processContainerInspect(
+// processDockerInspect handles inspecting a docker container.
+func (a *Agent) processDockerInspect(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
@@ -210,7 +204,7 @@ func (a *Agent) processContainerInspect(
return nil, fmt.Errorf("unmarshal inspect data: %w", err)
}
- result, err := a.containerProvider.Inspect(ctx, data.ID)
+ result, err := a.dockerProvider.Inspect(ctx, data.ID)
if err != nil {
return nil, err
}
@@ -218,8 +212,8 @@ func (a *Agent) processContainerInspect(
return json.Marshal(result)
}
-// processContainerExec handles executing a command in a container.
-func (a *Agent) processContainerExec(
+// processDockerExec handles executing a command in a docker container.
+func (a *Agent) processDockerExec(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
@@ -233,7 +227,7 @@ func (a *Agent) processContainerExec(
return nil, fmt.Errorf("unmarshal exec data: %w", err)
}
- result, err := a.containerProvider.Exec(ctx, data.ID, runtime.ExecParams{
+ result, err := a.dockerProvider.Exec(ctx, data.ID, dockerProv.ExecParams{
Command: data.Command,
Env: data.Env,
WorkingDir: data.WorkingDir,
@@ -245,8 +239,8 @@ func (a *Agent) processContainerExec(
return json.Marshal(result)
}
-// processContainerPull handles pulling a container image.
-func (a *Agent) processContainerPull(
+// processDockerPull handles pulling a docker image.
+func (a *Agent) processDockerPull(
ctx context.Context,
jobRequest job.Request,
) (json.RawMessage, error) {
@@ -257,7 +251,7 @@ func (a *Agent) processContainerPull(
return nil, fmt.Errorf("unmarshal pull data: %w", err)
}
- result, err := a.containerProvider.Pull(ctx, data.Image)
+ result, err := a.dockerProvider.Pull(ctx, data.Image)
if err != nil {
return nil, err
}
diff --git a/internal/agent/processor_container_test.go b/internal/agent/processor_docker_test.go
similarity index 72%
rename from internal/agent/processor_container_test.go
rename to internal/agent/processor_docker_test.go
index 33083b5f..86922195 100644
--- a/internal/agent/processor_container_test.go
+++ b/internal/agent/processor_docker_test.go
@@ -35,9 +35,8 @@ import (
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/job/mocks"
commandMocks "github.com/retr0h/osapi/internal/provider/command/mocks"
- containerProv "github.com/retr0h/osapi/internal/provider/container"
- containerMocks "github.com/retr0h/osapi/internal/provider/container/mocks"
- "github.com/retr0h/osapi/internal/provider/container/runtime"
+ dockerProv "github.com/retr0h/osapi/internal/provider/docker"
+ dockerMocks "github.com/retr0h/osapi/internal/provider/docker/mocks"
fileMocks "github.com/retr0h/osapi/internal/provider/file/mocks"
dnsMocks "github.com/retr0h/osapi/internal/provider/network/dns/mocks"
netinfoMocks "github.com/retr0h/osapi/internal/provider/network/netinfo/mocks"
@@ -48,24 +47,24 @@ import (
memMocks "github.com/retr0h/osapi/internal/provider/node/mem/mocks"
)
-type ProcessorContainerTestSuite struct {
+type ProcessorDockerTestSuite struct {
suite.Suite
mockCtrl *gomock.Controller
mockJobClient *mocks.MockJobClient
}
-func (s *ProcessorContainerTestSuite) SetupTest() {
+func (s *ProcessorDockerTestSuite) SetupTest() {
s.mockCtrl = gomock.NewController(s.T())
s.mockJobClient = mocks.NewMockJobClient(s.mockCtrl)
}
-func (s *ProcessorContainerTestSuite) TearDownTest() {
+func (s *ProcessorDockerTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ProcessorContainerTestSuite) newAgentWithContainerMock(
- containerMock containerProv.Provider,
+func (s *ProcessorDockerTestSuite) newAgentWithContainerMock(
+ containerMock dockerProv.Provider,
) *Agent {
return New(
afero.NewMemMapFs(),
@@ -88,11 +87,11 @@ func (s *ProcessorContainerTestSuite) newAgentWithContainerMock(
)
}
-func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
+func (s *ProcessorDockerTestSuite) TestProcessDockerOperation() {
tests := []struct {
name string
jobRequest job.Request
- setupMock func(*containerMocks.MockProvider)
+ setupMock func(*dockerMocks.MockProvider)
expectError bool
errorMsg string
validate func(json.RawMessage)
@@ -101,103 +100,107 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "nil provider returns error",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(`{"image":"nginx:latest"}`),
},
setupMock: nil,
expectError: true,
- errorMsg: "container runtime not available",
+ errorMsg: "docker runtime not available",
},
{
name: "successful container create",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(
`{"image":"nginx:latest","name":"web","auto_start":true}`,
),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
- Create(gomock.Any(), runtime.CreateParams{
+ Create(gomock.Any(), dockerProv.CreateParams{
Image: "nginx:latest",
Name: "web",
AutoStart: true,
}).
- Return(&runtime.Container{
- ID: "abc123",
- Name: "web",
- Image: "nginx:latest",
- State: "created",
+ Return(&dockerProv.Container{
+ ID: "abc123",
+ Name: "web",
+ Image: "nginx:latest",
+ State: "created",
+ Changed: true,
}, nil)
},
validate: func(result json.RawMessage) {
- var r runtime.Container
+ var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
- s.Equal("abc123", r.ID)
- s.Equal("web", r.Name)
+ s.Equal("abc123", r["id"])
+ s.Equal("web", r["name"])
+ s.Equal(true, r["changed"])
},
},
{
name: "successful container create with ports and volumes",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(
`{"image":"nginx:latest","name":"web","ports":[{"host":8080,"container":80}],"volumes":[{"host":"/data","container":"/var/data"}]}`,
),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
- Create(gomock.Any(), runtime.CreateParams{
+ Create(gomock.Any(), dockerProv.CreateParams{
Image: "nginx:latest",
Name: "web",
- Ports: []runtime.PortMapping{
+ Ports: []dockerProv.PortMapping{
{Host: 8080, Container: 80},
},
- Volumes: []runtime.VolumeMapping{
+ Volumes: []dockerProv.VolumeMapping{
{Host: "/data", Container: "/var/data"},
},
}).
- Return(&runtime.Container{
- ID: "def456",
- Name: "web",
- Image: "nginx:latest",
- State: "created",
+ Return(&dockerProv.Container{
+ ID: "def456",
+ Name: "web",
+ Image: "nginx:latest",
+ State: "created",
+ Changed: true,
}, nil)
},
validate: func(result json.RawMessage) {
- var r runtime.Container
+ var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
- s.Equal("def456", r.ID)
+ s.Equal("def456", r["id"])
+ s.Equal(true, r["changed"])
},
},
{
- name: "unsupported container operation",
+ name: "unsupported docker operation",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "unknown.get",
Data: json.RawMessage(`{}`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
- errorMsg: "unsupported container operation",
+ errorMsg: "unsupported docker operation",
},
{
name: "create with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal create data",
},
@@ -205,11 +208,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on create",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(`{"image":"nginx:latest"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Create(gomock.Any(), gomock.Any()).
Return(nil, errors.New("docker error"))
@@ -222,31 +225,35 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container start",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "start.execute",
Data: json.RawMessage(`{"id":"abc123"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Start(gomock.Any(), "abc123").
- Return(nil)
+ Return(&dockerProv.ActionResult{
+ Message: "Container started successfully",
+ Changed: true,
+ }, nil)
},
validate: func(result json.RawMessage) {
var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Contains(r, "message")
+ s.Equal(true, r["changed"])
},
},
{
name: "start with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "start.execute",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal start data",
},
@@ -254,14 +261,14 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on start",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "start.execute",
Data: json.RawMessage(`{"id":"abc123"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Start(gomock.Any(), "abc123").
- Return(errors.New("start failed"))
+ Return(nil, errors.New("start failed"))
},
expectError: true,
errorMsg: "start failed",
@@ -271,51 +278,59 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container stop with timeout",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "stop.execute",
Data: json.RawMessage(`{"id":"abc123","timeout":10}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Stop(gomock.Any(), "abc123", gomock.Any()).
- Return(nil)
+ Return(&dockerProv.ActionResult{
+ Message: "Container stopped successfully",
+ Changed: true,
+ }, nil)
},
validate: func(result json.RawMessage) {
var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Contains(r, "message")
+ s.Equal(true, r["changed"])
},
},
{
name: "successful container stop without timeout",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "stop.execute",
Data: json.RawMessage(`{"id":"abc123"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Stop(gomock.Any(), "abc123", (*time.Duration)(nil)).
- Return(nil)
+ Return(&dockerProv.ActionResult{
+ Message: "Container stopped successfully",
+ Changed: true,
+ }, nil)
},
validate: func(result json.RawMessage) {
var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Contains(r, "message")
+ s.Equal(true, r["changed"])
},
},
{
name: "stop with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "stop.execute",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal stop data",
},
@@ -323,14 +338,14 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on stop",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "stop.execute",
Data: json.RawMessage(`{"id":"abc123","timeout":10}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Stop(gomock.Any(), "abc123", gomock.Any()).
- Return(errors.New("stop failed"))
+ Return(nil, errors.New("stop failed"))
},
expectError: true,
errorMsg: "stop failed",
@@ -340,31 +355,35 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container remove",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "remove.execute",
Data: json.RawMessage(`{"id":"abc123","force":true}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Remove(gomock.Any(), "abc123", true).
- Return(nil)
+ Return(&dockerProv.ActionResult{
+ Message: "Container removed successfully",
+ Changed: true,
+ }, nil)
},
validate: func(result json.RawMessage) {
var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Contains(r, "message")
+ s.Equal(true, r["changed"])
},
},
{
name: "remove with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "remove.execute",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal remove data",
},
@@ -372,14 +391,14 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on remove",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "remove.execute",
Data: json.RawMessage(`{"id":"abc123","force":false}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Remove(gomock.Any(), "abc123", false).
- Return(errors.New("remove failed"))
+ Return(nil, errors.New("remove failed"))
},
expectError: true,
errorMsg: "remove failed",
@@ -389,22 +408,22 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container list",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "list.get",
Data: json.RawMessage(`{"state":"running","limit":10}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
- List(gomock.Any(), runtime.ListParams{
+ List(gomock.Any(), dockerProv.ListParams{
State: "running",
Limit: 10,
}).
- Return([]runtime.Container{
+ Return([]dockerProv.Container{
{ID: "abc123"},
}, nil)
},
validate: func(result json.RawMessage) {
- var r []runtime.Container
+ var r []dockerProv.Container
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Len(r, 1)
@@ -415,11 +434,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "list with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "list.get",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal list data",
},
@@ -427,11 +446,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on list",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "list.get",
Data: json.RawMessage(`{"state":"all"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
List(gomock.Any(), gomock.Any()).
Return(nil, errors.New("list failed"))
@@ -444,19 +463,19 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container inspect",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "inspect.get",
Data: json.RawMessage(`{"id":"abc123"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Inspect(gomock.Any(), "abc123").
- Return(&runtime.ContainerDetail{
- Container: runtime.Container{ID: "abc123"},
+ Return(&dockerProv.ContainerDetail{
+ Container: dockerProv.Container{ID: "abc123"},
}, nil)
},
validate: func(result json.RawMessage) {
- var r runtime.ContainerDetail
+ var r dockerProv.ContainerDetail
err := json.Unmarshal(result, &r)
s.NoError(err)
s.Equal("abc123", r.ID)
@@ -466,11 +485,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "inspect with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "inspect.get",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal inspect data",
},
@@ -478,11 +497,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on inspect",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "inspect.get",
Data: json.RawMessage(`{"id":"abc123"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Inspect(gomock.Any(), "abc123").
Return(nil, errors.New("inspect failed"))
@@ -495,37 +514,39 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container exec",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "exec.execute",
Data: json.RawMessage(`{"id":"abc123","command":["ls","-la"]}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
- Exec(gomock.Any(), "abc123", runtime.ExecParams{
+ Exec(gomock.Any(), "abc123", dockerProv.ExecParams{
Command: []string{"ls", "-la"},
}).
- Return(&runtime.ExecResult{
+ Return(&dockerProv.ExecResult{
Stdout: "output",
ExitCode: 0,
+ Changed: true,
}, nil)
},
validate: func(result json.RawMessage) {
- var r runtime.ExecResult
+ var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
- s.Equal("output", r.Stdout)
- s.Equal(0, r.ExitCode)
+ s.Equal("output", r["stdout"])
+ s.Equal(float64(0), r["exit_code"])
+ s.Equal(true, r["changed"])
},
},
{
name: "exec with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "exec.execute",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal exec data",
},
@@ -533,11 +554,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on exec",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "exec.execute",
Data: json.RawMessage(`{"id":"abc123","command":["ls"]}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Exec(gomock.Any(), "abc123", gomock.Any()).
Return(nil, errors.New("exec failed"))
@@ -550,33 +571,35 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "successful container pull",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "pull.execute",
Data: json.RawMessage(`{"image":"nginx:latest"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Pull(gomock.Any(), "nginx:latest").
- Return(&runtime.PullResult{
+ Return(&dockerProv.PullResult{
ImageID: "sha256:abc",
+ Changed: true,
}, nil)
},
validate: func(result json.RawMessage) {
- var r runtime.PullResult
+ var r map[string]interface{}
err := json.Unmarshal(result, &r)
s.NoError(err)
- s.Equal("sha256:abc", r.ImageID)
+ s.Equal("sha256:abc", r["image_id"])
+ s.Equal(true, r["changed"])
},
},
{
name: "pull with invalid JSON data",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "pull.execute",
Data: json.RawMessage(`invalid json`),
},
- setupMock: func(_ *containerMocks.MockProvider) {},
+ setupMock: func(_ *dockerMocks.MockProvider) {},
expectError: true,
errorMsg: "unmarshal pull data",
},
@@ -584,11 +607,11 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
name: "provider error on pull",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "pull.execute",
Data: json.RawMessage(`{"image":"nginx:latest"}`),
},
- setupMock: func(m *containerMocks.MockProvider) {
+ setupMock: func(m *dockerMocks.MockProvider) {
m.EXPECT().
Pull(gomock.Any(), "nginx:latest").
Return(nil, errors.New("pull failed"))
@@ -602,7 +625,7 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
s.Run(tt.name, func() {
var a *Agent
if tt.setupMock != nil {
- containerMock := containerMocks.NewMockProvider(s.mockCtrl)
+ containerMock := dockerMocks.NewMockProvider(s.mockCtrl)
tt.setupMock(containerMock)
a = s.newAgentWithContainerMock(containerMock)
} else {
@@ -610,7 +633,7 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
a = s.newAgentWithContainerMock(nil)
}
- result, err := a.processContainerOperation(tt.jobRequest)
+ result, err := a.processDockerOperation(tt.jobRequest)
if tt.expectError {
s.Error(err)
@@ -627,6 +650,6 @@ func (s *ProcessorContainerTestSuite) TestProcessContainerOperation() {
}
}
-func TestProcessorContainerTestSuite(t *testing.T) {
- suite.Run(t, new(ProcessorContainerTestSuite))
+func TestProcessorDockerTestSuite(t *testing.T) {
+ suite.Run(t, new(ProcessorDockerTestSuite))
}
diff --git a/internal/agent/processor_test.go b/internal/agent/processor_test.go
index 57f61bb6..34b792cc 100644
--- a/internal/agent/processor_test.go
+++ b/internal/agent/processor_test.go
@@ -377,15 +377,15 @@ func (s *ProcessorTestSuite) TestProcessJobOperation() {
},
},
{
- name: "container category routes to container processor",
+ name: "docker category routes to docker processor",
jobRequest: job.Request{
Type: job.TypeModify,
- Category: "container",
+ Category: "docker",
Operation: "create.execute",
Data: json.RawMessage(`{"image":"nginx:latest"}`),
},
expectError: true,
- errorMsg: "container runtime not available",
+ errorMsg: "docker runtime not available",
},
{
name: "unsupported job category",
diff --git a/internal/agent/types.go b/internal/agent/types.go
index 894d39e7..a2d91457 100644
--- a/internal/agent/types.go
+++ b/internal/agent/types.go
@@ -33,7 +33,7 @@ import (
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/job/client"
"github.com/retr0h/osapi/internal/provider/command"
- containerProv "github.com/retr0h/osapi/internal/provider/container"
+ dockerProv "github.com/retr0h/osapi/internal/provider/docker"
fileProv "github.com/retr0h/osapi/internal/provider/file"
"github.com/retr0h/osapi/internal/provider/network/dns"
"github.com/retr0h/osapi/internal/provider/network/netinfo"
@@ -71,8 +71,8 @@ type Agent struct {
// File provider
fileProvider fileProv.Provider
- // Container provider
- containerProvider containerProv.Provider
+ // Docker provider
+ dockerProvider dockerProv.Provider
// Registry KV for heartbeat registration
registryKV jetstream.KeyValue
diff --git a/internal/api/container/gen/container.gen.go b/internal/api/container/gen/container.gen.go
deleted file mode 100644
index 0f22430f..00000000
--- a/internal/api/container/gen/container.gen.go
+++ /dev/null
@@ -1,1351 +0,0 @@
-// Package gen provides primitives to interact with the openapi HTTP API.
-//
-// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT.
-package gen
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "net/http"
-
- "github.com/labstack/echo/v4"
- "github.com/oapi-codegen/runtime"
- strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
- openapi_types "github.com/oapi-codegen/runtime/types"
- externalRef0 "github.com/retr0h/osapi/internal/api/common/gen"
-)
-
-const (
- BearerAuthScopes = "BearerAuth.Scopes"
-)
-
-// Defines values for GetNodeContainerParamsState.
-const (
- All GetNodeContainerParamsState = "all"
- Running GetNodeContainerParamsState = "running"
- Stopped GetNodeContainerParamsState = "stopped"
-)
-
-// ContainerActionCollectionResponse defines model for ContainerActionCollectionResponse.
-type ContainerActionCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerActionResultItem `json:"results"`
-}
-
-// ContainerActionResultItem Result of a container lifecycle action.
-type ContainerActionResultItem struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-
- // Id Container identifier.
- Id *string `json:"id,omitempty"`
-
- // Message Status message.
- Message *string `json:"message,omitempty"`
-}
-
-// ContainerCreateRequest defines model for ContainerCreateRequest.
-type ContainerCreateRequest struct {
- // AutoStart Whether to start the container immediately after creation. Defaults to true.
- AutoStart *bool `json:"auto_start,omitempty"`
-
- // Command Command to run in the container.
- Command *[]string `json:"command,omitempty"`
-
- // Env Environment variables in KEY=VALUE format.
- Env *[]string `json:"env,omitempty"`
-
- // Image Container image reference (e.g., "nginx:latest").
- Image string `json:"image" validate:"required,min=1"`
-
- // Name Optional name for the container.
- Name *string `json:"name,omitempty"`
-
- // Ports Port mappings in host_port:container_port format.
- Ports *[]string `json:"ports,omitempty"`
-
- // Volumes Volume mounts in host_path:container_path format.
- Volumes *[]string `json:"volumes,omitempty"`
-}
-
-// ContainerDetailCollectionResponse defines model for ContainerDetailCollectionResponse.
-type ContainerDetailCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerDetailResponse `json:"results"`
-}
-
-// ContainerDetailResponse Detailed information about a container.
-type ContainerDetailResponse struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Created Container creation timestamp.
- Created *string `json:"created,omitempty"`
-
- // Env Environment variables.
- Env *[]string `json:"env,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Health Health check status if configured.
- Health *string `json:"health,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-
- // Id Container identifier.
- Id *string `json:"id,omitempty"`
-
- // Image Image used by the container.
- Image *string `json:"image,omitempty"`
-
- // Mounts Volume mounts.
- Mounts *[]string `json:"mounts,omitempty"`
-
- // Name Container name.
- Name *string `json:"name,omitempty"`
-
- // NetworkSettings Network configuration.
- NetworkSettings *map[string]string `json:"network_settings,omitempty"`
-
- // Ports Port mappings.
- Ports *[]string `json:"ports,omitempty"`
-
- // State Current container state.
- State *string `json:"state,omitempty"`
-}
-
-// ContainerExecCollectionResponse defines model for ContainerExecCollectionResponse.
-type ContainerExecCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerExecResultItem `json:"results"`
-}
-
-// ContainerExecRequest defines model for ContainerExecRequest.
-type ContainerExecRequest struct {
- // Command Command to execute inside the container.
- Command []string `json:"command" validate:"required,min=1"`
-
- // Env Additional environment variables in KEY=VALUE format.
- Env *[]string `json:"env,omitempty"`
-
- // WorkingDir Working directory inside the container.
- WorkingDir *string `json:"working_dir,omitempty"`
-}
-
-// ContainerExecResultItem Result of a command execution inside a container.
-type ContainerExecResultItem struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // ExitCode Exit code of the command.
- ExitCode *int `json:"exit_code,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-
- // Stderr Standard error output of the command.
- Stderr *string `json:"stderr,omitempty"`
-
- // Stdout Standard output of the command.
- Stdout *string `json:"stdout,omitempty"`
-}
-
-// ContainerListCollectionResponse defines model for ContainerListCollectionResponse.
-type ContainerListCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerListItem `json:"results"`
-}
-
-// ContainerListItem Container summary for list operations.
-type ContainerListItem struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Containers List of containers on this agent.
- Containers *[]ContainerSummary `json:"containers,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-}
-
-// ContainerPullCollectionResponse defines model for ContainerPullCollectionResponse.
-type ContainerPullCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerPullResultItem `json:"results"`
-}
-
-// ContainerPullRequest defines model for ContainerPullRequest.
-type ContainerPullRequest struct {
- // Image Image reference to pull (e.g., "nginx:latest", "docker.io/library/alpine:3.18").
- Image string `json:"image" validate:"required,min=1"`
-}
-
-// ContainerPullResultItem Result of an image pull operation.
-type ContainerPullResultItem struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-
- // ImageId The pulled image ID.
- ImageId *string `json:"image_id,omitempty"`
-
- // Size Image size in bytes.
- Size *int64 `json:"size,omitempty"`
-
- // Tag The image tag that was pulled.
- Tag *string `json:"tag,omitempty"`
-}
-
-// ContainerResponse Summary information about a container.
-type ContainerResponse struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Created Container creation timestamp.
- Created *string `json:"created,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-
- // Id Container identifier.
- Id *string `json:"id,omitempty"`
-
- // Image Image used by the container.
- Image *string `json:"image,omitempty"`
-
- // Name Container name.
- Name *string `json:"name,omitempty"`
-
- // State Current container state.
- State *string `json:"state,omitempty"`
-}
-
-// ContainerResultCollectionResponse defines model for ContainerResultCollectionResponse.
-type ContainerResultCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerResponse `json:"results"`
-}
-
-// ContainerStopRequest defines model for ContainerStopRequest.
-type ContainerStopRequest struct {
- // Timeout Seconds to wait before killing the container. Defaults to 10.
- Timeout *int `json:"timeout,omitempty" validate:"omitempty,min=0,max=300"`
-}
-
-// ContainerSummary Brief container summary.
-type ContainerSummary struct {
- // Created Container creation timestamp.
- Created *string `json:"created,omitempty"`
-
- // Id Container identifier.
- Id *string `json:"id,omitempty"`
-
- // Image Image used by the container.
- Image *string `json:"image,omitempty"`
-
- // Name Container name.
- Name *string `json:"name,omitempty"`
-
- // State Current container state.
- State *string `json:"state,omitempty"`
-}
-
-// ErrorResponse defines model for ErrorResponse.
-type ErrorResponse = externalRef0.ErrorResponse
-
-// ContainerId defines model for ContainerId.
-type ContainerId = string
-
-// Hostname defines model for Hostname.
-type Hostname = string
-
-// GetNodeContainerParams defines parameters for GetNodeContainer.
-type GetNodeContainerParams struct {
- // State Filter containers by state. Defaults to "all".
- State *GetNodeContainerParamsState `form:"state,omitempty" json:"state,omitempty" validate:"omitempty,oneof=running stopped all"`
-
- // Limit Maximum number of containers to return.
- Limit *int `form:"limit,omitempty" json:"limit,omitempty" validate:"omitempty,min=1,max=100"`
-}
-
-// GetNodeContainerParamsState defines parameters for GetNodeContainer.
-type GetNodeContainerParamsState string
-
-// DeleteNodeContainerByIDParams defines parameters for DeleteNodeContainerByID.
-type DeleteNodeContainerByIDParams struct {
- // Force Force removal of a running container.
- Force *bool `form:"force,omitempty" json:"force,omitempty" validate:"omitempty"`
-}
-
-// PostNodeContainerJSONRequestBody defines body for PostNodeContainer for application/json ContentType.
-type PostNodeContainerJSONRequestBody = ContainerCreateRequest
-
-// PostNodeContainerPullJSONRequestBody defines body for PostNodeContainerPull for application/json ContentType.
-type PostNodeContainerPullJSONRequestBody = ContainerPullRequest
-
-// PostNodeContainerExecJSONRequestBody defines body for PostNodeContainerExec for application/json ContentType.
-type PostNodeContainerExecJSONRequestBody = ContainerExecRequest
-
-// PostNodeContainerStopJSONRequestBody defines body for PostNodeContainerStop for application/json ContentType.
-type PostNodeContainerStopJSONRequestBody = ContainerStopRequest
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
- // List containers
- // (GET /node/{hostname}/container)
- GetNodeContainer(ctx echo.Context, hostname Hostname, params GetNodeContainerParams) error
- // Create a container
- // (POST /node/{hostname}/container)
- PostNodeContainer(ctx echo.Context, hostname Hostname) error
- // Pull a container image
- // (POST /node/{hostname}/container/pull)
- PostNodeContainerPull(ctx echo.Context, hostname Hostname) error
- // Remove a container
- // (DELETE /node/{hostname}/container/{id})
- DeleteNodeContainerByID(ctx echo.Context, hostname Hostname, id ContainerId, params DeleteNodeContainerByIDParams) error
- // Inspect a container
- // (GET /node/{hostname}/container/{id})
- GetNodeContainerByID(ctx echo.Context, hostname Hostname, id ContainerId) error
- // Execute a command in a container
- // (POST /node/{hostname}/container/{id}/exec)
- PostNodeContainerExec(ctx echo.Context, hostname Hostname, id ContainerId) error
- // Start a container
- // (POST /node/{hostname}/container/{id}/start)
- PostNodeContainerStart(ctx echo.Context, hostname Hostname, id ContainerId) error
- // Stop a container
- // (POST /node/{hostname}/container/{id}/stop)
- PostNodeContainerStop(ctx echo.Context, hostname Hostname, id ContainerId) error
-}
-
-// ServerInterfaceWrapper converts echo contexts to parameters.
-type ServerInterfaceWrapper struct {
- Handler ServerInterface
-}
-
-// GetNodeContainer converts echo context to params.
-func (w *ServerInterfaceWrapper) GetNodeContainer(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:read"})
-
- // Parameter object where we will unmarshal all parameters from the context
- var params GetNodeContainerParams
- // ------------- Optional query parameter "state" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "state", ctx.QueryParams(), ¶ms.State)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter state: %s", err))
- }
-
- // ------------- Optional query parameter "limit" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "limit", ctx.QueryParams(), ¶ms.Limit)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetNodeContainer(ctx, hostname, params)
- return err
-}
-
-// PostNodeContainer converts echo context to params.
-func (w *ServerInterfaceWrapper) PostNodeContainer(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:write"})
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.PostNodeContainer(ctx, hostname)
- return err
-}
-
-// PostNodeContainerPull converts echo context to params.
-func (w *ServerInterfaceWrapper) PostNodeContainerPull(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:write"})
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.PostNodeContainerPull(ctx, hostname)
- return err
-}
-
-// DeleteNodeContainerByID converts echo context to params.
-func (w *ServerInterfaceWrapper) DeleteNodeContainerByID(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- // ------------- Path parameter "id" -------------
- var id ContainerId
-
- err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:write"})
-
- // Parameter object where we will unmarshal all parameters from the context
- var params DeleteNodeContainerByIDParams
- // ------------- Optional query parameter "force" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "force", ctx.QueryParams(), ¶ms.Force)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter force: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.DeleteNodeContainerByID(ctx, hostname, id, params)
- return err
-}
-
-// GetNodeContainerByID converts echo context to params.
-func (w *ServerInterfaceWrapper) GetNodeContainerByID(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- // ------------- Path parameter "id" -------------
- var id ContainerId
-
- err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:read"})
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetNodeContainerByID(ctx, hostname, id)
- return err
-}
-
-// PostNodeContainerExec converts echo context to params.
-func (w *ServerInterfaceWrapper) PostNodeContainerExec(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- // ------------- Path parameter "id" -------------
- var id ContainerId
-
- err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:execute"})
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.PostNodeContainerExec(ctx, hostname, id)
- return err
-}
-
-// PostNodeContainerStart converts echo context to params.
-func (w *ServerInterfaceWrapper) PostNodeContainerStart(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- // ------------- Path parameter "id" -------------
- var id ContainerId
-
- err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:write"})
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.PostNodeContainerStart(ctx, hostname, id)
- return err
-}
-
-// PostNodeContainerStop converts echo context to params.
-func (w *ServerInterfaceWrapper) PostNodeContainerStop(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "hostname" -------------
- var hostname Hostname
-
- err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
- }
-
- // ------------- Path parameter "id" -------------
- var id ContainerId
-
- err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- ctx.Set(BearerAuthScopes, []string{"container:write"})
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.PostNodeContainerStop(ctx, hostname, id)
- return err
-}
-
-// This is a simple interface which specifies echo.Route addition functions which
-// are present on both echo.Echo and echo.Group, since we want to allow using
-// either of them for path registration
-type EchoRouter interface {
- CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
-}
-
-// RegisterHandlers adds each server route to the EchoRouter.
-func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
-}
-
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
-func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
-
- wrapper := ServerInterfaceWrapper{
- Handler: si,
- }
-
- router.GET(baseURL+"/node/:hostname/container", wrapper.GetNodeContainer)
- router.POST(baseURL+"/node/:hostname/container", wrapper.PostNodeContainer)
- router.POST(baseURL+"/node/:hostname/container/pull", wrapper.PostNodeContainerPull)
- router.DELETE(baseURL+"/node/:hostname/container/:id", wrapper.DeleteNodeContainerByID)
- router.GET(baseURL+"/node/:hostname/container/:id", wrapper.GetNodeContainerByID)
- router.POST(baseURL+"/node/:hostname/container/:id/exec", wrapper.PostNodeContainerExec)
- router.POST(baseURL+"/node/:hostname/container/:id/start", wrapper.PostNodeContainerStart)
- router.POST(baseURL+"/node/:hostname/container/:id/stop", wrapper.PostNodeContainerStop)
-
-}
-
-type GetNodeContainerRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Params GetNodeContainerParams
-}
-
-type GetNodeContainerResponseObject interface {
- VisitGetNodeContainerResponse(w http.ResponseWriter) error
-}
-
-type GetNodeContainer200JSONResponse ContainerListCollectionResponse
-
-func (response GetNodeContainer200JSONResponse) VisitGetNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainer400JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainer400JSONResponse) VisitGetNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainer401JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainer401JSONResponse) VisitGetNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainer403JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainer403JSONResponse) VisitGetNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainer500JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainer500JSONResponse) VisitGetNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Body *PostNodeContainerJSONRequestBody
-}
-
-type PostNodeContainerResponseObject interface {
- VisitPostNodeContainerResponse(w http.ResponseWriter) error
-}
-
-type PostNodeContainer202JSONResponse ContainerResultCollectionResponse
-
-func (response PostNodeContainer202JSONResponse) VisitPostNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(202)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainer400JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainer400JSONResponse) VisitPostNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainer401JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainer401JSONResponse) VisitPostNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainer403JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainer403JSONResponse) VisitPostNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainer500JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainer500JSONResponse) VisitPostNodeContainerResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerPullRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Body *PostNodeContainerPullJSONRequestBody
-}
-
-type PostNodeContainerPullResponseObject interface {
- VisitPostNodeContainerPullResponse(w http.ResponseWriter) error
-}
-
-type PostNodeContainerPull202JSONResponse ContainerPullCollectionResponse
-
-func (response PostNodeContainerPull202JSONResponse) VisitPostNodeContainerPullResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(202)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerPull400JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerPull400JSONResponse) VisitPostNodeContainerPullResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerPull401JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerPull401JSONResponse) VisitPostNodeContainerPullResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerPull403JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerPull403JSONResponse) VisitPostNodeContainerPullResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerPull500JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerPull500JSONResponse) VisitPostNodeContainerPullResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type DeleteNodeContainerByIDRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Id ContainerId `json:"id"`
- Params DeleteNodeContainerByIDParams
-}
-
-type DeleteNodeContainerByIDResponseObject interface {
- VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error
-}
-
-type DeleteNodeContainerByID202JSONResponse ContainerActionCollectionResponse
-
-func (response DeleteNodeContainerByID202JSONResponse) VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(202)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type DeleteNodeContainerByID400JSONResponse externalRef0.ErrorResponse
-
-func (response DeleteNodeContainerByID400JSONResponse) VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type DeleteNodeContainerByID401JSONResponse externalRef0.ErrorResponse
-
-func (response DeleteNodeContainerByID401JSONResponse) VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type DeleteNodeContainerByID403JSONResponse externalRef0.ErrorResponse
-
-func (response DeleteNodeContainerByID403JSONResponse) VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type DeleteNodeContainerByID404JSONResponse externalRef0.ErrorResponse
-
-func (response DeleteNodeContainerByID404JSONResponse) VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(404)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type DeleteNodeContainerByID500JSONResponse externalRef0.ErrorResponse
-
-func (response DeleteNodeContainerByID500JSONResponse) VisitDeleteNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainerByIDRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Id ContainerId `json:"id"`
-}
-
-type GetNodeContainerByIDResponseObject interface {
- VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error
-}
-
-type GetNodeContainerByID200JSONResponse ContainerDetailCollectionResponse
-
-func (response GetNodeContainerByID200JSONResponse) VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainerByID400JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainerByID400JSONResponse) VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainerByID401JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainerByID401JSONResponse) VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainerByID403JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainerByID403JSONResponse) VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainerByID404JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainerByID404JSONResponse) VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(404)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type GetNodeContainerByID500JSONResponse externalRef0.ErrorResponse
-
-func (response GetNodeContainerByID500JSONResponse) VisitGetNodeContainerByIDResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerExecRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Id ContainerId `json:"id"`
- Body *PostNodeContainerExecJSONRequestBody
-}
-
-type PostNodeContainerExecResponseObject interface {
- VisitPostNodeContainerExecResponse(w http.ResponseWriter) error
-}
-
-type PostNodeContainerExec202JSONResponse ContainerExecCollectionResponse
-
-func (response PostNodeContainerExec202JSONResponse) VisitPostNodeContainerExecResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(202)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerExec400JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerExec400JSONResponse) VisitPostNodeContainerExecResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerExec401JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerExec401JSONResponse) VisitPostNodeContainerExecResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerExec403JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerExec403JSONResponse) VisitPostNodeContainerExecResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerExec404JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerExec404JSONResponse) VisitPostNodeContainerExecResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(404)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerExec500JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerExec500JSONResponse) VisitPostNodeContainerExecResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStartRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Id ContainerId `json:"id"`
-}
-
-type PostNodeContainerStartResponseObject interface {
- VisitPostNodeContainerStartResponse(w http.ResponseWriter) error
-}
-
-type PostNodeContainerStart202JSONResponse ContainerActionCollectionResponse
-
-func (response PostNodeContainerStart202JSONResponse) VisitPostNodeContainerStartResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(202)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStart400JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStart400JSONResponse) VisitPostNodeContainerStartResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStart401JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStart401JSONResponse) VisitPostNodeContainerStartResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStart403JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStart403JSONResponse) VisitPostNodeContainerStartResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStart404JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStart404JSONResponse) VisitPostNodeContainerStartResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(404)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStart500JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStart500JSONResponse) VisitPostNodeContainerStartResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStopRequestObject struct {
- Hostname Hostname `json:"hostname"`
- Id ContainerId `json:"id"`
- Body *PostNodeContainerStopJSONRequestBody
-}
-
-type PostNodeContainerStopResponseObject interface {
- VisitPostNodeContainerStopResponse(w http.ResponseWriter) error
-}
-
-type PostNodeContainerStop202JSONResponse ContainerActionCollectionResponse
-
-func (response PostNodeContainerStop202JSONResponse) VisitPostNodeContainerStopResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(202)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStop400JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStop400JSONResponse) VisitPostNodeContainerStopResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(400)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStop401JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStop401JSONResponse) VisitPostNodeContainerStopResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(401)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStop403JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStop403JSONResponse) VisitPostNodeContainerStopResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(403)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStop404JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStop404JSONResponse) VisitPostNodeContainerStopResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(404)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-type PostNodeContainerStop500JSONResponse externalRef0.ErrorResponse
-
-func (response PostNodeContainerStop500JSONResponse) VisitPostNodeContainerStopResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(500)
-
- return json.NewEncoder(w).Encode(response)
-}
-
-// StrictServerInterface represents all server handlers.
-type StrictServerInterface interface {
- // List containers
- // (GET /node/{hostname}/container)
- GetNodeContainer(ctx context.Context, request GetNodeContainerRequestObject) (GetNodeContainerResponseObject, error)
- // Create a container
- // (POST /node/{hostname}/container)
- PostNodeContainer(ctx context.Context, request PostNodeContainerRequestObject) (PostNodeContainerResponseObject, error)
- // Pull a container image
- // (POST /node/{hostname}/container/pull)
- PostNodeContainerPull(ctx context.Context, request PostNodeContainerPullRequestObject) (PostNodeContainerPullResponseObject, error)
- // Remove a container
- // (DELETE /node/{hostname}/container/{id})
- DeleteNodeContainerByID(ctx context.Context, request DeleteNodeContainerByIDRequestObject) (DeleteNodeContainerByIDResponseObject, error)
- // Inspect a container
- // (GET /node/{hostname}/container/{id})
- GetNodeContainerByID(ctx context.Context, request GetNodeContainerByIDRequestObject) (GetNodeContainerByIDResponseObject, error)
- // Execute a command in a container
- // (POST /node/{hostname}/container/{id}/exec)
- PostNodeContainerExec(ctx context.Context, request PostNodeContainerExecRequestObject) (PostNodeContainerExecResponseObject, error)
- // Start a container
- // (POST /node/{hostname}/container/{id}/start)
- PostNodeContainerStart(ctx context.Context, request PostNodeContainerStartRequestObject) (PostNodeContainerStartResponseObject, error)
- // Stop a container
- // (POST /node/{hostname}/container/{id}/stop)
- PostNodeContainerStop(ctx context.Context, request PostNodeContainerStopRequestObject) (PostNodeContainerStopResponseObject, error)
-}
-
-type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc
-type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc
-
-func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
-}
-
-type strictHandler struct {
- ssi StrictServerInterface
- middlewares []StrictMiddlewareFunc
-}
-
-// GetNodeContainer operation middleware
-func (sh *strictHandler) GetNodeContainer(ctx echo.Context, hostname Hostname, params GetNodeContainerParams) error {
- var request GetNodeContainerRequestObject
-
- request.Hostname = hostname
- request.Params = params
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.GetNodeContainer(ctx.Request().Context(), request.(GetNodeContainerRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "GetNodeContainer")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(GetNodeContainerResponseObject); ok {
- return validResponse.VisitGetNodeContainerResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// PostNodeContainer operation middleware
-func (sh *strictHandler) PostNodeContainer(ctx echo.Context, hostname Hostname) error {
- var request PostNodeContainerRequestObject
-
- request.Hostname = hostname
-
- var body PostNodeContainerJSONRequestBody
- if err := ctx.Bind(&body); err != nil {
- return err
- }
- request.Body = &body
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.PostNodeContainer(ctx.Request().Context(), request.(PostNodeContainerRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "PostNodeContainer")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(PostNodeContainerResponseObject); ok {
- return validResponse.VisitPostNodeContainerResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// PostNodeContainerPull operation middleware
-func (sh *strictHandler) PostNodeContainerPull(ctx echo.Context, hostname Hostname) error {
- var request PostNodeContainerPullRequestObject
-
- request.Hostname = hostname
-
- var body PostNodeContainerPullJSONRequestBody
- if err := ctx.Bind(&body); err != nil {
- return err
- }
- request.Body = &body
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.PostNodeContainerPull(ctx.Request().Context(), request.(PostNodeContainerPullRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "PostNodeContainerPull")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(PostNodeContainerPullResponseObject); ok {
- return validResponse.VisitPostNodeContainerPullResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// DeleteNodeContainerByID operation middleware
-func (sh *strictHandler) DeleteNodeContainerByID(ctx echo.Context, hostname Hostname, id ContainerId, params DeleteNodeContainerByIDParams) error {
- var request DeleteNodeContainerByIDRequestObject
-
- request.Hostname = hostname
- request.Id = id
- request.Params = params
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.DeleteNodeContainerByID(ctx.Request().Context(), request.(DeleteNodeContainerByIDRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "DeleteNodeContainerByID")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(DeleteNodeContainerByIDResponseObject); ok {
- return validResponse.VisitDeleteNodeContainerByIDResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// GetNodeContainerByID operation middleware
-func (sh *strictHandler) GetNodeContainerByID(ctx echo.Context, hostname Hostname, id ContainerId) error {
- var request GetNodeContainerByIDRequestObject
-
- request.Hostname = hostname
- request.Id = id
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.GetNodeContainerByID(ctx.Request().Context(), request.(GetNodeContainerByIDRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "GetNodeContainerByID")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(GetNodeContainerByIDResponseObject); ok {
- return validResponse.VisitGetNodeContainerByIDResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// PostNodeContainerExec operation middleware
-func (sh *strictHandler) PostNodeContainerExec(ctx echo.Context, hostname Hostname, id ContainerId) error {
- var request PostNodeContainerExecRequestObject
-
- request.Hostname = hostname
- request.Id = id
-
- var body PostNodeContainerExecJSONRequestBody
- if err := ctx.Bind(&body); err != nil {
- return err
- }
- request.Body = &body
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.PostNodeContainerExec(ctx.Request().Context(), request.(PostNodeContainerExecRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "PostNodeContainerExec")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(PostNodeContainerExecResponseObject); ok {
- return validResponse.VisitPostNodeContainerExecResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// PostNodeContainerStart operation middleware
-func (sh *strictHandler) PostNodeContainerStart(ctx echo.Context, hostname Hostname, id ContainerId) error {
- var request PostNodeContainerStartRequestObject
-
- request.Hostname = hostname
- request.Id = id
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.PostNodeContainerStart(ctx.Request().Context(), request.(PostNodeContainerStartRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "PostNodeContainerStart")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(PostNodeContainerStartResponseObject); ok {
- return validResponse.VisitPostNodeContainerStartResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
-
-// PostNodeContainerStop operation middleware
-func (sh *strictHandler) PostNodeContainerStop(ctx echo.Context, hostname Hostname, id ContainerId) error {
- var request PostNodeContainerStopRequestObject
-
- request.Hostname = hostname
- request.Id = id
-
- var body PostNodeContainerStopJSONRequestBody
- if err := ctx.Bind(&body); err != nil {
- return err
- }
- request.Body = &body
-
- handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
- return sh.ssi.PostNodeContainerStop(ctx.Request().Context(), request.(PostNodeContainerStopRequestObject))
- }
- for _, middleware := range sh.middlewares {
- handler = middleware(handler, "PostNodeContainerStop")
- }
-
- response, err := handler(ctx, request)
-
- if err != nil {
- return err
- } else if validResponse, ok := response.(PostNodeContainerStopResponseObject); ok {
- return validResponse.VisitPostNodeContainerStopResponse(ctx.Response())
- } else if response != nil {
- return fmt.Errorf("unexpected response type: %T", response)
- }
- return nil
-}
diff --git a/internal/api/container/container.go b/internal/api/docker/container.go
similarity index 96%
rename from internal/api/container/container.go
rename to internal/api/docker/container.go
index 872c6ead..affe0702 100644
--- a/internal/api/container/container.go
+++ b/internal/api/docker/container.go
@@ -24,7 +24,7 @@ package container
import (
"log/slog"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job/client"
)
diff --git a/internal/api/container/container_create.go b/internal/api/docker/container_create.go
similarity index 78%
rename from internal/api/container/container_create.go
rename to internal/api/docker/container_create.go
index d46b1973..b147458e 100644
--- a/internal/api/container/container_create.go
+++ b/internal/api/docker/container_create.go
@@ -27,25 +27,25 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/validation"
)
-// PostNodeContainer creates a container on a target node.
-func (s *Container) PostNodeContainer(
+// PostNodeContainerDocker creates a container on a target node.
+func (s *Container) PostNodeContainerDocker(
ctx context.Context,
- request gen.PostNodeContainerRequestObject,
-) (gen.PostNodeContainerResponseObject, error) {
+ request gen.PostNodeContainerDockerRequestObject,
+) (gen.PostNodeContainerDockerResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.PostNodeContainer400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDocker400JSONResponse{Error: &errMsg}, nil
}
if errMsg, ok := validation.Struct(request.Body); !ok {
- return gen.PostNodeContainer400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDocker400JSONResponse{Error: &errMsg}, nil
}
- data := &job.ContainerCreateData{
+ data := &job.DockerCreateData{
Image: request.Body.Image,
Command: ptrToSlice(request.Body.Command),
Env: envSliceToMap(request.Body.Env),
@@ -68,10 +68,10 @@ func (s *Container) PostNodeContainer(
slog.String("target", hostname),
)
- resp, err := s.JobClient.ModifyContainerCreate(ctx, hostname, data)
+ resp, err := s.JobClient.ModifyDockerCreate(ctx, hostname, data)
if err != nil {
errMsg := err.Error()
- return gen.PostNodeContainer500JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDocker500JSONResponse{Error: &errMsg}, nil
}
var containerResp struct {
@@ -85,9 +85,9 @@ func (s *Container) PostNodeContainer(
id := containerResp.ID
changed := resp.Changed
- return gen.PostNodeContainer202JSONResponse{
+ return gen.PostNodeContainerDocker202JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerResponse{
+ Results: []gen.DockerResponse{
{
Hostname: resp.Hostname,
Id: stringPtrOrNil(id),
diff --git a/internal/api/container/container_create_public_test.go b/internal/api/docker/container_create_public_test.go
similarity index 77%
rename from internal/api/container/container_create_public_test.go
rename to internal/api/docker/container_create_public_test.go
index 1c455ac5..fc76791f 100644
--- a/internal/api/container/container_create_public_test.go
+++ b/internal/api/docker/container_create_public_test.go
@@ -35,8 +35,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -76,25 +76,25 @@ func (s *ContainerCreatePublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
+func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerDocker() {
tests := []struct {
name string
- request gen.PostNodeContainerRequestObject
+ request gen.PostNodeContainerDockerRequestObject
setupMock func()
- validateFunc func(resp gen.PostNodeContainerResponseObject)
+ validateFunc func(resp gen.PostNodeContainerDockerResponseObject)
}{
{
name: "success",
- request: gen.PostNodeContainerRequestObject{
+ request: gen.PostNodeContainerDockerRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "nginx:latest",
Name: strPtr("my-nginx"),
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerCreate(
+ ModifyDockerCreate(
gomock.Any(),
"server1",
gomock.Any(),
@@ -106,8 +106,8 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
Data: json.RawMessage(`{"id":"abc123"}`),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerResponseObject) {
- r, ok := resp.(gen.PostNodeContainer202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDocker202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -119,15 +119,15 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
},
{
name: "validation error empty hostname",
- request: gen.PostNodeContainerRequestObject{
+ request: gen.PostNodeContainerDockerRequestObject{
Hostname: "",
- Body: &gen.PostNodeContainerJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "nginx:latest",
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerResponseObject) {
- r, ok := resp.(gen.PostNodeContainer400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDocker400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -135,31 +135,31 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
},
{
name: "body validation error empty image",
- request: gen.PostNodeContainerRequestObject{
+ request: gen.PostNodeContainerDockerRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "",
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerResponseObject) {
- r, ok := resp.(gen.PostNodeContainer400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDocker400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
},
},
{
name: "success with explicit auto_start false",
- request: gen.PostNodeContainerRequestObject{
+ request: gen.PostNodeContainerDockerRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "nginx:latest",
AutoStart: boolPtr(false),
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerCreate(
+ ModifyDockerCreate(
gomock.Any(),
"server1",
gomock.Any(),
@@ -171,8 +171,8 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
Data: json.RawMessage(`{"id":"xyz789"}`),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerResponseObject) {
- r, ok := resp.(gen.PostNodeContainer202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDocker202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -184,15 +184,15 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
},
{
name: "success with nil response data",
- request: gen.PostNodeContainerRequestObject{
+ request: gen.PostNodeContainerDockerRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "nginx:latest",
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerCreate(
+ ModifyDockerCreate(
gomock.Any(),
"server1",
gomock.Any(),
@@ -204,8 +204,8 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
Data: nil,
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerResponseObject) {
- r, ok := resp.(gen.PostNodeContainer202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDocker202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -216,23 +216,23 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
},
{
name: "job client error",
- request: gen.PostNodeContainerRequestObject{
+ request: gen.PostNodeContainerDockerRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerJSONRequestBody{
Image: "nginx:latest",
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerCreate(
+ ModifyDockerCreate(
gomock.Any(),
"server1",
gomock.Any(),
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.PostNodeContainerResponseObject) {
- _, ok := resp.(gen.PostNodeContainer500JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerResponseObject) {
+ _, ok := resp.(gen.PostNodeContainerDocker500JSONResponse)
s.True(ok)
},
},
@@ -242,14 +242,14 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainer() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.PostNodeContainer(s.ctx, tt.request)
+ resp, err := s.handler.PostNodeContainerDocker(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerValidationHTTP() {
+func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerDockerValidationHTTP() {
tests := []struct {
name string
path string
@@ -260,12 +260,12 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerValidationHTTP() {
}{
{
name: "when valid request",
- path: "/node/server1/container",
+ path: "/node/server1/container/docker",
body: `{"image":"nginx:latest"}`,
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- ModifyContainerCreate(gomock.Any(), "server1", gomock.Any()).
+ ModifyDockerCreate(gomock.Any(), "server1", gomock.Any()).
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -279,7 +279,7 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerValidationHTTP() {
},
{
name: "when missing image",
- path: "/node/server1/container",
+ path: "/node/server1/container/docker",
body: `{}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
@@ -289,7 +289,7 @@ func (s *ContainerCreatePublicTestSuite) TestPostNodeContainerValidationHTTP() {
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container",
+ path: "/node/nonexistent/container/docker",
body: `{"image":"nginx:latest"}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
diff --git a/internal/api/container/container_exec.go b/internal/api/docker/container_exec.go
similarity index 76%
rename from internal/api/container/container_exec.go
rename to internal/api/docker/container_exec.go
index a7c78d0a..c55a2aa2 100644
--- a/internal/api/container/container_exec.go
+++ b/internal/api/docker/container_exec.go
@@ -27,28 +27,28 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/validation"
)
-// PostNodeContainerExec executes a command in a container on a target node.
-func (s *Container) PostNodeContainerExec(
+// PostNodeContainerDockerExec executes a command in a container on a target node.
+func (s *Container) PostNodeContainerDockerExec(
ctx context.Context,
- request gen.PostNodeContainerExecRequestObject,
-) (gen.PostNodeContainerExecResponseObject, error) {
+ request gen.PostNodeContainerDockerExecRequestObject,
+) (gen.PostNodeContainerDockerExecResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.PostNodeContainerExec400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerExec400JSONResponse{Error: &errMsg}, nil
}
if errMsg, ok := validation.Struct(request.Body); !ok {
- return gen.PostNodeContainerExec400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerExec400JSONResponse{Error: &errMsg}, nil
}
hostname := request.Hostname
id := request.Id
- data := &job.ContainerExecData{
+ data := &job.DockerExecData{
Command: request.Body.Command,
Env: envSliceToMap(request.Body.Env),
}
@@ -62,10 +62,10 @@ func (s *Container) PostNodeContainerExec(
slog.Any("command", data.Command),
)
- resp, err := s.JobClient.ModifyContainerExec(ctx, hostname, id, data)
+ resp, err := s.JobClient.ModifyDockerExec(ctx, hostname, id, data)
if err != nil {
errMsg := err.Error()
- return gen.PostNodeContainerExec500JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerExec500JSONResponse{Error: &errMsg}, nil
}
var execResult struct {
@@ -83,9 +83,9 @@ func (s *Container) PostNodeContainerExec(
stderr := execResult.Stderr
exitCode := execResult.ExitCode
- return gen.PostNodeContainerExec202JSONResponse{
+ return gen.PostNodeContainerDockerExec202JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerExecResultItem{
+ Results: []gen.DockerExecResultItem{
{
Hostname: resp.Hostname,
Stdout: &stdout,
diff --git a/internal/api/container/container_exec_public_test.go b/internal/api/docker/container_exec_public_test.go
similarity index 77%
rename from internal/api/container/container_exec_public_test.go
rename to internal/api/docker/container_exec_public_test.go
index 8e2cedb1..ed829136 100644
--- a/internal/api/container/container_exec_public_test.go
+++ b/internal/api/docker/container_exec_public_test.go
@@ -35,8 +35,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -76,25 +76,25 @@ func (s *ContainerExecPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
+func (s *ContainerExecPublicTestSuite) TestPostNodeContainerDockerExec() {
tests := []struct {
name string
- request gen.PostNodeContainerExecRequestObject
+ request gen.PostNodeContainerDockerExecRequestObject
setupMock func()
- validateFunc func(resp gen.PostNodeContainerExecResponseObject)
+ validateFunc func(resp gen.PostNodeContainerDockerExecResponseObject)
}{
{
name: "success",
- request: gen.PostNodeContainerExecRequestObject{
+ request: gen.PostNodeContainerDockerExecRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerExecJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerExecJSONRequestBody{
Command: []string{"ls", "-la"},
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerExec(
+ ModifyDockerExec(
gomock.Any(),
"server1",
"abc123",
@@ -109,8 +109,8 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerExecResponseObject) {
- r, ok := resp.(gen.PostNodeContainerExec202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerExecResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerExec202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -124,16 +124,16 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
},
{
name: "validation error empty hostname",
- request: gen.PostNodeContainerExecRequestObject{
+ request: gen.PostNodeContainerDockerExecRequestObject{
Hostname: "",
Id: "abc123",
- Body: &gen.PostNodeContainerExecJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerExecJSONRequestBody{
Command: []string{"ls"},
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerExecResponseObject) {
- r, ok := resp.(gen.PostNodeContainerExec400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerExecResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerExec400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -141,33 +141,33 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
},
{
name: "body validation error empty command",
- request: gen.PostNodeContainerExecRequestObject{
+ request: gen.PostNodeContainerDockerExecRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerExecJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerExecJSONRequestBody{
Command: []string{},
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerExecResponseObject) {
- r, ok := resp.(gen.PostNodeContainerExec400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerExecResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerExec400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
},
},
{
name: "success with working dir",
- request: gen.PostNodeContainerExecRequestObject{
+ request: gen.PostNodeContainerDockerExecRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerExecJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerExecJSONRequestBody{
Command: []string{"ls", "-la"},
WorkingDir: strPtr("/app"),
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerExec(
+ ModifyDockerExec(
gomock.Any(),
"server1",
"abc123",
@@ -182,8 +182,8 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerExecResponseObject) {
- r, ok := resp.(gen.PostNodeContainerExec202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerExecResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerExec202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -197,16 +197,16 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
},
{
name: "success with nil response data",
- request: gen.PostNodeContainerExecRequestObject{
+ request: gen.PostNodeContainerDockerExecRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerExecJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerExecJSONRequestBody{
Command: []string{"ls"},
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerExec(
+ ModifyDockerExec(
gomock.Any(),
"server1",
"abc123",
@@ -219,8 +219,8 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
Data: nil,
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerExecResponseObject) {
- r, ok := resp.(gen.PostNodeContainerExec202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerExecResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerExec202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -236,16 +236,16 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
},
{
name: "job client error",
- request: gen.PostNodeContainerExecRequestObject{
+ request: gen.PostNodeContainerDockerExecRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerExecJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerExecJSONRequestBody{
Command: []string{"ls"},
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerExec(
+ ModifyDockerExec(
gomock.Any(),
"server1",
"abc123",
@@ -253,8 +253,8 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.PostNodeContainerExecResponseObject) {
- _, ok := resp.(gen.PostNodeContainerExec500JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerExecResponseObject) {
+ _, ok := resp.(gen.PostNodeContainerDockerExec500JSONResponse)
s.True(ok)
},
},
@@ -264,14 +264,14 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExec() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.PostNodeContainerExec(s.ctx, tt.request)
+ resp, err := s.handler.PostNodeContainerDockerExec(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExecValidationHTTP() {
+func (s *ContainerExecPublicTestSuite) TestPostNodeContainerDockerExecValidationHTTP() {
tests := []struct {
name string
path string
@@ -282,12 +282,12 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExecValidationHTTP()
}{
{
name: "when valid request",
- path: "/node/server1/container/abc123/exec",
+ path: "/node/server1/container/docker/abc123/exec",
body: `{"command":["ls","-la"]}`,
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- ModifyContainerExec(gomock.Any(), "server1", "abc123", gomock.Any()).
+ ModifyDockerExec(gomock.Any(), "server1", "abc123", gomock.Any()).
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -301,7 +301,7 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExecValidationHTTP()
},
{
name: "when missing command",
- path: "/node/server1/container/abc123/exec",
+ path: "/node/server1/container/docker/abc123/exec",
body: `{}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
@@ -311,7 +311,7 @@ func (s *ContainerExecPublicTestSuite) TestPostNodeContainerExecValidationHTTP()
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container/abc123/exec",
+ path: "/node/nonexistent/container/docker/abc123/exec",
body: `{"command":["ls"]}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
diff --git a/internal/api/container/container_inspect.go b/internal/api/docker/container_inspect.go
similarity index 85%
rename from internal/api/container/container_inspect.go
rename to internal/api/docker/container_inspect.go
index f16b3529..9202629d 100644
--- a/internal/api/container/container_inspect.go
+++ b/internal/api/docker/container_inspect.go
@@ -27,16 +27,16 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
)
-// GetNodeContainerByID inspects a container on a target node.
-func (s *Container) GetNodeContainerByID(
+// GetNodeContainerDockerByID inspects a container on a target node.
+func (s *Container) GetNodeContainerDockerByID(
ctx context.Context,
- request gen.GetNodeContainerByIDRequestObject,
-) (gen.GetNodeContainerByIDResponseObject, error) {
+ request gen.GetNodeContainerDockerByIDRequestObject,
+) (gen.GetNodeContainerDockerByIDResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.GetNodeContainerByID400JSONResponse{Error: &errMsg}, nil
+ return gen.GetNodeContainerDockerByID400JSONResponse{Error: &errMsg}, nil
}
hostname := request.Hostname
@@ -47,10 +47,10 @@ func (s *Container) GetNodeContainerByID(
slog.String("id", id),
)
- resp, err := s.JobClient.QueryContainerInspect(ctx, hostname, id)
+ resp, err := s.JobClient.QueryDockerInspect(ctx, hostname, id)
if err != nil {
errMsg := err.Error()
- return gen.GetNodeContainerByID500JSONResponse{Error: &errMsg}, nil
+ return gen.GetNodeContainerDockerByID500JSONResponse{Error: &errMsg}, nil
}
var detail struct {
@@ -97,9 +97,9 @@ func (s *Container) GetNodeContainerByID(
jobUUID := uuid.MustParse(resp.JobID)
changed := resp.Changed
- return gen.GetNodeContainerByID200JSONResponse{
+ return gen.GetNodeContainerDockerByID200JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerDetailResponse{
+ Results: []gen.DockerDetailResponse{
{
Hostname: resp.Hostname,
Id: stringPtrOrNil(detail.ID),
diff --git a/internal/api/container/container_inspect_public_test.go b/internal/api/docker/container_inspect_public_test.go
similarity index 81%
rename from internal/api/container/container_inspect_public_test.go
rename to internal/api/docker/container_inspect_public_test.go
index 4111ab8a..85b1afa4 100644
--- a/internal/api/container/container_inspect_public_test.go
+++ b/internal/api/docker/container_inspect_public_test.go
@@ -34,8 +34,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -75,22 +75,22 @@ func (s *ContainerInspectPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByID() {
+func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerDockerByID() {
tests := []struct {
name string
- request gen.GetNodeContainerByIDRequestObject
+ request gen.GetNodeContainerDockerByIDRequestObject
setupMock func()
- validateFunc func(resp gen.GetNodeContainerByIDResponseObject)
+ validateFunc func(resp gen.GetNodeContainerDockerByIDResponseObject)
}{
{
name: "success",
- request: gen.GetNodeContainerByIDRequestObject{
+ request: gen.GetNodeContainerDockerByIDRequestObject{
Hostname: "server1",
Id: "abc123",
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerInspect(
+ QueryDockerInspect(
gomock.Any(),
"server1",
"abc123",
@@ -107,8 +107,8 @@ func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByID() {
}`),
}, nil)
},
- validateFunc: func(resp gen.GetNodeContainerByIDResponseObject) {
- r, ok := resp.(gen.GetNodeContainerByID200JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerByIDResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDockerByID200JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -123,13 +123,13 @@ func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByID() {
},
{
name: "validation error empty hostname",
- request: gen.GetNodeContainerByIDRequestObject{
+ request: gen.GetNodeContainerDockerByIDRequestObject{
Hostname: "",
Id: "abc123",
},
setupMock: func() {},
- validateFunc: func(resp gen.GetNodeContainerByIDResponseObject) {
- r, ok := resp.(gen.GetNodeContainerByID400JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerByIDResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDockerByID400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -137,21 +137,21 @@ func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByID() {
},
{
name: "job client error",
- request: gen.GetNodeContainerByIDRequestObject{
+ request: gen.GetNodeContainerDockerByIDRequestObject{
Hostname: "server1",
Id: "abc123",
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerInspect(
+ QueryDockerInspect(
gomock.Any(),
"server1",
"abc123",
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.GetNodeContainerByIDResponseObject) {
- _, ok := resp.(gen.GetNodeContainerByID500JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerByIDResponseObject) {
+ _, ok := resp.(gen.GetNodeContainerDockerByID500JSONResponse)
s.True(ok)
},
},
@@ -161,14 +161,14 @@ func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByID() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.GetNodeContainerByID(s.ctx, tt.request)
+ resp, err := s.handler.GetNodeContainerDockerByID(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByIDValidationHTTP() {
+func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerDockerByIDValidationHTTP() {
tests := []struct {
name string
path string
@@ -178,11 +178,11 @@ func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByIDValidationHTTP
}{
{
name: "when valid request",
- path: "/node/server1/container/abc123",
+ path: "/node/server1/container/docker/abc123",
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- QueryContainerInspect(gomock.Any(), "server1", "abc123").
+ QueryDockerInspect(gomock.Any(), "server1", "abc123").
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -197,7 +197,7 @@ func (s *ContainerInspectPublicTestSuite) TestGetNodeContainerByIDValidationHTTP
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container/abc123",
+ path: "/node/nonexistent/container/docker/abc123",
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
},
diff --git a/internal/api/container/container_list.go b/internal/api/docker/container_list.go
similarity index 77%
rename from internal/api/container/container_list.go
rename to internal/api/docker/container_list.go
index c5ced0c9..b4e4dbb4 100644
--- a/internal/api/container/container_list.go
+++ b/internal/api/docker/container_list.go
@@ -27,25 +27,25 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/validation"
)
-// GetNodeContainer lists containers on a target node.
-func (s *Container) GetNodeContainer(
+// GetNodeContainerDocker lists containers on a target node.
+func (s *Container) GetNodeContainerDocker(
ctx context.Context,
- request gen.GetNodeContainerRequestObject,
-) (gen.GetNodeContainerResponseObject, error) {
+ request gen.GetNodeContainerDockerRequestObject,
+) (gen.GetNodeContainerDockerResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.GetNodeContainer400JSONResponse{Error: &errMsg}, nil
+ return gen.GetNodeContainerDocker400JSONResponse{Error: &errMsg}, nil
}
if errMsg, ok := validation.Struct(request.Params); !ok {
- return gen.GetNodeContainer400JSONResponse{Error: &errMsg}, nil
+ return gen.GetNodeContainerDocker400JSONResponse{Error: &errMsg}, nil
}
- data := &job.ContainerListData{}
+ data := &job.DockerListData{}
if request.Params.State != nil {
data.State = string(*request.Params.State)
}
@@ -60,10 +60,10 @@ func (s *Container) GetNodeContainer(
slog.String("state", data.State),
)
- resp, err := s.JobClient.QueryContainerList(ctx, hostname, data)
+ resp, err := s.JobClient.QueryDockerList(ctx, hostname, data)
if err != nil {
errMsg := err.Error()
- return gen.GetNodeContainer500JSONResponse{Error: &errMsg}, nil
+ return gen.GetNodeContainerDocker500JSONResponse{Error: &errMsg}, nil
}
var containers []struct {
@@ -77,14 +77,14 @@ func (s *Container) GetNodeContainer(
_ = json.Unmarshal(resp.Data, &containers)
}
- var summaries []gen.ContainerSummary
+ var summaries []gen.DockerSummary
for _, c := range containers {
id := c.ID
name := c.Name
image := c.Image
state := c.State
created := c.Created
- summaries = append(summaries, gen.ContainerSummary{
+ summaries = append(summaries, gen.DockerSummary{
Id: &id,
Name: &name,
Image: &image,
@@ -96,9 +96,9 @@ func (s *Container) GetNodeContainer(
jobUUID := uuid.MustParse(resp.JobID)
changed := resp.Changed
- return gen.GetNodeContainer200JSONResponse{
+ return gen.GetNodeContainerDocker200JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerListItem{
+ Results: []gen.DockerListItem{
{
Hostname: resp.Hostname,
Containers: &summaries,
diff --git a/internal/api/container/container_list_public_test.go b/internal/api/docker/container_list_public_test.go
similarity index 76%
rename from internal/api/container/container_list_public_test.go
rename to internal/api/docker/container_list_public_test.go
index df7dcc0b..9f251bdb 100644
--- a/internal/api/container/container_list_public_test.go
+++ b/internal/api/docker/container_list_public_test.go
@@ -34,8 +34,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -75,26 +75,26 @@ func (s *ContainerListPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
+func (s *ContainerListPublicTestSuite) TestGetNodeContainerDocker() {
stateAll := gen.All
tests := []struct {
name string
- request gen.GetNodeContainerRequestObject
+ request gen.GetNodeContainerDockerRequestObject
setupMock func()
- validateFunc func(resp gen.GetNodeContainerResponseObject)
+ validateFunc func(resp gen.GetNodeContainerDockerResponseObject)
}{
{
name: "success",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "server1",
- Params: gen.GetNodeContainerParams{
+ Params: gen.GetNodeContainerDockerParams{
State: &stateAll,
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerList(
+ QueryDockerList(
gomock.Any(),
"server1",
gomock.Any(),
@@ -107,8 +107,8 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
),
}, nil)
},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- r, ok := resp.(gen.GetNodeContainer200JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDocker200JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -121,13 +121,13 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
},
{
name: "validation error empty hostname",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "",
- Params: gen.GetNodeContainerParams{},
+ Params: gen.GetNodeContainerDockerParams{},
},
setupMock: func() {},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- r, ok := resp.(gen.GetNodeContainer400JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDocker400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -135,15 +135,15 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
},
{
name: "validation error invalid limit",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "server1",
- Params: gen.GetNodeContainerParams{
+ Params: gen.GetNodeContainerDockerParams{
Limit: intPtr(0),
},
},
setupMock: func() {},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- r, ok := resp.(gen.GetNodeContainer400JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDocker400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "Limit")
@@ -151,16 +151,16 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
},
{
name: "success with limit param",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "server1",
- Params: gen.GetNodeContainerParams{
+ Params: gen.GetNodeContainerDockerParams{
State: &stateAll,
Limit: intPtr(5),
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerList(
+ QueryDockerList(
gomock.Any(),
"server1",
gomock.Any(),
@@ -173,8 +173,8 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
),
}, nil)
},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- r, ok := resp.(gen.GetNodeContainer200JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDocker200JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -188,15 +188,15 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
},
{
name: "success with nil response data",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "server1",
- Params: gen.GetNodeContainerParams{
+ Params: gen.GetNodeContainerDockerParams{
State: &stateAll,
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerList(
+ QueryDockerList(
gomock.Any(),
"server1",
gomock.Any(),
@@ -207,8 +207,8 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
Data: nil,
}, nil)
},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- r, ok := resp.(gen.GetNodeContainer200JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDocker200JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -218,15 +218,15 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
},
{
name: "success with empty created field",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "server1",
- Params: gen.GetNodeContainerParams{
+ Params: gen.GetNodeContainerDockerParams{
State: &stateAll,
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerList(
+ QueryDockerList(
gomock.Any(),
"server1",
gomock.Any(),
@@ -239,8 +239,8 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
),
}, nil)
},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- r, ok := resp.(gen.GetNodeContainer200JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ r, ok := resp.(gen.GetNodeContainerDocker200JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Require().NotNil(r.Results[0].Containers)
@@ -252,21 +252,21 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
},
{
name: "job client error",
- request: gen.GetNodeContainerRequestObject{
+ request: gen.GetNodeContainerDockerRequestObject{
Hostname: "server1",
- Params: gen.GetNodeContainerParams{},
+ Params: gen.GetNodeContainerDockerParams{},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- QueryContainerList(
+ QueryDockerList(
gomock.Any(),
"server1",
gomock.Any(),
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.GetNodeContainerResponseObject) {
- _, ok := resp.(gen.GetNodeContainer500JSONResponse)
+ validateFunc: func(resp gen.GetNodeContainerDockerResponseObject) {
+ _, ok := resp.(gen.GetNodeContainerDocker500JSONResponse)
s.True(ok)
},
},
@@ -276,14 +276,14 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainer() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.GetNodeContainer(s.ctx, tt.request)
+ resp, err := s.handler.GetNodeContainerDocker(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerListPublicTestSuite) TestGetNodeContainerValidationHTTP() {
+func (s *ContainerListPublicTestSuite) TestGetNodeContainerDockerValidationHTTP() {
tests := []struct {
name string
path string
@@ -293,11 +293,11 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainerValidationHTTP() {
}{
{
name: "when valid request",
- path: "/node/server1/container",
+ path: "/node/server1/container/docker",
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- QueryContainerList(gomock.Any(), "server1", gomock.Any()).
+ QueryDockerList(gomock.Any(), "server1", gomock.Any()).
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -310,7 +310,7 @@ func (s *ContainerListPublicTestSuite) TestGetNodeContainerValidationHTTP() {
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container",
+ path: "/node/nonexistent/container/docker",
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
},
diff --git a/internal/api/container/container_pull.go b/internal/api/docker/container_pull.go
similarity index 76%
rename from internal/api/container/container_pull.go
rename to internal/api/docker/container_pull.go
index 079c0ca6..f42963c6 100644
--- a/internal/api/container/container_pull.go
+++ b/internal/api/docker/container_pull.go
@@ -27,25 +27,25 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/validation"
)
-// PostNodeContainerPull pulls a container image on a target node.
-func (s *Container) PostNodeContainerPull(
+// PostNodeContainerDockerPull pulls a container image on a target node.
+func (s *Container) PostNodeContainerDockerPull(
ctx context.Context,
- request gen.PostNodeContainerPullRequestObject,
-) (gen.PostNodeContainerPullResponseObject, error) {
+ request gen.PostNodeContainerDockerPullRequestObject,
+) (gen.PostNodeContainerDockerPullResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.PostNodeContainerPull400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerPull400JSONResponse{Error: &errMsg}, nil
}
if errMsg, ok := validation.Struct(request.Body); !ok {
- return gen.PostNodeContainerPull400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerPull400JSONResponse{Error: &errMsg}, nil
}
- data := &job.ContainerPullData{
+ data := &job.DockerPullData{
Image: request.Body.Image,
}
@@ -56,10 +56,10 @@ func (s *Container) PostNodeContainerPull(
slog.String("image", data.Image),
)
- resp, err := s.JobClient.ModifyContainerPull(ctx, hostname, data)
+ resp, err := s.JobClient.ModifyDockerPull(ctx, hostname, data)
if err != nil {
errMsg := err.Error()
- return gen.PostNodeContainerPull500JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerPull500JSONResponse{Error: &errMsg}, nil
}
var pullResult struct {
@@ -74,9 +74,9 @@ func (s *Container) PostNodeContainerPull(
jobUUID := uuid.MustParse(resp.JobID)
changed := resp.Changed
- return gen.PostNodeContainerPull202JSONResponse{
+ return gen.PostNodeContainerDockerPull202JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerPullResultItem{
+ Results: []gen.DockerPullResultItem{
{
Hostname: resp.Hostname,
ImageId: stringPtrOrNil(pullResult.ImageID),
diff --git a/internal/api/container/container_pull_public_test.go b/internal/api/docker/container_pull_public_test.go
similarity index 78%
rename from internal/api/container/container_pull_public_test.go
rename to internal/api/docker/container_pull_public_test.go
index 698385b5..0293017f 100644
--- a/internal/api/container/container_pull_public_test.go
+++ b/internal/api/docker/container_pull_public_test.go
@@ -35,8 +35,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -76,24 +76,24 @@ func (s *ContainerPullPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPull() {
+func (s *ContainerPullPublicTestSuite) TestPostNodeContainerDockerPull() {
tests := []struct {
name string
- request gen.PostNodeContainerPullRequestObject
+ request gen.PostNodeContainerDockerPullRequestObject
setupMock func()
- validateFunc func(resp gen.PostNodeContainerPullResponseObject)
+ validateFunc func(resp gen.PostNodeContainerDockerPullResponseObject)
}{
{
name: "success",
- request: gen.PostNodeContainerPullRequestObject{
+ request: gen.PostNodeContainerDockerPullRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerPullJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerPullJSONRequestBody{
Image: "nginx:latest",
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerPull(
+ ModifyDockerPull(
gomock.Any(),
"server1",
gomock.Any(),
@@ -107,8 +107,8 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPull() {
),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerPullResponseObject) {
- r, ok := resp.(gen.PostNodeContainerPull202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerPullResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerPull202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -124,15 +124,15 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPull() {
},
{
name: "validation error empty hostname",
- request: gen.PostNodeContainerPullRequestObject{
+ request: gen.PostNodeContainerDockerPullRequestObject{
Hostname: "",
- Body: &gen.PostNodeContainerPullJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerPullJSONRequestBody{
Image: "nginx:latest",
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerPullResponseObject) {
- r, ok := resp.(gen.PostNodeContainerPull400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerPullResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerPull400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -140,38 +140,38 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPull() {
},
{
name: "body validation error empty image",
- request: gen.PostNodeContainerPullRequestObject{
+ request: gen.PostNodeContainerDockerPullRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerPullJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerPullJSONRequestBody{
Image: "",
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerPullResponseObject) {
- r, ok := resp.(gen.PostNodeContainerPull400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerPullResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerPull400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
},
},
{
name: "job client error",
- request: gen.PostNodeContainerPullRequestObject{
+ request: gen.PostNodeContainerDockerPullRequestObject{
Hostname: "server1",
- Body: &gen.PostNodeContainerPullJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerPullJSONRequestBody{
Image: "nginx:latest",
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerPull(
+ ModifyDockerPull(
gomock.Any(),
"server1",
gomock.Any(),
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.PostNodeContainerPullResponseObject) {
- _, ok := resp.(gen.PostNodeContainerPull500JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerPullResponseObject) {
+ _, ok := resp.(gen.PostNodeContainerDockerPull500JSONResponse)
s.True(ok)
},
},
@@ -181,14 +181,14 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPull() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.PostNodeContainerPull(s.ctx, tt.request)
+ resp, err := s.handler.PostNodeContainerDockerPull(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPullValidationHTTP() {
+func (s *ContainerPullPublicTestSuite) TestPostNodeContainerDockerPullValidationHTTP() {
tests := []struct {
name string
path string
@@ -199,12 +199,12 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPullValidationHTTP()
}{
{
name: "when valid request",
- path: "/node/server1/container/pull",
+ path: "/node/server1/container/docker/pull",
body: `{"image":"nginx:latest"}`,
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- ModifyContainerPull(gomock.Any(), "server1", gomock.Any()).
+ ModifyDockerPull(gomock.Any(), "server1", gomock.Any()).
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -220,7 +220,7 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPullValidationHTTP()
},
{
name: "when missing image",
- path: "/node/server1/container/pull",
+ path: "/node/server1/container/docker/pull",
body: `{}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
@@ -230,7 +230,7 @@ func (s *ContainerPullPublicTestSuite) TestPostNodeContainerPullValidationHTTP()
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container/pull",
+ path: "/node/nonexistent/container/docker/pull",
body: `{"image":"nginx:latest"}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
diff --git a/internal/api/container/container_remove.go b/internal/api/docker/container_remove.go
similarity index 73%
rename from internal/api/container/container_remove.go
rename to internal/api/docker/container_remove.go
index 7848f630..e141d924 100644
--- a/internal/api/container/container_remove.go
+++ b/internal/api/docker/container_remove.go
@@ -26,23 +26,23 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job"
)
-// DeleteNodeContainerByID removes a container from a target node.
-func (s *Container) DeleteNodeContainerByID(
+// DeleteNodeContainerDockerByID removes a container from a target node.
+func (s *Container) DeleteNodeContainerDockerByID(
ctx context.Context,
- request gen.DeleteNodeContainerByIDRequestObject,
-) (gen.DeleteNodeContainerByIDResponseObject, error) {
+ request gen.DeleteNodeContainerDockerByIDRequestObject,
+) (gen.DeleteNodeContainerDockerByIDResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.DeleteNodeContainerByID400JSONResponse{Error: &errMsg}, nil
+ return gen.DeleteNodeContainerDockerByID400JSONResponse{Error: &errMsg}, nil
}
hostname := request.Hostname
id := request.Id
- data := &job.ContainerRemoveData{}
+ data := &job.DockerRemoveData{}
if request.Params.Force != nil {
data.Force = *request.Params.Force
}
@@ -53,19 +53,19 @@ func (s *Container) DeleteNodeContainerByID(
slog.Bool("force", data.Force),
)
- resp, err := s.JobClient.ModifyContainerRemove(ctx, hostname, id, data)
+ resp, err := s.JobClient.ModifyDockerRemove(ctx, hostname, id, data)
if err != nil {
errMsg := err.Error()
- return gen.DeleteNodeContainerByID500JSONResponse{Error: &errMsg}, nil
+ return gen.DeleteNodeContainerDockerByID500JSONResponse{Error: &errMsg}, nil
}
jobUUID := uuid.MustParse(resp.JobID)
changed := resp.Changed
msg := "container removed"
- return gen.DeleteNodeContainerByID202JSONResponse{
+ return gen.DeleteNodeContainerDockerByID202JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerActionResultItem{
+ Results: []gen.DockerActionResultItem{
{
Hostname: resp.Hostname,
Id: &id,
diff --git a/internal/api/container/container_remove_public_test.go b/internal/api/docker/container_remove_public_test.go
similarity index 78%
rename from internal/api/container/container_remove_public_test.go
rename to internal/api/docker/container_remove_public_test.go
index d52eade4..490ca6df 100644
--- a/internal/api/container/container_remove_public_test.go
+++ b/internal/api/docker/container_remove_public_test.go
@@ -33,8 +33,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -74,23 +74,23 @@ func (s *ContainerRemovePublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
+func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerDockerByID() {
tests := []struct {
name string
- request gen.DeleteNodeContainerByIDRequestObject
+ request gen.DeleteNodeContainerDockerByIDRequestObject
setupMock func()
- validateFunc func(resp gen.DeleteNodeContainerByIDResponseObject)
+ validateFunc func(resp gen.DeleteNodeContainerDockerByIDResponseObject)
}{
{
name: "success",
- request: gen.DeleteNodeContainerByIDRequestObject{
+ request: gen.DeleteNodeContainerDockerByIDRequestObject{
Hostname: "server1",
Id: "abc123",
- Params: gen.DeleteNodeContainerByIDParams{},
+ Params: gen.DeleteNodeContainerDockerByIDParams{},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerRemove(
+ ModifyDockerRemove(
gomock.Any(),
"server1",
"abc123",
@@ -102,8 +102,8 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
Changed: boolPtr(true),
}, nil)
},
- validateFunc: func(resp gen.DeleteNodeContainerByIDResponseObject) {
- r, ok := resp.(gen.DeleteNodeContainerByID202JSONResponse)
+ validateFunc: func(resp gen.DeleteNodeContainerDockerByIDResponseObject) {
+ r, ok := resp.(gen.DeleteNodeContainerDockerByID202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -117,14 +117,14 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
},
{
name: "success with force",
- request: gen.DeleteNodeContainerByIDRequestObject{
+ request: gen.DeleteNodeContainerDockerByIDRequestObject{
Hostname: "server1",
Id: "abc123",
- Params: gen.DeleteNodeContainerByIDParams{Force: boolPtr(true)},
+ Params: gen.DeleteNodeContainerDockerByIDParams{Force: boolPtr(true)},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerRemove(
+ ModifyDockerRemove(
gomock.Any(),
"server1",
"abc123",
@@ -136,22 +136,22 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
Changed: boolPtr(true),
}, nil)
},
- validateFunc: func(resp gen.DeleteNodeContainerByIDResponseObject) {
- r, ok := resp.(gen.DeleteNodeContainerByID202JSONResponse)
+ validateFunc: func(resp gen.DeleteNodeContainerDockerByIDResponseObject) {
+ r, ok := resp.(gen.DeleteNodeContainerDockerByID202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
},
},
{
name: "validation error empty hostname",
- request: gen.DeleteNodeContainerByIDRequestObject{
+ request: gen.DeleteNodeContainerDockerByIDRequestObject{
Hostname: "",
Id: "abc123",
- Params: gen.DeleteNodeContainerByIDParams{},
+ Params: gen.DeleteNodeContainerDockerByIDParams{},
},
setupMock: func() {},
- validateFunc: func(resp gen.DeleteNodeContainerByIDResponseObject) {
- r, ok := resp.(gen.DeleteNodeContainerByID400JSONResponse)
+ validateFunc: func(resp gen.DeleteNodeContainerDockerByIDResponseObject) {
+ r, ok := resp.(gen.DeleteNodeContainerDockerByID400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -159,14 +159,14 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
},
{
name: "job client error",
- request: gen.DeleteNodeContainerByIDRequestObject{
+ request: gen.DeleteNodeContainerDockerByIDRequestObject{
Hostname: "server1",
Id: "abc123",
- Params: gen.DeleteNodeContainerByIDParams{},
+ Params: gen.DeleteNodeContainerDockerByIDParams{},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerRemove(
+ ModifyDockerRemove(
gomock.Any(),
"server1",
"abc123",
@@ -174,8 +174,8 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.DeleteNodeContainerByIDResponseObject) {
- _, ok := resp.(gen.DeleteNodeContainerByID500JSONResponse)
+ validateFunc: func(resp gen.DeleteNodeContainerDockerByIDResponseObject) {
+ _, ok := resp.(gen.DeleteNodeContainerDockerByID500JSONResponse)
s.True(ok)
},
},
@@ -185,14 +185,14 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByID() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.DeleteNodeContainerByID(s.ctx, tt.request)
+ resp, err := s.handler.DeleteNodeContainerDockerByID(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByIDValidationHTTP() {
+func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerDockerByIDValidationHTTP() {
tests := []struct {
name string
path string
@@ -202,11 +202,11 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByIDValidationHT
}{
{
name: "when valid request",
- path: "/node/server1/container/abc123",
+ path: "/node/server1/container/docker/abc123",
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- ModifyContainerRemove(gomock.Any(), "server1", "abc123", gomock.Any()).
+ ModifyDockerRemove(gomock.Any(), "server1", "abc123", gomock.Any()).
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -219,7 +219,7 @@ func (s *ContainerRemovePublicTestSuite) TestDeleteNodeContainerByIDValidationHT
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container/abc123",
+ path: "/node/nonexistent/container/docker/abc123",
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
},
diff --git a/internal/api/container/container_start.go b/internal/api/docker/container_start.go
similarity index 73%
rename from internal/api/container/container_start.go
rename to internal/api/docker/container_start.go
index 5d010b92..b2c50a84 100644
--- a/internal/api/container/container_start.go
+++ b/internal/api/docker/container_start.go
@@ -26,16 +26,16 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
)
-// PostNodeContainerStart starts a container on a target node.
-func (s *Container) PostNodeContainerStart(
+// PostNodeContainerDockerStart starts a container on a target node.
+func (s *Container) PostNodeContainerDockerStart(
ctx context.Context,
- request gen.PostNodeContainerStartRequestObject,
-) (gen.PostNodeContainerStartResponseObject, error) {
+ request gen.PostNodeContainerDockerStartRequestObject,
+) (gen.PostNodeContainerDockerStartResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.PostNodeContainerStart400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerStart400JSONResponse{Error: &errMsg}, nil
}
hostname := request.Hostname
@@ -46,19 +46,19 @@ func (s *Container) PostNodeContainerStart(
slog.String("id", id),
)
- resp, err := s.JobClient.ModifyContainerStart(ctx, hostname, id)
+ resp, err := s.JobClient.ModifyDockerStart(ctx, hostname, id)
if err != nil {
errMsg := err.Error()
- return gen.PostNodeContainerStart500JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerStart500JSONResponse{Error: &errMsg}, nil
}
jobUUID := uuid.MustParse(resp.JobID)
changed := resp.Changed
msg := "container started"
- return gen.PostNodeContainerStart202JSONResponse{
+ return gen.PostNodeContainerDockerStart202JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerActionResultItem{
+ Results: []gen.DockerActionResultItem{
{
Hostname: resp.Hostname,
Id: &id,
diff --git a/internal/api/container/container_start_public_test.go b/internal/api/docker/container_start_public_test.go
similarity index 80%
rename from internal/api/container/container_start_public_test.go
rename to internal/api/docker/container_start_public_test.go
index 5cabeb55..b48bc9c7 100644
--- a/internal/api/container/container_start_public_test.go
+++ b/internal/api/docker/container_start_public_test.go
@@ -33,8 +33,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -74,22 +74,22 @@ func (s *ContainerStartPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStart() {
+func (s *ContainerStartPublicTestSuite) TestPostNodeContainerDockerStart() {
tests := []struct {
name string
- request gen.PostNodeContainerStartRequestObject
+ request gen.PostNodeContainerDockerStartRequestObject
setupMock func()
- validateFunc func(resp gen.PostNodeContainerStartResponseObject)
+ validateFunc func(resp gen.PostNodeContainerDockerStartResponseObject)
}{
{
name: "success",
- request: gen.PostNodeContainerStartRequestObject{
+ request: gen.PostNodeContainerDockerStartRequestObject{
Hostname: "server1",
Id: "abc123",
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerStart(
+ ModifyDockerStart(
gomock.Any(),
"server1",
"abc123",
@@ -100,8 +100,8 @@ func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStart() {
Changed: boolPtr(true),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerStartResponseObject) {
- r, ok := resp.(gen.PostNodeContainerStart202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStartResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerStart202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -115,13 +115,13 @@ func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStart() {
},
{
name: "validation error empty hostname",
- request: gen.PostNodeContainerStartRequestObject{
+ request: gen.PostNodeContainerDockerStartRequestObject{
Hostname: "",
Id: "abc123",
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerStartResponseObject) {
- r, ok := resp.(gen.PostNodeContainerStart400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStartResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerStart400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -129,21 +129,21 @@ func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStart() {
},
{
name: "job client error",
- request: gen.PostNodeContainerStartRequestObject{
+ request: gen.PostNodeContainerDockerStartRequestObject{
Hostname: "server1",
Id: "abc123",
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerStart(
+ ModifyDockerStart(
gomock.Any(),
"server1",
"abc123",
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.PostNodeContainerStartResponseObject) {
- _, ok := resp.(gen.PostNodeContainerStart500JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStartResponseObject) {
+ _, ok := resp.(gen.PostNodeContainerDockerStart500JSONResponse)
s.True(ok)
},
},
@@ -153,14 +153,14 @@ func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStart() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.PostNodeContainerStart(s.ctx, tt.request)
+ resp, err := s.handler.PostNodeContainerDockerStart(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStartValidationHTTP() {
+func (s *ContainerStartPublicTestSuite) TestPostNodeContainerDockerStartValidationHTTP() {
tests := []struct {
name string
path string
@@ -170,11 +170,11 @@ func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStartValidationHTTP
}{
{
name: "when valid request",
- path: "/node/server1/container/abc123/start",
+ path: "/node/server1/container/docker/abc123/start",
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- ModifyContainerStart(gomock.Any(), "server1", "abc123").
+ ModifyDockerStart(gomock.Any(), "server1", "abc123").
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -187,7 +187,7 @@ func (s *ContainerStartPublicTestSuite) TestPostNodeContainerStartValidationHTTP
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container/abc123/start",
+ path: "/node/nonexistent/container/docker/abc123/start",
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
},
diff --git a/internal/api/container/container_stop.go b/internal/api/docker/container_stop.go
similarity index 73%
rename from internal/api/container/container_stop.go
rename to internal/api/docker/container_stop.go
index fd653d6c..f454f46e 100644
--- a/internal/api/container/container_stop.go
+++ b/internal/api/docker/container_stop.go
@@ -26,30 +26,30 @@ import (
"github.com/google/uuid"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/job"
"github.com/retr0h/osapi/internal/validation"
)
-// PostNodeContainerStop stops a container on a target node.
-func (s *Container) PostNodeContainerStop(
+// PostNodeContainerDockerStop stops a container on a target node.
+func (s *Container) PostNodeContainerDockerStop(
ctx context.Context,
- request gen.PostNodeContainerStopRequestObject,
-) (gen.PostNodeContainerStopResponseObject, error) {
+ request gen.PostNodeContainerDockerStopRequestObject,
+) (gen.PostNodeContainerDockerStopResponseObject, error) {
if errMsg, ok := validateHostname(request.Hostname); !ok {
- return gen.PostNodeContainerStop400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerStop400JSONResponse{Error: &errMsg}, nil
}
if request.Body != nil {
if errMsg, ok := validation.Struct(request.Body); !ok {
- return gen.PostNodeContainerStop400JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerStop400JSONResponse{Error: &errMsg}, nil
}
}
hostname := request.Hostname
id := request.Id
- data := &job.ContainerStopData{}
+ data := &job.DockerStopData{}
if request.Body != nil && request.Body.Timeout != nil {
data.Timeout = request.Body.Timeout
}
@@ -59,19 +59,19 @@ func (s *Container) PostNodeContainerStop(
slog.String("id", id),
)
- resp, err := s.JobClient.ModifyContainerStop(ctx, hostname, id, data)
+ resp, err := s.JobClient.ModifyDockerStop(ctx, hostname, id, data)
if err != nil {
errMsg := err.Error()
- return gen.PostNodeContainerStop500JSONResponse{Error: &errMsg}, nil
+ return gen.PostNodeContainerDockerStop500JSONResponse{Error: &errMsg}, nil
}
jobUUID := uuid.MustParse(resp.JobID)
changed := resp.Changed
msg := "container stopped"
- return gen.PostNodeContainerStop202JSONResponse{
+ return gen.PostNodeContainerDockerStop202JSONResponse{
JobId: &jobUUID,
- Results: []gen.ContainerActionResultItem{
+ Results: []gen.DockerActionResultItem{
{
Hostname: resp.Hostname,
Id: &id,
diff --git a/internal/api/container/container_stop_public_test.go b/internal/api/docker/container_stop_public_test.go
similarity index 77%
rename from internal/api/container/container_stop_public_test.go
rename to internal/api/docker/container_stop_public_test.go
index 0b7d6bae..3c2427cf 100644
--- a/internal/api/container/container_stop_public_test.go
+++ b/internal/api/docker/container_stop_public_test.go
@@ -34,8 +34,8 @@ import (
"github.com/stretchr/testify/suite"
"github.com/retr0h/osapi/internal/api"
- apicontainer "github.com/retr0h/osapi/internal/api/container"
- "github.com/retr0h/osapi/internal/api/container/gen"
+ apicontainer "github.com/retr0h/osapi/internal/api/docker"
+ "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/config"
"github.com/retr0h/osapi/internal/job"
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
@@ -75,23 +75,23 @@ func (s *ContainerStopPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
+func (s *ContainerStopPublicTestSuite) TestPostNodeContainerDockerStop() {
tests := []struct {
name string
- request gen.PostNodeContainerStopRequestObject
+ request gen.PostNodeContainerDockerStopRequestObject
setupMock func()
- validateFunc func(resp gen.PostNodeContainerStopResponseObject)
+ validateFunc func(resp gen.PostNodeContainerDockerStopResponseObject)
}{
{
name: "success without body",
- request: gen.PostNodeContainerStopRequestObject{
+ request: gen.PostNodeContainerDockerStopRequestObject{
Hostname: "server1",
Id: "abc123",
Body: nil,
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerStop(
+ ModifyDockerStop(
gomock.Any(),
"server1",
"abc123",
@@ -103,8 +103,8 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
Changed: boolPtr(true),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerStopResponseObject) {
- r, ok := resp.(gen.PostNodeContainerStop202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStopResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerStop202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -118,16 +118,16 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
},
{
name: "success with timeout",
- request: gen.PostNodeContainerStopRequestObject{
+ request: gen.PostNodeContainerDockerStopRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerStopJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerStopJSONRequestBody{
Timeout: intPtr(30),
},
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerStop(
+ ModifyDockerStop(
gomock.Any(),
"server1",
"abc123",
@@ -139,8 +139,8 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
Changed: boolPtr(true),
}, nil)
},
- validateFunc: func(resp gen.PostNodeContainerStopResponseObject) {
- r, ok := resp.(gen.PostNodeContainerStop202JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStopResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerStop202JSONResponse)
s.True(ok)
s.Require().Len(r.Results, 1)
s.Equal("agent1", r.Results[0].Hostname)
@@ -148,16 +148,16 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
},
{
name: "body validation error invalid timeout",
- request: gen.PostNodeContainerStopRequestObject{
+ request: gen.PostNodeContainerDockerStopRequestObject{
Hostname: "server1",
Id: "abc123",
- Body: &gen.PostNodeContainerStopJSONRequestBody{
+ Body: &gen.PostNodeContainerDockerStopJSONRequestBody{
Timeout: intPtr(999),
},
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerStopResponseObject) {
- r, ok := resp.(gen.PostNodeContainerStop400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStopResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerStop400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "Timeout")
@@ -165,13 +165,13 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
},
{
name: "validation error empty hostname",
- request: gen.PostNodeContainerStopRequestObject{
+ request: gen.PostNodeContainerDockerStopRequestObject{
Hostname: "",
Id: "abc123",
},
setupMock: func() {},
- validateFunc: func(resp gen.PostNodeContainerStopResponseObject) {
- r, ok := resp.(gen.PostNodeContainerStop400JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStopResponseObject) {
+ r, ok := resp.(gen.PostNodeContainerDockerStop400JSONResponse)
s.True(ok)
s.Require().NotNil(r.Error)
s.Contains(*r.Error, "required")
@@ -179,13 +179,13 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
},
{
name: "job client error",
- request: gen.PostNodeContainerStopRequestObject{
+ request: gen.PostNodeContainerDockerStopRequestObject{
Hostname: "server1",
Id: "abc123",
},
setupMock: func() {
s.mockJobClient.EXPECT().
- ModifyContainerStop(
+ ModifyDockerStop(
gomock.Any(),
"server1",
"abc123",
@@ -193,8 +193,8 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
).
Return(nil, assert.AnError)
},
- validateFunc: func(resp gen.PostNodeContainerStopResponseObject) {
- _, ok := resp.(gen.PostNodeContainerStop500JSONResponse)
+ validateFunc: func(resp gen.PostNodeContainerDockerStopResponseObject) {
+ _, ok := resp.(gen.PostNodeContainerDockerStop500JSONResponse)
s.True(ok)
},
},
@@ -204,14 +204,14 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStop() {
s.Run(tt.name, func() {
tt.setupMock()
- resp, err := s.handler.PostNodeContainerStop(s.ctx, tt.request)
+ resp, err := s.handler.PostNodeContainerDockerStop(s.ctx, tt.request)
s.NoError(err)
tt.validateFunc(resp)
})
}
}
-func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStopValidationHTTP() {
+func (s *ContainerStopPublicTestSuite) TestPostNodeContainerDockerStopValidationHTTP() {
tests := []struct {
name string
path string
@@ -222,12 +222,12 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStopValidationHTTP()
}{
{
name: "when valid request",
- path: "/node/server1/container/abc123/stop",
+ path: "/node/server1/container/docker/abc123/stop",
body: `{"timeout":10}`,
setupJobMock: func() *jobmocks.MockJobClient {
mock := jobmocks.NewMockJobClient(s.mockCtrl)
mock.EXPECT().
- ModifyContainerStop(gomock.Any(), "server1", "abc123", gomock.Any()).
+ ModifyDockerStop(gomock.Any(), "server1", "abc123", gomock.Any()).
Return(&job.Response{
JobID: "550e8400-e29b-41d4-a716-446655440000",
Hostname: "agent1",
@@ -240,7 +240,7 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStopValidationHTTP()
},
{
name: "when invalid timeout",
- path: "/node/server1/container/abc123/stop",
+ path: "/node/server1/container/docker/abc123/stop",
body: `{"timeout":999}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
@@ -250,7 +250,7 @@ func (s *ContainerStopPublicTestSuite) TestPostNodeContainerStopValidationHTTP()
},
{
name: "when target agent not found",
- path: "/node/nonexistent/container/abc123/stop",
+ path: "/node/nonexistent/container/docker/abc123/stop",
body: `{}`,
setupJobMock: func() *jobmocks.MockJobClient {
return jobmocks.NewMockJobClient(s.mockCtrl)
diff --git a/internal/api/container/convert.go b/internal/api/docker/convert.go
similarity index 100%
rename from internal/api/container/convert.go
rename to internal/api/docker/convert.go
diff --git a/internal/api/container/convert_test.go b/internal/api/docker/convert_test.go
similarity index 100%
rename from internal/api/container/convert_test.go
rename to internal/api/docker/convert_test.go
diff --git a/internal/api/container/gen/api.yaml b/internal/api/docker/gen/api.yaml
similarity index 87%
rename from internal/api/container/gen/api.yaml
rename to internal/api/docker/gen/api.yaml
index abecb3cd..130a46b8 100644
--- a/internal/api/container/gen/api.yaml
+++ b/internal/api/docker/gen/api.yaml
@@ -21,34 +21,34 @@
---
openapi: 3.0.0
info:
- title: Container Management API
+ title: Docker Management API
version: 1.0.0
tags:
- - name: container_operations
- x-displayName: Node/Container
- description: Container lifecycle operations on a target node.
- - name: container_exec
- x-displayName: Node/Container/Exec
+ - name: docker_operations
+ x-displayName: Node/Docker
+ description: Docker lifecycle operations on a target node.
+ - name: docker_exec
+ x-displayName: Node/Docker/Exec
description: Command execution inside containers on a target node.
- - name: container_image
- x-displayName: Node/Container/Image
- description: Container image operations on a target node.
+ - name: docker_image
+ x-displayName: Node/Docker/Image
+ description: Docker image operations on a target node.
paths:
- # ── Container lifecycle ─────────────────────────────────────
+ # ── Docker lifecycle ──────────────────────────────────────
- /node/{hostname}/container:
+ /node/{hostname}/container/docker:
post:
summary: Create a container
description: >
Create a new container on the target node. Returns a job ID
for tracking the asynchronous operation.
tags:
- - container_operations
- operationId: PostNodeContainer
+ - docker_operations
+ operationId: PostNodeContainerDocker
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
requestBody:
@@ -57,14 +57,14 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerCreateRequest'
+ $ref: '#/components/schemas/DockerCreateRequest'
responses:
'202':
description: Container creation accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerResultCollectionResponse'
+ $ref: '#/components/schemas/DockerResultCollectionResponse'
'400':
description: Invalid request payload.
content:
@@ -95,11 +95,11 @@ paths:
description: >
List containers on the target node, optionally filtered by state.
tags:
- - container_operations
- operationId: GetNodeContainer
+ - docker_operations
+ operationId: GetNodeContainerDocker
security:
- BearerAuth:
- - container:read
+ - docker:read
parameters:
- $ref: '#/components/parameters/Hostname'
- name: state
@@ -134,7 +134,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerListCollectionResponse'
+ $ref: '#/components/schemas/DockerListCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -160,27 +160,27 @@ paths:
schema:
$ref: '../../common/gen/api.yaml#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}:
+ /node/{hostname}/container/docker/{id}:
get:
summary: Inspect a container
description: >
Get detailed information about a specific container.
tags:
- - container_operations
- operationId: GetNodeContainerByID
+ - docker_operations
+ operationId: GetNodeContainerDockerByID
security:
- BearerAuth:
- - container:read
+ - docker:read
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
responses:
'200':
description: Container detail.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerDetailCollectionResponse'
+ $ref: '#/components/schemas/DockerDetailCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -218,14 +218,14 @@ paths:
Remove a container from the target node. Use the force query
parameter to remove a running container.
tags:
- - container_operations
- operationId: DeleteNodeContainerByID
+ - docker_operations
+ operationId: DeleteNodeContainerDockerByID
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
- name: force
in: query
required: false
@@ -242,7 +242,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerActionCollectionResponse'
+ $ref: '#/components/schemas/DockerActionCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -274,27 +274,27 @@ paths:
schema:
$ref: '../../common/gen/api.yaml#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}/start:
+ /node/{hostname}/container/docker/{id}/start:
post:
summary: Start a container
description: >
Start a stopped container on the target node.
tags:
- - container_operations
- operationId: PostNodeContainerStart
+ - docker_operations
+ operationId: PostNodeContainerDockerStart
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
responses:
'202':
description: Container start accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerActionCollectionResponse'
+ $ref: '#/components/schemas/DockerActionCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -326,35 +326,35 @@ paths:
schema:
$ref: '../../common/gen/api.yaml#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}/stop:
+ /node/{hostname}/container/docker/{id}/stop:
post:
summary: Stop a container
description: >
Stop a running container on the target node. Optionally
specify a timeout before the container is killed.
tags:
- - container_operations
- operationId: PostNodeContainerStop
+ - docker_operations
+ operationId: PostNodeContainerDockerStop
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
requestBody:
description: Optional stop parameters.
required: false
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerStopRequest'
+ $ref: '#/components/schemas/DockerStopRequest'
responses:
'202':
description: Container stop accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerActionCollectionResponse'
+ $ref: '#/components/schemas/DockerActionCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -386,36 +386,36 @@ paths:
schema:
$ref: '../../common/gen/api.yaml#/components/schemas/ErrorResponse'
- # ── Container exec ──────────────────────────────────────────
+ # ── Docker exec ────────────────────────────────────────────
- /node/{hostname}/container/{id}/exec:
+ /node/{hostname}/container/docker/{id}/exec:
post:
summary: Execute a command in a container
description: >
Execute a command inside a running container on the target node.
tags:
- - container_exec
- operationId: PostNodeContainerExec
+ - docker_exec
+ operationId: PostNodeContainerDockerExec
security:
- BearerAuth:
- - container:execute
+ - docker:execute
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
requestBody:
description: The command to execute inside the container.
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerExecRequest'
+ $ref: '#/components/schemas/DockerExecRequest'
responses:
'202':
description: Container exec accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerExecCollectionResponse'
+ $ref: '#/components/schemas/DockerExecCollectionResponse'
'400':
description: Invalid request payload.
content:
@@ -447,19 +447,19 @@ paths:
schema:
$ref: '../../common/gen/api.yaml#/components/schemas/ErrorResponse'
- # ── Container image ─────────────────────────────────────────
+ # ── Docker image ───────────────────────────────────────────
- /node/{hostname}/container/pull:
+ /node/{hostname}/container/docker/pull:
post:
summary: Pull a container image
description: >
Pull a container image on the target node.
tags:
- - container_image
- operationId: PostNodeContainerPull
+ - docker_image
+ operationId: PostNodeContainerDockerPull
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
requestBody:
@@ -468,14 +468,14 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerPullRequest'
+ $ref: '#/components/schemas/DockerPullRequest'
responses:
'202':
description: Image pull accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerPullCollectionResponse'
+ $ref: '#/components/schemas/DockerPullCollectionResponse'
'400':
description: Invalid request payload.
content:
@@ -521,7 +521,7 @@ components:
type: string
minLength: 1
- ContainerId:
+ DockerId:
name: id
in: path
required: true
@@ -551,7 +551,7 @@ components:
# ── Request schemas ───────────────────────────────────────
- ContainerCreateRequest:
+ DockerCreateRequest:
type: object
properties:
image:
@@ -599,7 +599,7 @@ components:
required:
- image
- ContainerStopRequest:
+ DockerStopRequest:
type: object
properties:
timeout:
@@ -613,7 +613,7 @@ components:
x-oapi-codegen-extra-tags:
validate: omitempty,min=0,max=300
- ContainerExecRequest:
+ DockerExecRequest:
type: object
properties:
command:
@@ -636,7 +636,7 @@ components:
required:
- command
- ContainerPullRequest:
+ DockerPullRequest:
type: object
properties:
image:
@@ -652,7 +652,7 @@ components:
# ── Response schemas ──────────────────────────────────────
- ContainerResponse:
+ DockerResponse:
type: object
description: Summary information about a container.
properties:
@@ -688,7 +688,7 @@ components:
required:
- hostname
- ContainerDetailResponse:
+ DockerDetailResponse:
type: object
description: Detailed information about a container.
properties:
@@ -750,7 +750,7 @@ components:
required:
- hostname
- ContainerActionResultItem:
+ DockerActionResultItem:
type: object
description: Result of a container lifecycle action.
properties:
@@ -773,7 +773,7 @@ components:
required:
- hostname
- ContainerExecResultItem:
+ DockerExecResultItem:
type: object
description: Result of a command execution inside a container.
properties:
@@ -798,7 +798,7 @@ components:
required:
- hostname
- ContainerPullResultItem:
+ DockerPullResultItem:
type: object
description: Result of an image pull operation.
properties:
@@ -826,7 +826,7 @@ components:
required:
- hostname
- ContainerListItem:
+ DockerListItem:
type: object
description: Container summary for list operations.
properties:
@@ -837,7 +837,7 @@ components:
type: array
description: List of containers on this agent.
items:
- $ref: '#/components/schemas/ContainerSummary'
+ $ref: '#/components/schemas/DockerSummary'
changed:
type: boolean
description: Whether the operation modified system state.
@@ -847,7 +847,7 @@ components:
required:
- hostname
- ContainerSummary:
+ DockerSummary:
type: object
description: Brief container summary.
properties:
@@ -874,7 +874,7 @@ components:
# ── Collection responses ──────────────────────────────────
- ContainerResultCollectionResponse:
+ DockerResultCollectionResponse:
type: object
properties:
job_id:
@@ -885,11 +885,11 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerResponse'
+ $ref: '#/components/schemas/DockerResponse'
required:
- results
- ContainerListCollectionResponse:
+ DockerListCollectionResponse:
type: object
properties:
job_id:
@@ -900,11 +900,11 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerListItem'
+ $ref: '#/components/schemas/DockerListItem'
required:
- results
- ContainerDetailCollectionResponse:
+ DockerDetailCollectionResponse:
type: object
properties:
job_id:
@@ -915,11 +915,11 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerDetailResponse'
+ $ref: '#/components/schemas/DockerDetailResponse'
required:
- results
- ContainerActionCollectionResponse:
+ DockerActionCollectionResponse:
type: object
properties:
job_id:
@@ -930,11 +930,11 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerActionResultItem'
+ $ref: '#/components/schemas/DockerActionResultItem'
required:
- results
- ContainerExecCollectionResponse:
+ DockerExecCollectionResponse:
type: object
properties:
job_id:
@@ -945,11 +945,11 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerExecResultItem'
+ $ref: '#/components/schemas/DockerExecResultItem'
required:
- results
- ContainerPullCollectionResponse:
+ DockerPullCollectionResponse:
type: object
properties:
job_id:
@@ -960,6 +960,6 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerPullResultItem'
+ $ref: '#/components/schemas/DockerPullResultItem'
required:
- results
diff --git a/internal/api/container/gen/cfg.yaml b/internal/api/docker/gen/cfg.yaml
similarity index 98%
rename from internal/api/container/gen/cfg.yaml
rename to internal/api/docker/gen/cfg.yaml
index 392eda5a..042895cb 100644
--- a/internal/api/container/gen/cfg.yaml
+++ b/internal/api/docker/gen/cfg.yaml
@@ -20,7 +20,7 @@
---
package: gen
-output: container.gen.go
+output: docker.gen.go
generate:
models: true
echo-server: true
diff --git a/internal/api/docker/gen/docker.gen.go b/internal/api/docker/gen/docker.gen.go
new file mode 100644
index 00000000..ab0371cd
--- /dev/null
+++ b/internal/api/docker/gen/docker.gen.go
@@ -0,0 +1,1351 @@
+// Package gen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT.
+package gen
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/runtime"
+ strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+ externalRef0 "github.com/retr0h/osapi/internal/api/common/gen"
+)
+
+const (
+ BearerAuthScopes = "BearerAuth.Scopes"
+)
+
+// Defines values for GetNodeContainerDockerParamsState.
+const (
+ All GetNodeContainerDockerParamsState = "all"
+ Running GetNodeContainerDockerParamsState = "running"
+ Stopped GetNodeContainerDockerParamsState = "stopped"
+)
+
+// DockerActionCollectionResponse defines model for DockerActionCollectionResponse.
+type DockerActionCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerActionResultItem `json:"results"`
+}
+
+// DockerActionResultItem Result of a container lifecycle action.
+type DockerActionResultItem struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+
+ // Id Container identifier.
+ Id *string `json:"id,omitempty"`
+
+ // Message Status message.
+ Message *string `json:"message,omitempty"`
+}
+
+// DockerCreateRequest defines model for DockerCreateRequest.
+type DockerCreateRequest struct {
+ // AutoStart Whether to start the container immediately after creation. Defaults to true.
+ AutoStart *bool `json:"auto_start,omitempty"`
+
+ // Command Command to run in the container.
+ Command *[]string `json:"command,omitempty"`
+
+ // Env Environment variables in KEY=VALUE format.
+ Env *[]string `json:"env,omitempty"`
+
+ // Image Container image reference (e.g., "nginx:latest").
+ Image string `json:"image" validate:"required,min=1"`
+
+ // Name Optional name for the container.
+ Name *string `json:"name,omitempty"`
+
+ // Ports Port mappings in host_port:container_port format.
+ Ports *[]string `json:"ports,omitempty"`
+
+ // Volumes Volume mounts in host_path:container_path format.
+ Volumes *[]string `json:"volumes,omitempty"`
+}
+
+// DockerDetailCollectionResponse defines model for DockerDetailCollectionResponse.
+type DockerDetailCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerDetailResponse `json:"results"`
+}
+
+// DockerDetailResponse Detailed information about a container.
+type DockerDetailResponse struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Created Container creation timestamp.
+ Created *string `json:"created,omitempty"`
+
+ // Env Environment variables.
+ Env *[]string `json:"env,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Health Health check status if configured.
+ Health *string `json:"health,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+
+ // Id Container identifier.
+ Id *string `json:"id,omitempty"`
+
+ // Image Image used by the container.
+ Image *string `json:"image,omitempty"`
+
+ // Mounts Volume mounts.
+ Mounts *[]string `json:"mounts,omitempty"`
+
+ // Name Container name.
+ Name *string `json:"name,omitempty"`
+
+ // NetworkSettings Network configuration.
+ NetworkSettings *map[string]string `json:"network_settings,omitempty"`
+
+ // Ports Port mappings.
+ Ports *[]string `json:"ports,omitempty"`
+
+ // State Current container state.
+ State *string `json:"state,omitempty"`
+}
+
+// DockerExecCollectionResponse defines model for DockerExecCollectionResponse.
+type DockerExecCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerExecResultItem `json:"results"`
+}
+
+// DockerExecRequest defines model for DockerExecRequest.
+type DockerExecRequest struct {
+ // Command Command to execute inside the container.
+ Command []string `json:"command" validate:"required,min=1"`
+
+ // Env Additional environment variables in KEY=VALUE format.
+ Env *[]string `json:"env,omitempty"`
+
+ // WorkingDir Working directory inside the container.
+ WorkingDir *string `json:"working_dir,omitempty"`
+}
+
+// DockerExecResultItem Result of a command execution inside a container.
+type DockerExecResultItem struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // ExitCode Exit code of the command.
+ ExitCode *int `json:"exit_code,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+
+ // Stderr Standard error output of the command.
+ Stderr *string `json:"stderr,omitempty"`
+
+ // Stdout Standard output of the command.
+ Stdout *string `json:"stdout,omitempty"`
+}
+
+// DockerListCollectionResponse defines model for DockerListCollectionResponse.
+type DockerListCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerListItem `json:"results"`
+}
+
+// DockerListItem Container summary for list operations.
+type DockerListItem struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Containers List of containers on this agent.
+ Containers *[]DockerSummary `json:"containers,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+}
+
+// DockerPullCollectionResponse defines model for DockerPullCollectionResponse.
+type DockerPullCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerPullResultItem `json:"results"`
+}
+
+// DockerPullRequest defines model for DockerPullRequest.
+type DockerPullRequest struct {
+ // Image Image reference to pull (e.g., "nginx:latest", "docker.io/library/alpine:3.18").
+ Image string `json:"image" validate:"required,min=1"`
+}
+
+// DockerPullResultItem Result of an image pull operation.
+type DockerPullResultItem struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+
+ // ImageId The pulled image ID.
+ ImageId *string `json:"image_id,omitempty"`
+
+ // Size Image size in bytes.
+ Size *int64 `json:"size,omitempty"`
+
+ // Tag The image tag that was pulled.
+ Tag *string `json:"tag,omitempty"`
+}
+
+// DockerResponse Summary information about a container.
+type DockerResponse struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Created Container creation timestamp.
+ Created *string `json:"created,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+
+ // Id Container identifier.
+ Id *string `json:"id,omitempty"`
+
+ // Image Image used by the container.
+ Image *string `json:"image,omitempty"`
+
+ // Name Container name.
+ Name *string `json:"name,omitempty"`
+
+ // State Current container state.
+ State *string `json:"state,omitempty"`
+}
+
+// DockerResultCollectionResponse defines model for DockerResultCollectionResponse.
+type DockerResultCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerResponse `json:"results"`
+}
+
+// DockerStopRequest defines model for DockerStopRequest.
+type DockerStopRequest struct {
+ // Timeout Seconds to wait before killing the container. Defaults to 10.
+ Timeout *int `json:"timeout,omitempty" validate:"omitempty,min=0,max=300"`
+}
+
+// DockerSummary Brief container summary.
+type DockerSummary struct {
+ // Created Container creation timestamp.
+ Created *string `json:"created,omitempty"`
+
+ // Id Container identifier.
+ Id *string `json:"id,omitempty"`
+
+ // Image Image used by the container.
+ Image *string `json:"image,omitempty"`
+
+ // Name Container name.
+ Name *string `json:"name,omitempty"`
+
+ // State Current container state.
+ State *string `json:"state,omitempty"`
+}
+
+// ErrorResponse defines model for ErrorResponse.
+type ErrorResponse = externalRef0.ErrorResponse
+
+// DockerId defines model for DockerId.
+type DockerId = string
+
+// Hostname defines model for Hostname.
+type Hostname = string
+
+// GetNodeContainerDockerParams defines parameters for GetNodeContainerDocker.
+type GetNodeContainerDockerParams struct {
+ // State Filter containers by state. Defaults to "all".
+ State *GetNodeContainerDockerParamsState `form:"state,omitempty" json:"state,omitempty" validate:"omitempty,oneof=running stopped all"`
+
+ // Limit Maximum number of containers to return.
+ Limit *int `form:"limit,omitempty" json:"limit,omitempty" validate:"omitempty,min=1,max=100"`
+}
+
+// GetNodeContainerDockerParamsState defines parameters for GetNodeContainerDocker.
+type GetNodeContainerDockerParamsState string
+
+// DeleteNodeContainerDockerByIDParams defines parameters for DeleteNodeContainerDockerByID.
+type DeleteNodeContainerDockerByIDParams struct {
+ // Force Force removal of a running container.
+ Force *bool `form:"force,omitempty" json:"force,omitempty" validate:"omitempty"`
+}
+
+// PostNodeContainerDockerJSONRequestBody defines body for PostNodeContainerDocker for application/json ContentType.
+type PostNodeContainerDockerJSONRequestBody = DockerCreateRequest
+
+// PostNodeContainerDockerPullJSONRequestBody defines body for PostNodeContainerDockerPull for application/json ContentType.
+type PostNodeContainerDockerPullJSONRequestBody = DockerPullRequest
+
+// PostNodeContainerDockerExecJSONRequestBody defines body for PostNodeContainerDockerExec for application/json ContentType.
+type PostNodeContainerDockerExecJSONRequestBody = DockerExecRequest
+
+// PostNodeContainerDockerStopJSONRequestBody defines body for PostNodeContainerDockerStop for application/json ContentType.
+type PostNodeContainerDockerStopJSONRequestBody = DockerStopRequest
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // List containers
+ // (GET /node/{hostname}/container/docker)
+ GetNodeContainerDocker(ctx echo.Context, hostname Hostname, params GetNodeContainerDockerParams) error
+ // Create a container
+ // (POST /node/{hostname}/container/docker)
+ PostNodeContainerDocker(ctx echo.Context, hostname Hostname) error
+ // Pull a container image
+ // (POST /node/{hostname}/container/docker/pull)
+ PostNodeContainerDockerPull(ctx echo.Context, hostname Hostname) error
+ // Remove a container
+ // (DELETE /node/{hostname}/container/docker/{id})
+ DeleteNodeContainerDockerByID(ctx echo.Context, hostname Hostname, id DockerId, params DeleteNodeContainerDockerByIDParams) error
+ // Inspect a container
+ // (GET /node/{hostname}/container/docker/{id})
+ GetNodeContainerDockerByID(ctx echo.Context, hostname Hostname, id DockerId) error
+ // Execute a command in a container
+ // (POST /node/{hostname}/container/docker/{id}/exec)
+ PostNodeContainerDockerExec(ctx echo.Context, hostname Hostname, id DockerId) error
+ // Start a container
+ // (POST /node/{hostname}/container/docker/{id}/start)
+ PostNodeContainerDockerStart(ctx echo.Context, hostname Hostname, id DockerId) error
+ // Stop a container
+ // (POST /node/{hostname}/container/docker/{id}/stop)
+ PostNodeContainerDockerStop(ctx echo.Context, hostname Hostname, id DockerId) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetNodeContainerDocker converts echo context to params.
+func (w *ServerInterfaceWrapper) GetNodeContainerDocker(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:read"})
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetNodeContainerDockerParams
+ // ------------- Optional query parameter "state" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "state", ctx.QueryParams(), ¶ms.State)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter state: %s", err))
+ }
+
+ // ------------- Optional query parameter "limit" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "limit", ctx.QueryParams(), ¶ms.Limit)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetNodeContainerDocker(ctx, hostname, params)
+ return err
+}
+
+// PostNodeContainerDocker converts echo context to params.
+func (w *ServerInterfaceWrapper) PostNodeContainerDocker(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:write"})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostNodeContainerDocker(ctx, hostname)
+ return err
+}
+
+// PostNodeContainerDockerPull converts echo context to params.
+func (w *ServerInterfaceWrapper) PostNodeContainerDockerPull(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:write"})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostNodeContainerDockerPull(ctx, hostname)
+ return err
+}
+
+// DeleteNodeContainerDockerByID converts echo context to params.
+func (w *ServerInterfaceWrapper) DeleteNodeContainerDockerByID(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ // ------------- Path parameter "id" -------------
+ var id DockerId
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:write"})
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params DeleteNodeContainerDockerByIDParams
+ // ------------- Optional query parameter "force" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "force", ctx.QueryParams(), ¶ms.Force)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter force: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.DeleteNodeContainerDockerByID(ctx, hostname, id, params)
+ return err
+}
+
+// GetNodeContainerDockerByID converts echo context to params.
+func (w *ServerInterfaceWrapper) GetNodeContainerDockerByID(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ // ------------- Path parameter "id" -------------
+ var id DockerId
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:read"})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetNodeContainerDockerByID(ctx, hostname, id)
+ return err
+}
+
+// PostNodeContainerDockerExec converts echo context to params.
+func (w *ServerInterfaceWrapper) PostNodeContainerDockerExec(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ // ------------- Path parameter "id" -------------
+ var id DockerId
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:execute"})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostNodeContainerDockerExec(ctx, hostname, id)
+ return err
+}
+
+// PostNodeContainerDockerStart converts echo context to params.
+func (w *ServerInterfaceWrapper) PostNodeContainerDockerStart(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ // ------------- Path parameter "id" -------------
+ var id DockerId
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:write"})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostNodeContainerDockerStart(ctx, hostname, id)
+ return err
+}
+
+// PostNodeContainerDockerStop converts echo context to params.
+func (w *ServerInterfaceWrapper) PostNodeContainerDockerStop(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "hostname" -------------
+ var hostname Hostname
+
+ err = runtime.BindStyledParameterWithOptions("simple", "hostname", ctx.Param("hostname"), &hostname, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hostname: %s", err))
+ }
+
+ // ------------- Path parameter "id" -------------
+ var id DockerId
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ ctx.Set(BearerAuthScopes, []string{"docker:write"})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostNodeContainerDockerStop(ctx, hostname, id)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithBaseURL(router, si, "")
+}
+
+// Registers handlers, and prepends BaseURL to the paths, so that the paths
+// can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(baseURL+"/node/:hostname/container/docker", wrapper.GetNodeContainerDocker)
+ router.POST(baseURL+"/node/:hostname/container/docker", wrapper.PostNodeContainerDocker)
+ router.POST(baseURL+"/node/:hostname/container/docker/pull", wrapper.PostNodeContainerDockerPull)
+ router.DELETE(baseURL+"/node/:hostname/container/docker/:id", wrapper.DeleteNodeContainerDockerByID)
+ router.GET(baseURL+"/node/:hostname/container/docker/:id", wrapper.GetNodeContainerDockerByID)
+ router.POST(baseURL+"/node/:hostname/container/docker/:id/exec", wrapper.PostNodeContainerDockerExec)
+ router.POST(baseURL+"/node/:hostname/container/docker/:id/start", wrapper.PostNodeContainerDockerStart)
+ router.POST(baseURL+"/node/:hostname/container/docker/:id/stop", wrapper.PostNodeContainerDockerStop)
+
+}
+
+type GetNodeContainerDockerRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Params GetNodeContainerDockerParams
+}
+
+type GetNodeContainerDockerResponseObject interface {
+ VisitGetNodeContainerDockerResponse(w http.ResponseWriter) error
+}
+
+type GetNodeContainerDocker200JSONResponse DockerListCollectionResponse
+
+func (response GetNodeContainerDocker200JSONResponse) VisitGetNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDocker400JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDocker400JSONResponse) VisitGetNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDocker401JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDocker401JSONResponse) VisitGetNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDocker403JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDocker403JSONResponse) VisitGetNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDocker500JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDocker500JSONResponse) VisitGetNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Body *PostNodeContainerDockerJSONRequestBody
+}
+
+type PostNodeContainerDockerResponseObject interface {
+ VisitPostNodeContainerDockerResponse(w http.ResponseWriter) error
+}
+
+type PostNodeContainerDocker202JSONResponse DockerResultCollectionResponse
+
+func (response PostNodeContainerDocker202JSONResponse) VisitPostNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(202)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDocker400JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDocker400JSONResponse) VisitPostNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDocker401JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDocker401JSONResponse) VisitPostNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDocker403JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDocker403JSONResponse) VisitPostNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDocker500JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDocker500JSONResponse) VisitPostNodeContainerDockerResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerPullRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Body *PostNodeContainerDockerPullJSONRequestBody
+}
+
+type PostNodeContainerDockerPullResponseObject interface {
+ VisitPostNodeContainerDockerPullResponse(w http.ResponseWriter) error
+}
+
+type PostNodeContainerDockerPull202JSONResponse DockerPullCollectionResponse
+
+func (response PostNodeContainerDockerPull202JSONResponse) VisitPostNodeContainerDockerPullResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(202)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerPull400JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerPull400JSONResponse) VisitPostNodeContainerDockerPullResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerPull401JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerPull401JSONResponse) VisitPostNodeContainerDockerPullResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerPull403JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerPull403JSONResponse) VisitPostNodeContainerDockerPullResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerPull500JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerPull500JSONResponse) VisitPostNodeContainerDockerPullResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type DeleteNodeContainerDockerByIDRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Id DockerId `json:"id"`
+ Params DeleteNodeContainerDockerByIDParams
+}
+
+type DeleteNodeContainerDockerByIDResponseObject interface {
+ VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error
+}
+
+type DeleteNodeContainerDockerByID202JSONResponse DockerActionCollectionResponse
+
+func (response DeleteNodeContainerDockerByID202JSONResponse) VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(202)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type DeleteNodeContainerDockerByID400JSONResponse externalRef0.ErrorResponse
+
+func (response DeleteNodeContainerDockerByID400JSONResponse) VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type DeleteNodeContainerDockerByID401JSONResponse externalRef0.ErrorResponse
+
+func (response DeleteNodeContainerDockerByID401JSONResponse) VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type DeleteNodeContainerDockerByID403JSONResponse externalRef0.ErrorResponse
+
+func (response DeleteNodeContainerDockerByID403JSONResponse) VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type DeleteNodeContainerDockerByID404JSONResponse externalRef0.ErrorResponse
+
+func (response DeleteNodeContainerDockerByID404JSONResponse) VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(404)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type DeleteNodeContainerDockerByID500JSONResponse externalRef0.ErrorResponse
+
+func (response DeleteNodeContainerDockerByID500JSONResponse) VisitDeleteNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDockerByIDRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Id DockerId `json:"id"`
+}
+
+type GetNodeContainerDockerByIDResponseObject interface {
+ VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error
+}
+
+type GetNodeContainerDockerByID200JSONResponse DockerDetailCollectionResponse
+
+func (response GetNodeContainerDockerByID200JSONResponse) VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDockerByID400JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDockerByID400JSONResponse) VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDockerByID401JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDockerByID401JSONResponse) VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDockerByID403JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDockerByID403JSONResponse) VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDockerByID404JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDockerByID404JSONResponse) VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(404)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type GetNodeContainerDockerByID500JSONResponse externalRef0.ErrorResponse
+
+func (response GetNodeContainerDockerByID500JSONResponse) VisitGetNodeContainerDockerByIDResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerExecRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Id DockerId `json:"id"`
+ Body *PostNodeContainerDockerExecJSONRequestBody
+}
+
+type PostNodeContainerDockerExecResponseObject interface {
+ VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error
+}
+
+type PostNodeContainerDockerExec202JSONResponse DockerExecCollectionResponse
+
+func (response PostNodeContainerDockerExec202JSONResponse) VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(202)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerExec400JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerExec400JSONResponse) VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerExec401JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerExec401JSONResponse) VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerExec403JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerExec403JSONResponse) VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerExec404JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerExec404JSONResponse) VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(404)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerExec500JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerExec500JSONResponse) VisitPostNodeContainerDockerExecResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStartRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Id DockerId `json:"id"`
+}
+
+type PostNodeContainerDockerStartResponseObject interface {
+ VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error
+}
+
+type PostNodeContainerDockerStart202JSONResponse DockerActionCollectionResponse
+
+func (response PostNodeContainerDockerStart202JSONResponse) VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(202)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStart400JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStart400JSONResponse) VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStart401JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStart401JSONResponse) VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStart403JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStart403JSONResponse) VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStart404JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStart404JSONResponse) VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(404)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStart500JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStart500JSONResponse) VisitPostNodeContainerDockerStartResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStopRequestObject struct {
+ Hostname Hostname `json:"hostname"`
+ Id DockerId `json:"id"`
+ Body *PostNodeContainerDockerStopJSONRequestBody
+}
+
+type PostNodeContainerDockerStopResponseObject interface {
+ VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error
+}
+
+type PostNodeContainerDockerStop202JSONResponse DockerActionCollectionResponse
+
+func (response PostNodeContainerDockerStop202JSONResponse) VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(202)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStop400JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStop400JSONResponse) VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStop401JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStop401JSONResponse) VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(401)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStop403JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStop403JSONResponse) VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(403)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStop404JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStop404JSONResponse) VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(404)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+type PostNodeContainerDockerStop500JSONResponse externalRef0.ErrorResponse
+
+func (response PostNodeContainerDockerStop500JSONResponse) VisitPostNodeContainerDockerStopResponse(w http.ResponseWriter) error {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(500)
+
+ return json.NewEncoder(w).Encode(response)
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+ // List containers
+ // (GET /node/{hostname}/container/docker)
+ GetNodeContainerDocker(ctx context.Context, request GetNodeContainerDockerRequestObject) (GetNodeContainerDockerResponseObject, error)
+ // Create a container
+ // (POST /node/{hostname}/container/docker)
+ PostNodeContainerDocker(ctx context.Context, request PostNodeContainerDockerRequestObject) (PostNodeContainerDockerResponseObject, error)
+ // Pull a container image
+ // (POST /node/{hostname}/container/docker/pull)
+ PostNodeContainerDockerPull(ctx context.Context, request PostNodeContainerDockerPullRequestObject) (PostNodeContainerDockerPullResponseObject, error)
+ // Remove a container
+ // (DELETE /node/{hostname}/container/docker/{id})
+ DeleteNodeContainerDockerByID(ctx context.Context, request DeleteNodeContainerDockerByIDRequestObject) (DeleteNodeContainerDockerByIDResponseObject, error)
+ // Inspect a container
+ // (GET /node/{hostname}/container/docker/{id})
+ GetNodeContainerDockerByID(ctx context.Context, request GetNodeContainerDockerByIDRequestObject) (GetNodeContainerDockerByIDResponseObject, error)
+ // Execute a command in a container
+ // (POST /node/{hostname}/container/docker/{id}/exec)
+ PostNodeContainerDockerExec(ctx context.Context, request PostNodeContainerDockerExecRequestObject) (PostNodeContainerDockerExecResponseObject, error)
+ // Start a container
+ // (POST /node/{hostname}/container/docker/{id}/start)
+ PostNodeContainerDockerStart(ctx context.Context, request PostNodeContainerDockerStartRequestObject) (PostNodeContainerDockerStartResponseObject, error)
+ // Stop a container
+ // (POST /node/{hostname}/container/docker/{id}/stop)
+ PostNodeContainerDockerStop(ctx context.Context, request PostNodeContainerDockerStopRequestObject) (PostNodeContainerDockerStopResponseObject, error)
+}
+
+type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc
+type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// GetNodeContainerDocker operation middleware
+func (sh *strictHandler) GetNodeContainerDocker(ctx echo.Context, hostname Hostname, params GetNodeContainerDockerParams) error {
+ var request GetNodeContainerDockerRequestObject
+
+ request.Hostname = hostname
+ request.Params = params
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetNodeContainerDocker(ctx.Request().Context(), request.(GetNodeContainerDockerRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetNodeContainerDocker")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(GetNodeContainerDockerResponseObject); ok {
+ return validResponse.VisitGetNodeContainerDockerResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostNodeContainerDocker operation middleware
+func (sh *strictHandler) PostNodeContainerDocker(ctx echo.Context, hostname Hostname) error {
+ var request PostNodeContainerDockerRequestObject
+
+ request.Hostname = hostname
+
+ var body PostNodeContainerDockerJSONRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ return err
+ }
+ request.Body = &body
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostNodeContainerDocker(ctx.Request().Context(), request.(PostNodeContainerDockerRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostNodeContainerDocker")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostNodeContainerDockerResponseObject); ok {
+ return validResponse.VisitPostNodeContainerDockerResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostNodeContainerDockerPull operation middleware
+func (sh *strictHandler) PostNodeContainerDockerPull(ctx echo.Context, hostname Hostname) error {
+ var request PostNodeContainerDockerPullRequestObject
+
+ request.Hostname = hostname
+
+ var body PostNodeContainerDockerPullJSONRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ return err
+ }
+ request.Body = &body
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostNodeContainerDockerPull(ctx.Request().Context(), request.(PostNodeContainerDockerPullRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostNodeContainerDockerPull")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostNodeContainerDockerPullResponseObject); ok {
+ return validResponse.VisitPostNodeContainerDockerPullResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// DeleteNodeContainerDockerByID operation middleware
+func (sh *strictHandler) DeleteNodeContainerDockerByID(ctx echo.Context, hostname Hostname, id DockerId, params DeleteNodeContainerDockerByIDParams) error {
+ var request DeleteNodeContainerDockerByIDRequestObject
+
+ request.Hostname = hostname
+ request.Id = id
+ request.Params = params
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.DeleteNodeContainerDockerByID(ctx.Request().Context(), request.(DeleteNodeContainerDockerByIDRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "DeleteNodeContainerDockerByID")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(DeleteNodeContainerDockerByIDResponseObject); ok {
+ return validResponse.VisitDeleteNodeContainerDockerByIDResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// GetNodeContainerDockerByID operation middleware
+func (sh *strictHandler) GetNodeContainerDockerByID(ctx echo.Context, hostname Hostname, id DockerId) error {
+ var request GetNodeContainerDockerByIDRequestObject
+
+ request.Hostname = hostname
+ request.Id = id
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetNodeContainerDockerByID(ctx.Request().Context(), request.(GetNodeContainerDockerByIDRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetNodeContainerDockerByID")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(GetNodeContainerDockerByIDResponseObject); ok {
+ return validResponse.VisitGetNodeContainerDockerByIDResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostNodeContainerDockerExec operation middleware
+func (sh *strictHandler) PostNodeContainerDockerExec(ctx echo.Context, hostname Hostname, id DockerId) error {
+ var request PostNodeContainerDockerExecRequestObject
+
+ request.Hostname = hostname
+ request.Id = id
+
+ var body PostNodeContainerDockerExecJSONRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ return err
+ }
+ request.Body = &body
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostNodeContainerDockerExec(ctx.Request().Context(), request.(PostNodeContainerDockerExecRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostNodeContainerDockerExec")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostNodeContainerDockerExecResponseObject); ok {
+ return validResponse.VisitPostNodeContainerDockerExecResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostNodeContainerDockerStart operation middleware
+func (sh *strictHandler) PostNodeContainerDockerStart(ctx echo.Context, hostname Hostname, id DockerId) error {
+ var request PostNodeContainerDockerStartRequestObject
+
+ request.Hostname = hostname
+ request.Id = id
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostNodeContainerDockerStart(ctx.Request().Context(), request.(PostNodeContainerDockerStartRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostNodeContainerDockerStart")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostNodeContainerDockerStartResponseObject); ok {
+ return validResponse.VisitPostNodeContainerDockerStartResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostNodeContainerDockerStop operation middleware
+func (sh *strictHandler) PostNodeContainerDockerStop(ctx echo.Context, hostname Hostname, id DockerId) error {
+ var request PostNodeContainerDockerStopRequestObject
+
+ request.Hostname = hostname
+ request.Id = id
+
+ var body PostNodeContainerDockerStopJSONRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ return err
+ }
+ request.Body = &body
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostNodeContainerDockerStop(ctx.Request().Context(), request.(PostNodeContainerDockerStopRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostNodeContainerDockerStop")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostNodeContainerDockerStopResponseObject); ok {
+ return validResponse.VisitPostNodeContainerDockerStopResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
diff --git a/internal/api/container/gen/generate.go b/internal/api/docker/gen/generate.go
similarity index 95%
rename from internal/api/container/gen/generate.go
rename to internal/api/docker/gen/generate.go
index d8d19308..9d1f7ec9 100644
--- a/internal/api/container/gen/generate.go
+++ b/internal/api/docker/gen/generate.go
@@ -18,7 +18,7 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
-// Package gen contains generated code for the container API.
+// Package gen contains generated code for the docker API.
package gen
//go:generate go tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/internal/api/container/test_ptr_public_test.go b/internal/api/docker/test_ptr_public_test.go
similarity index 100%
rename from internal/api/container/test_ptr_public_test.go
rename to internal/api/docker/test_ptr_public_test.go
diff --git a/internal/api/container/types.go b/internal/api/docker/types.go
similarity index 100%
rename from internal/api/container/types.go
rename to internal/api/docker/types.go
diff --git a/internal/api/container/validate.go b/internal/api/docker/validate.go
similarity index 100%
rename from internal/api/container/validate.go
rename to internal/api/docker/validate.go
diff --git a/internal/api/gen/api.yaml b/internal/api/gen/api.yaml
index c4c13505..d6ec424a 100644
--- a/internal/api/gen/api.yaml
+++ b/internal/api/gen/api.yaml
@@ -12,15 +12,15 @@ tags:
- name: OSAPI_-_A_CRUD_API_for_managing_Linux_systems_info
x-displayName: Info
description: Operations related to the info endpoint.
- - name: Container_Management_API_container_operations
- x-displayName: Node/Container
- description: Container lifecycle operations on a target node.
- - name: Container_Management_API_container_exec
- x-displayName: Node/Container/Exec
+ - name: Docker_Management_API_docker_operations
+ x-displayName: Node/Docker
+ description: Docker lifecycle operations on a target node.
+ - name: Docker_Management_API_docker_exec
+ x-displayName: Node/Docker/Exec
description: Command execution inside containers on a target node.
- - name: Container_Management_API_container_image
- x-displayName: Node/Container/Image
- description: Container image operations on a target node.
+ - name: Docker_Management_API_docker_image
+ x-displayName: Node/Docker/Image
+ description: Docker image operations on a target node.
- name: File_Management_API_file_operations
x-displayName: File
description: Object Store file management operations.
@@ -436,7 +436,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
- /node/{hostname}/container:
+ /node/{hostname}/container/docker:
servers: []
post:
summary: Create a container
@@ -444,11 +444,11 @@ paths:
Create a new container on the target node. Returns a job ID for tracking
the asynchronous operation.
tags:
- - Container_Management_API_container_operations
- operationId: PostNodeContainer
+ - Docker_Management_API_docker_operations
+ operationId: PostNodeContainerDocker
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
requestBody:
@@ -457,14 +457,14 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerCreateRequest'
+ $ref: '#/components/schemas/DockerCreateRequest'
responses:
'202':
description: Container creation accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerResultCollectionResponse'
+ $ref: '#/components/schemas/DockerResultCollectionResponse'
'400':
description: Invalid request payload.
content:
@@ -494,11 +494,11 @@ paths:
description: |
List containers on the target node, optionally filtered by state.
tags:
- - Container_Management_API_container_operations
- operationId: GetNodeContainer
+ - Docker_Management_API_docker_operations
+ operationId: GetNodeContainerDocker
security:
- BearerAuth:
- - container:read
+ - docker:read
parameters:
- $ref: '#/components/parameters/Hostname'
- name: state
@@ -533,7 +533,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerListCollectionResponse'
+ $ref: '#/components/schemas/DockerListCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -558,28 +558,28 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}:
+ /node/{hostname}/container/docker/{id}:
servers: []
get:
summary: Inspect a container
description: |
Get detailed information about a specific container.
tags:
- - Container_Management_API_container_operations
- operationId: GetNodeContainerByID
+ - Docker_Management_API_docker_operations
+ operationId: GetNodeContainerDockerByID
security:
- BearerAuth:
- - container:read
+ - docker:read
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
responses:
'200':
description: Container detail.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerDetailCollectionResponse'
+ $ref: '#/components/schemas/DockerDetailCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -616,14 +616,14 @@ paths:
Remove a container from the target node. Use the force query parameter
to remove a running container.
tags:
- - Container_Management_API_container_operations
- operationId: DeleteNodeContainerByID
+ - Docker_Management_API_docker_operations
+ operationId: DeleteNodeContainerDockerByID
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
- name: force
in: query
required: false
@@ -640,7 +640,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerActionCollectionResponse'
+ $ref: '#/components/schemas/DockerActionCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -671,28 +671,28 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}/start:
+ /node/{hostname}/container/docker/{id}/start:
servers: []
post:
summary: Start a container
description: |
Start a stopped container on the target node.
tags:
- - Container_Management_API_container_operations
- operationId: PostNodeContainerStart
+ - Docker_Management_API_docker_operations
+ operationId: PostNodeContainerDockerStart
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
responses:
'202':
description: Container start accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerActionCollectionResponse'
+ $ref: '#/components/schemas/DockerActionCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -723,7 +723,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}/stop:
+ /node/{hostname}/container/docker/{id}/stop:
servers: []
post:
summary: Stop a container
@@ -731,28 +731,28 @@ paths:
Stop a running container on the target node. Optionally specify a
timeout before the container is killed.
tags:
- - Container_Management_API_container_operations
- operationId: PostNodeContainerStop
+ - Docker_Management_API_docker_operations
+ operationId: PostNodeContainerDockerStop
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
requestBody:
description: Optional stop parameters.
required: false
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerStopRequest'
+ $ref: '#/components/schemas/DockerStopRequest'
responses:
'202':
description: Container stop accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerActionCollectionResponse'
+ $ref: '#/components/schemas/DockerActionCollectionResponse'
'400':
description: Invalid request parameters.
content:
@@ -783,35 +783,35 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
- /node/{hostname}/container/{id}/exec:
+ /node/{hostname}/container/docker/{id}/exec:
servers: []
post:
summary: Execute a command in a container
description: |
Execute a command inside a running container on the target node.
tags:
- - Container_Management_API_container_exec
- operationId: PostNodeContainerExec
+ - Docker_Management_API_docker_exec
+ operationId: PostNodeContainerDockerExec
security:
- BearerAuth:
- - container:execute
+ - docker:execute
parameters:
- $ref: '#/components/parameters/Hostname'
- - $ref: '#/components/parameters/ContainerId'
+ - $ref: '#/components/parameters/DockerId'
requestBody:
description: The command to execute inside the container.
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerExecRequest'
+ $ref: '#/components/schemas/DockerExecRequest'
responses:
'202':
description: Container exec accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerExecCollectionResponse'
+ $ref: '#/components/schemas/DockerExecCollectionResponse'
'400':
description: Invalid request payload.
content:
@@ -842,18 +842,18 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
- /node/{hostname}/container/pull:
+ /node/{hostname}/container/docker/pull:
servers: []
post:
summary: Pull a container image
description: |
Pull a container image on the target node.
tags:
- - Container_Management_API_container_image
- operationId: PostNodeContainerPull
+ - Docker_Management_API_docker_image
+ operationId: PostNodeContainerDockerPull
security:
- BearerAuth:
- - container:write
+ - docker:write
parameters:
- $ref: '#/components/parameters/Hostname'
requestBody:
@@ -862,14 +862,14 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerPullRequest'
+ $ref: '#/components/schemas/DockerPullRequest'
responses:
'202':
description: Image pull accepted.
content:
application/json:
schema:
- $ref: '#/components/schemas/ContainerPullCollectionResponse'
+ $ref: '#/components/schemas/DockerPullCollectionResponse'
'400':
description: Invalid request payload.
content:
@@ -2492,7 +2492,7 @@ components:
required:
- total_items
- items
- ContainerCreateRequest:
+ DockerCreateRequest:
type: object
properties:
image:
@@ -2547,7 +2547,7 @@ components:
default: true
required:
- image
- ContainerStopRequest:
+ DockerStopRequest:
type: object
properties:
timeout:
@@ -2559,7 +2559,7 @@ components:
default: 10
x-oapi-codegen-extra-tags:
validate: omitempty,min=0,max=300
- ContainerExecRequest:
+ DockerExecRequest:
type: object
properties:
command:
@@ -2584,7 +2584,7 @@ components:
example: /app
required:
- command
- ContainerPullRequest:
+ DockerPullRequest:
type: object
properties:
image:
@@ -2597,7 +2597,7 @@ components:
validate: required,min=1
required:
- image
- ContainerResponse:
+ DockerResponse:
type: object
description: Summary information about a container.
properties:
@@ -2632,7 +2632,7 @@ components:
description: Error message if the agent failed.
required:
- hostname
- ContainerDetailResponse:
+ DockerDetailResponse:
type: object
description: Detailed information about a container.
properties:
@@ -2695,7 +2695,7 @@ components:
description: Error message if the agent failed.
required:
- hostname
- ContainerActionResultItem:
+ DockerActionResultItem:
type: object
description: Result of a container lifecycle action.
properties:
@@ -2717,7 +2717,7 @@ components:
description: Error message if the agent failed.
required:
- hostname
- ContainerExecResultItem:
+ DockerExecResultItem:
type: object
description: Result of a command execution inside a container.
properties:
@@ -2741,7 +2741,7 @@ components:
description: Error message if the agent failed.
required:
- hostname
- ContainerPullResultItem:
+ DockerPullResultItem:
type: object
description: Result of an image pull operation.
properties:
@@ -2768,7 +2768,7 @@ components:
description: Error message if the agent failed.
required:
- hostname
- ContainerListItem:
+ DockerListItem:
type: object
description: Container summary for list operations.
properties:
@@ -2779,7 +2779,7 @@ components:
type: array
description: List of containers on this agent.
items:
- $ref: '#/components/schemas/ContainerSummary'
+ $ref: '#/components/schemas/DockerSummary'
changed:
type: boolean
description: Whether the operation modified system state.
@@ -2788,7 +2788,7 @@ components:
description: Error message if the agent failed.
required:
- hostname
- ContainerSummary:
+ DockerSummary:
type: object
description: Brief container summary.
properties:
@@ -2812,7 +2812,7 @@ components:
type: string
description: Container creation timestamp.
example: '2024-01-15T10:30:00Z'
- ContainerResultCollectionResponse:
+ DockerResultCollectionResponse:
type: object
properties:
job_id:
@@ -2823,10 +2823,10 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerResponse'
+ $ref: '#/components/schemas/DockerResponse'
required:
- results
- ContainerListCollectionResponse:
+ DockerListCollectionResponse:
type: object
properties:
job_id:
@@ -2837,10 +2837,10 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerListItem'
+ $ref: '#/components/schemas/DockerListItem'
required:
- results
- ContainerDetailCollectionResponse:
+ DockerDetailCollectionResponse:
type: object
properties:
job_id:
@@ -2851,10 +2851,10 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerDetailResponse'
+ $ref: '#/components/schemas/DockerDetailResponse'
required:
- results
- ContainerActionCollectionResponse:
+ DockerActionCollectionResponse:
type: object
properties:
job_id:
@@ -2865,10 +2865,10 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerActionResultItem'
+ $ref: '#/components/schemas/DockerActionResultItem'
required:
- results
- ContainerExecCollectionResponse:
+ DockerExecCollectionResponse:
type: object
properties:
job_id:
@@ -2879,10 +2879,10 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerExecResultItem'
+ $ref: '#/components/schemas/DockerExecResultItem'
required:
- results
- ContainerPullCollectionResponse:
+ DockerPullCollectionResponse:
type: object
properties:
job_id:
@@ -2893,7 +2893,7 @@ components:
results:
type: array
items:
- $ref: '#/components/schemas/ContainerPullResultItem'
+ $ref: '#/components/schemas/DockerPullResultItem'
required:
- results
FileInfo:
@@ -4028,7 +4028,7 @@ components:
schema:
type: string
minLength: 1
- ContainerId:
+ DockerId:
name: id
in: path
required: true
@@ -4064,11 +4064,11 @@ x-tagGroups:
- name: OSAPI - A CRUD API for managing Linux systems
tags:
- OSAPI_-_A_CRUD_API_for_managing_Linux_systems_info
- - name: Container Management API
+ - name: Docker Management API
tags:
- - Container_Management_API_container_operations
- - Container_Management_API_container_exec
- - Container_Management_API_container_image
+ - Docker_Management_API_docker_operations
+ - Docker_Management_API_docker_exec
+ - Docker_Management_API_docker_image
- name: File Management API
tags:
- File_Management_API_file_operations
diff --git a/internal/api/handler_container.go b/internal/api/handler_docker.go
similarity index 78%
rename from internal/api/handler_container.go
rename to internal/api/handler_docker.go
index a283cf6d..1d672437 100644
--- a/internal/api/handler_container.go
+++ b/internal/api/handler_docker.go
@@ -24,29 +24,29 @@ import (
"github.com/labstack/echo/v4"
strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
- "github.com/retr0h/osapi/internal/api/container"
- containerGen "github.com/retr0h/osapi/internal/api/container/gen"
+ docker "github.com/retr0h/osapi/internal/api/docker"
+ dockerGen "github.com/retr0h/osapi/internal/api/docker/gen"
"github.com/retr0h/osapi/internal/authtoken"
"github.com/retr0h/osapi/internal/job/client"
)
-// GetContainerHandler returns container handler for registration.
-func (s *Server) GetContainerHandler(
+// GetDockerHandler returns Docker handler for registration.
+func (s *Server) GetDockerHandler(
jobClient client.JobClient,
) []func(e *echo.Echo) {
var tokenManager TokenValidator = authtoken.New(s.logger)
- containerHandler := container.New(s.logger, jobClient)
+ dockerHandler := docker.New(s.logger, jobClient)
- strictHandler := containerGen.NewStrictHandler(
- containerHandler,
- []containerGen.StrictMiddlewareFunc{
+ strictHandler := dockerGen.NewStrictHandler(
+ dockerHandler,
+ []dockerGen.StrictMiddlewareFunc{
func(handler strictecho.StrictEchoHandlerFunc, _ string) strictecho.StrictEchoHandlerFunc {
return scopeMiddleware(
handler,
tokenManager,
s.appConfig.API.Server.Security.SigningKey,
- containerGen.BearerAuthScopes,
+ dockerGen.BearerAuthScopes,
s.customRoles,
)
},
@@ -55,7 +55,7 @@ func (s *Server) GetContainerHandler(
return []func(e *echo.Echo){
func(e *echo.Echo) {
- containerGen.RegisterHandlers(e, strictHandler)
+ dockerGen.RegisterHandlers(e, strictHandler)
},
}
}
diff --git a/internal/api/handler_public_test.go b/internal/api/handler_public_test.go
index fee2eab1..5ea228d9 100644
--- a/internal/api/handler_public_test.go
+++ b/internal/api/handler_public_test.go
@@ -379,13 +379,13 @@ func (s *HandlerPublicTestSuite) TestGetFileHandler() {
}
}
-func (s *HandlerPublicTestSuite) TestGetContainerHandler() {
+func (s *HandlerPublicTestSuite) TestGetDockerHandler() {
tests := []struct {
name string
validate func([]func(e *echo.Echo))
}{
{
- name: "returns container handler functions",
+ name: "returns docker handler functions",
validate: func(handlers []func(e *echo.Echo)) {
s.NotEmpty(handlers)
},
@@ -399,7 +399,7 @@ func (s *HandlerPublicTestSuite) TestGetContainerHandler() {
}
s.NotEmpty(e.Routes())
- req := httptest.NewRequest(http.MethodGet, "/node/hostname/container", nil)
+ req := httptest.NewRequest(http.MethodGet, "/node/hostname/container/docker", nil)
rec := httptest.NewRecorder()
e.ServeHTTP(rec, req)
},
@@ -408,7 +408,7 @@ func (s *HandlerPublicTestSuite) TestGetContainerHandler() {
for _, tt := range tests {
s.Run(tt.name, func() {
- handlers := s.server.GetContainerHandler(s.mockJobClient)
+ handlers := s.server.GetDockerHandler(s.mockJobClient)
tt.validate(handlers)
})
diff --git a/internal/authtoken/permissions.go b/internal/authtoken/permissions.go
index ebdd1b7c..0638cdb5 100644
--- a/internal/authtoken/permissions.go
+++ b/internal/authtoken/permissions.go
@@ -25,21 +25,21 @@ type Permission = string
// Permission constants using resource:verb format.
const (
- PermAgentRead Permission = "agent:read"
- PermAgentWrite Permission = "agent:write"
- PermNodeRead Permission = "node:read"
- PermNetworkRead Permission = "network:read"
- PermNetworkWrite Permission = "network:write"
- PermJobRead Permission = "job:read"
- PermJobWrite Permission = "job:write"
- PermHealthRead Permission = "health:read"
- PermAuditRead Permission = "audit:read"
- PermCommandExecute Permission = "command:execute"
- PermFileRead Permission = "file:read"
- PermFileWrite Permission = "file:write"
- PermContainerRead Permission = "container:read"
- PermContainerWrite Permission = "container:write"
- PermContainerExecute Permission = "container:execute"
+ PermAgentRead Permission = "agent:read"
+ PermAgentWrite Permission = "agent:write"
+ PermNodeRead Permission = "node:read"
+ PermNetworkRead Permission = "network:read"
+ PermNetworkWrite Permission = "network:write"
+ PermJobRead Permission = "job:read"
+ PermJobWrite Permission = "job:write"
+ PermHealthRead Permission = "health:read"
+ PermAuditRead Permission = "audit:read"
+ PermCommandExecute Permission = "command:execute"
+ PermFileRead Permission = "file:read"
+ PermFileWrite Permission = "file:write"
+ PermDockerRead Permission = "docker:read"
+ PermDockerWrite Permission = "docker:write"
+ PermDockerExecute Permission = "docker:execute"
)
// AllPermissions is the full set of known permissions.
@@ -56,9 +56,9 @@ var AllPermissions = []Permission{
PermCommandExecute,
PermFileRead,
PermFileWrite,
- PermContainerRead,
- PermContainerWrite,
- PermContainerExecute,
+ PermDockerRead,
+ PermDockerWrite,
+ PermDockerExecute,
}
// DefaultRolePermissions maps built-in role names to their granted permissions.
@@ -76,9 +76,9 @@ var DefaultRolePermissions = map[string][]Permission{
PermCommandExecute,
PermFileRead,
PermFileWrite,
- PermContainerRead,
- PermContainerWrite,
- PermContainerExecute,
+ PermDockerRead,
+ PermDockerWrite,
+ PermDockerExecute,
},
"write": {
PermAgentRead,
@@ -90,8 +90,8 @@ var DefaultRolePermissions = map[string][]Permission{
PermHealthRead,
PermFileRead,
PermFileWrite,
- PermContainerRead,
- PermContainerWrite,
+ PermDockerRead,
+ PermDockerWrite,
},
"read": {
PermAgentRead,
@@ -100,7 +100,7 @@ var DefaultRolePermissions = map[string][]Permission{
PermJobRead,
PermHealthRead,
PermFileRead,
- PermContainerRead,
+ PermDockerRead,
},
}
diff --git a/internal/job/client/modify_container.go b/internal/job/client/modify_docker.go
similarity index 80%
rename from internal/job/client/modify_container.go
rename to internal/job/client/modify_docker.go
index 91cc7d97..c50b9371 100644
--- a/internal/job/client/modify_container.go
+++ b/internal/job/client/modify_docker.go
@@ -28,17 +28,17 @@ import (
"github.com/retr0h/osapi/internal/job"
)
-// ModifyContainerCreate creates a container on a target.
-func (c *Client) ModifyContainerCreate(
+// ModifyDockerCreate creates a docker container on a target.
+func (c *Client) ModifyDockerCreate(
ctx context.Context,
target string,
- data *job.ContainerCreateData,
+ data *job.DockerCreateData,
) (*job.Response, error) {
dataBytes, _ := json.Marshal(data)
req := &job.Request{
Type: job.TypeModify,
- Category: "container",
- Operation: job.OperationContainerCreate,
+ Category: "docker",
+ Operation: job.OperationDockerCreate,
Data: json.RawMessage(dataBytes),
}
@@ -57,8 +57,8 @@ func (c *Client) ModifyContainerCreate(
return resp, nil
}
-// ModifyContainerStart starts a container on a target.
-func (c *Client) ModifyContainerStart(
+// ModifyDockerStart starts a docker container on a target.
+func (c *Client) ModifyDockerStart(
ctx context.Context,
target string,
id string,
@@ -67,8 +67,8 @@ func (c *Client) ModifyContainerStart(
dataBytes, _ := json.Marshal(data)
req := &job.Request{
Type: job.TypeModify,
- Category: "container",
- Operation: job.OperationContainerStart,
+ Category: "docker",
+ Operation: job.OperationDockerStart,
Data: json.RawMessage(dataBytes),
}
@@ -87,12 +87,12 @@ func (c *Client) ModifyContainerStart(
return resp, nil
}
-// ModifyContainerStop stops a container on a target.
-func (c *Client) ModifyContainerStop(
+// ModifyDockerStop stops a docker container on a target.
+func (c *Client) ModifyDockerStop(
ctx context.Context,
target string,
id string,
- data *job.ContainerStopData,
+ data *job.DockerStopData,
) (*job.Response, error) {
// Merge id into the data
stopData := struct {
@@ -105,8 +105,8 @@ func (c *Client) ModifyContainerStop(
dataBytes, _ := json.Marshal(stopData)
req := &job.Request{
Type: job.TypeModify,
- Category: "container",
- Operation: job.OperationContainerStop,
+ Category: "docker",
+ Operation: job.OperationDockerStop,
Data: json.RawMessage(dataBytes),
}
@@ -125,12 +125,12 @@ func (c *Client) ModifyContainerStop(
return resp, nil
}
-// ModifyContainerRemove removes a container on a target.
-func (c *Client) ModifyContainerRemove(
+// ModifyDockerRemove removes a docker container on a target.
+func (c *Client) ModifyDockerRemove(
ctx context.Context,
target string,
id string,
- data *job.ContainerRemoveData,
+ data *job.DockerRemoveData,
) (*job.Response, error) {
// Merge id into the data
removeData := struct {
@@ -143,8 +143,8 @@ func (c *Client) ModifyContainerRemove(
dataBytes, _ := json.Marshal(removeData)
req := &job.Request{
Type: job.TypeModify,
- Category: "container",
- Operation: job.OperationContainerRemove,
+ Category: "docker",
+ Operation: job.OperationDockerRemove,
Data: json.RawMessage(dataBytes),
}
@@ -163,17 +163,17 @@ func (c *Client) ModifyContainerRemove(
return resp, nil
}
-// QueryContainerList lists containers on a target.
-func (c *Client) QueryContainerList(
+// QueryDockerList lists docker containers on a target.
+func (c *Client) QueryDockerList(
ctx context.Context,
target string,
- data *job.ContainerListData,
+ data *job.DockerListData,
) (*job.Response, error) {
dataBytes, _ := json.Marshal(data)
req := &job.Request{
Type: job.TypeQuery,
- Category: "container",
- Operation: job.OperationContainerList,
+ Category: "docker",
+ Operation: job.OperationDockerList,
Data: json.RawMessage(dataBytes),
}
@@ -192,8 +192,8 @@ func (c *Client) QueryContainerList(
return resp, nil
}
-// QueryContainerInspect inspects a container on a target.
-func (c *Client) QueryContainerInspect(
+// QueryDockerInspect inspects a docker container on a target.
+func (c *Client) QueryDockerInspect(
ctx context.Context,
target string,
id string,
@@ -202,8 +202,8 @@ func (c *Client) QueryContainerInspect(
dataBytes, _ := json.Marshal(data)
req := &job.Request{
Type: job.TypeQuery,
- Category: "container",
- Operation: job.OperationContainerInspect,
+ Category: "docker",
+ Operation: job.OperationDockerInspect,
Data: json.RawMessage(dataBytes),
}
@@ -222,12 +222,12 @@ func (c *Client) QueryContainerInspect(
return resp, nil
}
-// ModifyContainerExec executes a command in a container on a target.
-func (c *Client) ModifyContainerExec(
+// ModifyDockerExec executes a command in a docker container on a target.
+func (c *Client) ModifyDockerExec(
ctx context.Context,
target string,
id string,
- data *job.ContainerExecData,
+ data *job.DockerExecData,
) (*job.Response, error) {
// Merge id into the data
execData := struct {
@@ -244,8 +244,8 @@ func (c *Client) ModifyContainerExec(
dataBytes, _ := json.Marshal(execData)
req := &job.Request{
Type: job.TypeModify,
- Category: "container",
- Operation: job.OperationContainerExec,
+ Category: "docker",
+ Operation: job.OperationDockerExec,
Data: json.RawMessage(dataBytes),
}
@@ -264,17 +264,17 @@ func (c *Client) ModifyContainerExec(
return resp, nil
}
-// ModifyContainerPull pulls an image on a target.
-func (c *Client) ModifyContainerPull(
+// ModifyDockerPull pulls a docker image on a target.
+func (c *Client) ModifyDockerPull(
ctx context.Context,
target string,
- data *job.ContainerPullData,
+ data *job.DockerPullData,
) (*job.Response, error) {
dataBytes, _ := json.Marshal(data)
req := &job.Request{
Type: job.TypeModify,
- Category: "container",
- Operation: job.OperationContainerPull,
+ Category: "docker",
+ Operation: job.OperationDockerPull,
Data: json.RawMessage(dataBytes),
}
diff --git a/internal/job/client/modify_container_public_test.go b/internal/job/client/modify_docker_public_test.go
similarity index 85%
rename from internal/job/client/modify_container_public_test.go
rename to internal/job/client/modify_docker_public_test.go
index e184877e..2917d355 100644
--- a/internal/job/client/modify_container_public_test.go
+++ b/internal/job/client/modify_docker_public_test.go
@@ -35,7 +35,7 @@ import (
jobmocks "github.com/retr0h/osapi/internal/job/mocks"
)
-type ModifyContainerPublicTestSuite struct {
+type ModifyDockerPublicTestSuite struct {
suite.Suite
mockCtrl *gomock.Controller
@@ -45,7 +45,7 @@ type ModifyContainerPublicTestSuite struct {
ctx context.Context
}
-func (s *ModifyContainerPublicTestSuite) SetupTest() {
+func (s *ModifyDockerPublicTestSuite) SetupTest() {
s.mockCtrl = gomock.NewController(s.T())
s.mockNATSClient = jobmocks.NewMockNATSClient(s.mockCtrl)
s.mockKV = jobmocks.NewMockKeyValue(s.mockCtrl)
@@ -60,15 +60,15 @@ func (s *ModifyContainerPublicTestSuite) SetupTest() {
s.Require().NoError(err)
}
-func (s *ModifyContainerPublicTestSuite) TearDownTest() {
+func (s *ModifyDockerPublicTestSuite) TearDownTest() {
s.mockCtrl.Finish()
}
-func (s *ModifyContainerPublicTestSuite) TestModifyContainerCreate() {
+func (s *ModifyDockerPublicTestSuite) TestModifyDockerCreate() {
tests := []struct {
name string
target string
- data *job.ContainerCreateData
+ data *job.DockerCreateData
responseData string
mockError error
expectError bool
@@ -77,7 +77,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerCreate() {
{
name: "success",
target: "server1",
- data: &job.ContainerCreateData{
+ data: &job.DockerCreateData{
Image: "nginx:latest",
Name: "test-nginx",
},
@@ -90,7 +90,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerCreate() {
{
name: "job failed",
target: "server1",
- data: &job.ContainerCreateData{
+ data: &job.DockerCreateData{
Image: "invalid:image",
},
responseData: `{
@@ -103,7 +103,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerCreate() {
{
name: "publish error",
target: "server1",
- data: &job.ContainerCreateData{
+ data: &job.DockerCreateData{
Image: "nginx:latest",
},
mockError: errors.New("connection failed"),
@@ -123,7 +123,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerCreate() {
tt.mockError,
)
- resp, err := s.jobsClient.ModifyContainerCreate(
+ resp, err := s.jobsClient.ModifyDockerCreate(
s.ctx,
tt.target,
tt.data,
@@ -143,7 +143,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerCreate() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestModifyContainerStart() {
+func (s *ModifyDockerPublicTestSuite) TestModifyDockerStart() {
tests := []struct {
name string
target string
@@ -195,7 +195,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStart() {
tt.mockError,
)
- resp, err := s.jobsClient.ModifyContainerStart(
+ resp, err := s.jobsClient.ModifyDockerStart(
s.ctx,
tt.target,
tt.id,
@@ -215,13 +215,13 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStart() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
+func (s *ModifyDockerPublicTestSuite) TestModifyDockerStop() {
timeout := 10
tests := []struct {
name string
target string
id string
- data *job.ContainerStopData
+ data *job.DockerStopData
responseData string
mockError error
expectError bool
@@ -231,7 +231,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
name: "success with timeout",
target: "server1",
id: "abc123",
- data: &job.ContainerStopData{Timeout: &timeout},
+ data: &job.DockerStopData{Timeout: &timeout},
responseData: `{
"status": "completed",
"data": {"message":"Container stopped successfully"}
@@ -242,7 +242,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
name: "success without timeout",
target: "server1",
id: "abc123",
- data: &job.ContainerStopData{},
+ data: &job.DockerStopData{},
responseData: `{
"status": "completed",
"data": {"message":"Container stopped successfully"}
@@ -253,7 +253,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
name: "job failed",
target: "server1",
id: "abc123",
- data: &job.ContainerStopData{},
+ data: &job.DockerStopData{},
responseData: `{
"status": "failed",
"error": "container not running"
@@ -265,7 +265,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
name: "publish error",
target: "server1",
id: "abc123",
- data: &job.ContainerStopData{},
+ data: &job.DockerStopData{},
mockError: errors.New("connection failed"),
expectError: true,
errorContains: "failed to publish and wait",
@@ -283,7 +283,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
tt.mockError,
)
- resp, err := s.jobsClient.ModifyContainerStop(
+ resp, err := s.jobsClient.ModifyDockerStop(
s.ctx,
tt.target,
tt.id,
@@ -304,12 +304,12 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerStop() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
+func (s *ModifyDockerPublicTestSuite) TestModifyDockerRemove() {
tests := []struct {
name string
target string
id string
- data *job.ContainerRemoveData
+ data *job.DockerRemoveData
responseData string
mockError error
expectError bool
@@ -319,7 +319,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
name: "success with force",
target: "server1",
id: "abc123",
- data: &job.ContainerRemoveData{Force: true},
+ data: &job.DockerRemoveData{Force: true},
responseData: `{
"status": "completed",
"data": {"message":"Container removed successfully"}
@@ -330,7 +330,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
name: "success without force",
target: "server1",
id: "abc123",
- data: &job.ContainerRemoveData{Force: false},
+ data: &job.DockerRemoveData{Force: false},
responseData: `{
"status": "completed",
"data": {"message":"Container removed successfully"}
@@ -341,7 +341,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
name: "job failed",
target: "server1",
id: "abc123",
- data: &job.ContainerRemoveData{},
+ data: &job.DockerRemoveData{},
responseData: `{
"status": "failed",
"error": "container is running"
@@ -353,7 +353,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
name: "publish error",
target: "server1",
id: "abc123",
- data: &job.ContainerRemoveData{},
+ data: &job.DockerRemoveData{},
mockError: errors.New("connection failed"),
expectError: true,
errorContains: "failed to publish and wait",
@@ -371,7 +371,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
tt.mockError,
)
- resp, err := s.jobsClient.ModifyContainerRemove(
+ resp, err := s.jobsClient.ModifyDockerRemove(
s.ctx,
tt.target,
tt.id,
@@ -392,11 +392,11 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerRemove() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestQueryContainerList() {
+func (s *ModifyDockerPublicTestSuite) TestQueryDockerList() {
tests := []struct {
name string
target string
- data *job.ContainerListData
+ data *job.DockerListData
responseData string
mockError error
expectError bool
@@ -405,7 +405,7 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerList() {
{
name: "success",
target: "server1",
- data: &job.ContainerListData{
+ data: &job.DockerListData{
State: "running",
Limit: 10,
},
@@ -418,7 +418,7 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerList() {
{
name: "job failed",
target: "server1",
- data: &job.ContainerListData{},
+ data: &job.DockerListData{},
responseData: `{
"status": "failed",
"error": "runtime not available"
@@ -429,7 +429,7 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerList() {
{
name: "publish error",
target: "server1",
- data: &job.ContainerListData{},
+ data: &job.DockerListData{},
mockError: errors.New("connection failed"),
expectError: true,
errorContains: "failed to publish and wait",
@@ -447,7 +447,7 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerList() {
tt.mockError,
)
- resp, err := s.jobsClient.QueryContainerList(
+ resp, err := s.jobsClient.QueryDockerList(
s.ctx,
tt.target,
tt.data,
@@ -467,7 +467,7 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerList() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestQueryContainerInspect() {
+func (s *ModifyDockerPublicTestSuite) TestQueryDockerInspect() {
tests := []struct {
name string
target string
@@ -519,7 +519,7 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerInspect() {
tt.mockError,
)
- resp, err := s.jobsClient.QueryContainerInspect(
+ resp, err := s.jobsClient.QueryDockerInspect(
s.ctx,
tt.target,
tt.id,
@@ -539,12 +539,12 @@ func (s *ModifyContainerPublicTestSuite) TestQueryContainerInspect() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestModifyContainerExec() {
+func (s *ModifyDockerPublicTestSuite) TestModifyDockerExec() {
tests := []struct {
name string
target string
id string
- data *job.ContainerExecData
+ data *job.DockerExecData
responseData string
mockError error
expectError bool
@@ -554,7 +554,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerExec() {
name: "success",
target: "server1",
id: "abc123",
- data: &job.ContainerExecData{
+ data: &job.DockerExecData{
Command: []string{"ls", "-la"},
},
responseData: `{
@@ -567,7 +567,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerExec() {
name: "job failed",
target: "server1",
id: "abc123",
- data: &job.ContainerExecData{
+ data: &job.DockerExecData{
Command: []string{"bad-cmd"},
},
responseData: `{
@@ -581,7 +581,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerExec() {
name: "publish error",
target: "server1",
id: "abc123",
- data: &job.ContainerExecData{
+ data: &job.DockerExecData{
Command: []string{"ls"},
},
mockError: errors.New("connection failed"),
@@ -601,7 +601,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerExec() {
tt.mockError,
)
- resp, err := s.jobsClient.ModifyContainerExec(
+ resp, err := s.jobsClient.ModifyDockerExec(
s.ctx,
tt.target,
tt.id,
@@ -622,11 +622,11 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerExec() {
}
}
-func (s *ModifyContainerPublicTestSuite) TestModifyContainerPull() {
+func (s *ModifyDockerPublicTestSuite) TestModifyDockerPull() {
tests := []struct {
name string
target string
- data *job.ContainerPullData
+ data *job.DockerPullData
responseData string
mockError error
expectError bool
@@ -635,7 +635,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerPull() {
{
name: "success",
target: "server1",
- data: &job.ContainerPullData{
+ data: &job.DockerPullData{
Image: "nginx:latest",
},
responseData: `{
@@ -647,7 +647,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerPull() {
{
name: "job failed",
target: "server1",
- data: &job.ContainerPullData{
+ data: &job.DockerPullData{
Image: "invalid:image",
},
responseData: `{
@@ -660,7 +660,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerPull() {
{
name: "publish error",
target: "server1",
- data: &job.ContainerPullData{
+ data: &job.DockerPullData{
Image: "nginx:latest",
},
mockError: errors.New("connection failed"),
@@ -680,7 +680,7 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerPull() {
tt.mockError,
)
- resp, err := s.jobsClient.ModifyContainerPull(
+ resp, err := s.jobsClient.ModifyDockerPull(
s.ctx,
tt.target,
tt.data,
@@ -700,6 +700,6 @@ func (s *ModifyContainerPublicTestSuite) TestModifyContainerPull() {
}
}
-func TestModifyContainerPublicTestSuite(t *testing.T) {
- suite.Run(t, new(ModifyContainerPublicTestSuite))
+func TestModifyDockerPublicTestSuite(t *testing.T) {
+ suite.Run(t, new(ModifyDockerPublicTestSuite))
}
diff --git a/internal/job/client/types.go b/internal/job/client/types.go
index ebf630cd..3a23e9b8 100644
--- a/internal/job/client/types.go
+++ b/internal/job/client/types.go
@@ -237,49 +237,49 @@ type JobClient interface {
path string,
) (string, *file.StatusResult, string, error)
- // Container operations
- ModifyContainerCreate(
+ // Docker operations
+ ModifyDockerCreate(
ctx context.Context,
target string,
- data *job.ContainerCreateData,
+ data *job.DockerCreateData,
) (*job.Response, error)
- ModifyContainerStart(
+ ModifyDockerStart(
ctx context.Context,
target string,
id string,
) (*job.Response, error)
- ModifyContainerStop(
+ ModifyDockerStop(
ctx context.Context,
target string,
id string,
- data *job.ContainerStopData,
+ data *job.DockerStopData,
) (*job.Response, error)
- ModifyContainerRemove(
+ ModifyDockerRemove(
ctx context.Context,
target string,
id string,
- data *job.ContainerRemoveData,
+ data *job.DockerRemoveData,
) (*job.Response, error)
- QueryContainerList(
+ QueryDockerList(
ctx context.Context,
target string,
- data *job.ContainerListData,
+ data *job.DockerListData,
) (*job.Response, error)
- QueryContainerInspect(
+ QueryDockerInspect(
ctx context.Context,
target string,
id string,
) (*job.Response, error)
- ModifyContainerExec(
+ ModifyDockerExec(
ctx context.Context,
target string,
id string,
- data *job.ContainerExecData,
+ data *job.DockerExecData,
) (*job.Response, error)
- ModifyContainerPull(
+ ModifyDockerPull(
ctx context.Context,
target string,
- data *job.ContainerPullData,
+ data *job.DockerPullData,
) (*job.Response, error)
// Agent discovery
diff --git a/internal/job/mocks/job_client.gen.go b/internal/job/mocks/job_client.gen.go
index b3e583bb..f5e7e0fc 100644
--- a/internal/job/mocks/job_client.gen.go
+++ b/internal/job/mocks/job_client.gen.go
@@ -288,94 +288,94 @@ func (mr *MockJobClientMockRecorder) ModifyCommandShellBroadcast(arg0, arg1, arg
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyCommandShellBroadcast", reflect.TypeOf((*MockJobClient)(nil).ModifyCommandShellBroadcast), arg0, arg1, arg2, arg3, arg4)
}
-// ModifyContainerCreate mocks base method.
-func (m *MockJobClient) ModifyContainerCreate(arg0 context.Context, arg1 string, arg2 *job.ContainerCreateData) (*job.Response, error) {
+// ModifyDockerCreate mocks base method.
+func (m *MockJobClient) ModifyDockerCreate(arg0 context.Context, arg1 string, arg2 *job.DockerCreateData) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ModifyContainerCreate", arg0, arg1, arg2)
+ ret := m.ctrl.Call(m, "ModifyDockerCreate", arg0, arg1, arg2)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// ModifyContainerCreate indicates an expected call of ModifyContainerCreate.
-func (mr *MockJobClientMockRecorder) ModifyContainerCreate(arg0, arg1, arg2 interface{}) *gomock.Call {
+// ModifyDockerCreate indicates an expected call of ModifyDockerCreate.
+func (mr *MockJobClientMockRecorder) ModifyDockerCreate(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyContainerCreate", reflect.TypeOf((*MockJobClient)(nil).ModifyContainerCreate), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDockerCreate", reflect.TypeOf((*MockJobClient)(nil).ModifyDockerCreate), arg0, arg1, arg2)
}
-// ModifyContainerExec mocks base method.
-func (m *MockJobClient) ModifyContainerExec(arg0 context.Context, arg1, arg2 string, arg3 *job.ContainerExecData) (*job.Response, error) {
+// ModifyDockerExec mocks base method.
+func (m *MockJobClient) ModifyDockerExec(arg0 context.Context, arg1, arg2 string, arg3 *job.DockerExecData) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ModifyContainerExec", arg0, arg1, arg2, arg3)
+ ret := m.ctrl.Call(m, "ModifyDockerExec", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// ModifyContainerExec indicates an expected call of ModifyContainerExec.
-func (mr *MockJobClientMockRecorder) ModifyContainerExec(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+// ModifyDockerExec indicates an expected call of ModifyDockerExec.
+func (mr *MockJobClientMockRecorder) ModifyDockerExec(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyContainerExec", reflect.TypeOf((*MockJobClient)(nil).ModifyContainerExec), arg0, arg1, arg2, arg3)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDockerExec", reflect.TypeOf((*MockJobClient)(nil).ModifyDockerExec), arg0, arg1, arg2, arg3)
}
-// ModifyContainerPull mocks base method.
-func (m *MockJobClient) ModifyContainerPull(arg0 context.Context, arg1 string, arg2 *job.ContainerPullData) (*job.Response, error) {
+// ModifyDockerPull mocks base method.
+func (m *MockJobClient) ModifyDockerPull(arg0 context.Context, arg1 string, arg2 *job.DockerPullData) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ModifyContainerPull", arg0, arg1, arg2)
+ ret := m.ctrl.Call(m, "ModifyDockerPull", arg0, arg1, arg2)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// ModifyContainerPull indicates an expected call of ModifyContainerPull.
-func (mr *MockJobClientMockRecorder) ModifyContainerPull(arg0, arg1, arg2 interface{}) *gomock.Call {
+// ModifyDockerPull indicates an expected call of ModifyDockerPull.
+func (mr *MockJobClientMockRecorder) ModifyDockerPull(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyContainerPull", reflect.TypeOf((*MockJobClient)(nil).ModifyContainerPull), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDockerPull", reflect.TypeOf((*MockJobClient)(nil).ModifyDockerPull), arg0, arg1, arg2)
}
-// ModifyContainerRemove mocks base method.
-func (m *MockJobClient) ModifyContainerRemove(arg0 context.Context, arg1, arg2 string, arg3 *job.ContainerRemoveData) (*job.Response, error) {
+// ModifyDockerRemove mocks base method.
+func (m *MockJobClient) ModifyDockerRemove(arg0 context.Context, arg1, arg2 string, arg3 *job.DockerRemoveData) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ModifyContainerRemove", arg0, arg1, arg2, arg3)
+ ret := m.ctrl.Call(m, "ModifyDockerRemove", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// ModifyContainerRemove indicates an expected call of ModifyContainerRemove.
-func (mr *MockJobClientMockRecorder) ModifyContainerRemove(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+// ModifyDockerRemove indicates an expected call of ModifyDockerRemove.
+func (mr *MockJobClientMockRecorder) ModifyDockerRemove(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyContainerRemove", reflect.TypeOf((*MockJobClient)(nil).ModifyContainerRemove), arg0, arg1, arg2, arg3)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDockerRemove", reflect.TypeOf((*MockJobClient)(nil).ModifyDockerRemove), arg0, arg1, arg2, arg3)
}
-// ModifyContainerStart mocks base method.
-func (m *MockJobClient) ModifyContainerStart(arg0 context.Context, arg1, arg2 string) (*job.Response, error) {
+// ModifyDockerStart mocks base method.
+func (m *MockJobClient) ModifyDockerStart(arg0 context.Context, arg1, arg2 string) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ModifyContainerStart", arg0, arg1, arg2)
+ ret := m.ctrl.Call(m, "ModifyDockerStart", arg0, arg1, arg2)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// ModifyContainerStart indicates an expected call of ModifyContainerStart.
-func (mr *MockJobClientMockRecorder) ModifyContainerStart(arg0, arg1, arg2 interface{}) *gomock.Call {
+// ModifyDockerStart indicates an expected call of ModifyDockerStart.
+func (mr *MockJobClientMockRecorder) ModifyDockerStart(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyContainerStart", reflect.TypeOf((*MockJobClient)(nil).ModifyContainerStart), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDockerStart", reflect.TypeOf((*MockJobClient)(nil).ModifyDockerStart), arg0, arg1, arg2)
}
-// ModifyContainerStop mocks base method.
-func (m *MockJobClient) ModifyContainerStop(arg0 context.Context, arg1, arg2 string, arg3 *job.ContainerStopData) (*job.Response, error) {
+// ModifyDockerStop mocks base method.
+func (m *MockJobClient) ModifyDockerStop(arg0 context.Context, arg1, arg2 string, arg3 *job.DockerStopData) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ModifyContainerStop", arg0, arg1, arg2, arg3)
+ ret := m.ctrl.Call(m, "ModifyDockerStop", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// ModifyContainerStop indicates an expected call of ModifyContainerStop.
-func (mr *MockJobClientMockRecorder) ModifyContainerStop(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+// ModifyDockerStop indicates an expected call of ModifyDockerStop.
+func (mr *MockJobClientMockRecorder) ModifyDockerStop(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyContainerStop", reflect.TypeOf((*MockJobClient)(nil).ModifyContainerStop), arg0, arg1, arg2, arg3)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDockerStop", reflect.TypeOf((*MockJobClient)(nil).ModifyDockerStop), arg0, arg1, arg2, arg3)
}
// ModifyFileDeploy mocks base method.
@@ -463,34 +463,34 @@ func (mr *MockJobClientMockRecorder) ModifyNetworkDNSBroadcast(arg0, arg1, arg2,
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyNetworkDNSBroadcast", reflect.TypeOf((*MockJobClient)(nil).ModifyNetworkDNSBroadcast), arg0, arg1, arg2, arg3, arg4)
}
-// QueryContainerInspect mocks base method.
-func (m *MockJobClient) QueryContainerInspect(arg0 context.Context, arg1, arg2 string) (*job.Response, error) {
+// QueryDockerInspect mocks base method.
+func (m *MockJobClient) QueryDockerInspect(arg0 context.Context, arg1, arg2 string) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "QueryContainerInspect", arg0, arg1, arg2)
+ ret := m.ctrl.Call(m, "QueryDockerInspect", arg0, arg1, arg2)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// QueryContainerInspect indicates an expected call of QueryContainerInspect.
-func (mr *MockJobClientMockRecorder) QueryContainerInspect(arg0, arg1, arg2 interface{}) *gomock.Call {
+// QueryDockerInspect indicates an expected call of QueryDockerInspect.
+func (mr *MockJobClientMockRecorder) QueryDockerInspect(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryContainerInspect", reflect.TypeOf((*MockJobClient)(nil).QueryContainerInspect), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryDockerInspect", reflect.TypeOf((*MockJobClient)(nil).QueryDockerInspect), arg0, arg1, arg2)
}
-// QueryContainerList mocks base method.
-func (m *MockJobClient) QueryContainerList(arg0 context.Context, arg1 string, arg2 *job.ContainerListData) (*job.Response, error) {
+// QueryDockerList mocks base method.
+func (m *MockJobClient) QueryDockerList(arg0 context.Context, arg1 string, arg2 *job.DockerListData) (*job.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "QueryContainerList", arg0, arg1, arg2)
+ ret := m.ctrl.Call(m, "QueryDockerList", arg0, arg1, arg2)
ret0, _ := ret[0].(*job.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// QueryContainerList indicates an expected call of QueryContainerList.
-func (mr *MockJobClientMockRecorder) QueryContainerList(arg0, arg1, arg2 interface{}) *gomock.Call {
+// QueryDockerList indicates an expected call of QueryDockerList.
+func (mr *MockJobClientMockRecorder) QueryDockerList(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryContainerList", reflect.TypeOf((*MockJobClient)(nil).QueryContainerList), arg0, arg1, arg2)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryDockerList", reflect.TypeOf((*MockJobClient)(nil).QueryDockerList), arg0, arg1, arg2)
}
// QueryFileStatus mocks base method.
diff --git a/internal/job/subjects.go b/internal/job/subjects.go
index 0ee5e834..efa02800 100644
--- a/internal/job/subjects.go
+++ b/internal/job/subjects.go
@@ -85,9 +85,9 @@ const (
// Subject categories for different operations
const (
- SubjectCategoryNode = "node"
- SubjectCategoryNetwork = "network"
- SubjectCategoryContainer = "container"
+ SubjectCategoryNode = "node"
+ SubjectCategoryNetwork = "network"
+ SubjectCategoryDocker = "docker"
)
// Node operation types
diff --git a/internal/job/types.go b/internal/job/types.go
index 32088920..d81189a1 100644
--- a/internal/job/types.go
+++ b/internal/job/types.go
@@ -132,16 +132,16 @@ const (
OperationFileStatusGet = "file.status.get"
)
-// Container operation types
+// Docker operation types
const (
- OperationContainerCreate = "container.create.execute"
- OperationContainerStart = "container.start.execute"
- OperationContainerStop = "container.stop.execute"
- OperationContainerRemove = "container.remove.execute"
- OperationContainerList = "container.list.get"
- OperationContainerInspect = "container.inspect.get"
- OperationContainerExec = "container.exec.execute"
- OperationContainerPull = "container.pull.execute"
+ OperationDockerCreate = "docker.create.execute"
+ OperationDockerStart = "docker.start.execute"
+ OperationDockerStop = "docker.stop.execute"
+ OperationDockerRemove = "docker.remove.execute"
+ OperationDockerList = "docker.list.get"
+ OperationDockerInspect = "docker.inspect.get"
+ OperationDockerExec = "docker.exec.execute"
+ OperationDockerPull = "docker.pull.execute"
)
// Operation represents an operation in the new hierarchical format
@@ -260,8 +260,8 @@ type CommandShellData struct {
Timeout int `json:"timeout,omitempty"`
}
-// ContainerCreateData represents data for container creation.
-type ContainerCreateData struct {
+// DockerCreateData represents data for docker container creation.
+type DockerCreateData struct {
Image string `json:"image"`
Name string `json:"name,omitempty"`
Command []string `json:"command,omitempty"`
@@ -286,31 +286,31 @@ type VolumeMapping struct {
Container string `json:"container"`
}
-// ContainerStopData represents data for stopping a container.
-type ContainerStopData struct {
+// DockerStopData represents data for stopping a docker container.
+type DockerStopData struct {
Timeout *int `json:"timeout,omitempty"`
}
-// ContainerRemoveData represents data for removing a container.
-type ContainerRemoveData struct {
+// DockerRemoveData represents data for removing a docker container.
+type DockerRemoveData struct {
Force bool `json:"force,omitempty"`
}
-// ContainerListData represents data for listing containers.
-type ContainerListData struct {
+// DockerListData represents data for listing docker containers.
+type DockerListData struct {
State string `json:"state,omitempty"`
Limit int `json:"limit,omitempty"`
}
-// ContainerExecData represents data for executing a command in a container.
-type ContainerExecData struct {
+// DockerExecData represents data for executing a command in a docker container.
+type DockerExecData struct {
Command []string `json:"command"`
Env map[string]string `json:"env,omitempty"`
WorkingDir string `json:"working_dir,omitempty"`
}
-// ContainerPullData represents data for pulling an image.
-type ContainerPullData struct {
+// DockerPullData represents data for pulling a docker image.
+type DockerPullData struct {
Image string `json:"image"`
}
diff --git a/internal/provider/container/provider.go b/internal/provider/container/provider.go
deleted file mode 100644
index 4a1f5780..00000000
--- a/internal/provider/container/provider.go
+++ /dev/null
@@ -1,103 +0,0 @@
-package container
-
-import (
- "context"
- "time"
-
- "github.com/retr0h/osapi/internal/provider/container/runtime"
-)
-
-// Service implements Provider by delegating to a runtime.Driver.
-type Service struct {
- driver runtime.Driver
-}
-
-// New creates a new container provider service.
-func New(
- driver runtime.Driver,
-) *Service {
- return &Service{driver: driver}
-}
-
-// Create delegates to the driver to create a container.
-func (
- s *Service,
-) Create(
- ctx context.Context,
- params runtime.CreateParams,
-) (*runtime.Container, error) {
- return s.driver.Create(ctx, params)
-}
-
-// Start delegates to the driver to start a container.
-func (
- s *Service,
-) Start(
- ctx context.Context,
- id string,
-) error {
- return s.driver.Start(ctx, id)
-}
-
-// Stop delegates to the driver to stop a container.
-func (
- s *Service,
-) Stop(
- ctx context.Context,
- id string,
- timeout *time.Duration,
-) error {
- return s.driver.Stop(ctx, id, timeout)
-}
-
-// Remove delegates to the driver to remove a container.
-func (
- s *Service,
-) Remove(
- ctx context.Context,
- id string,
- force bool,
-) error {
- return s.driver.Remove(ctx, id, force)
-}
-
-// List delegates to the driver to list containers.
-func (
- s *Service,
-) List(
- ctx context.Context,
- params runtime.ListParams,
-) ([]runtime.Container, error) {
- return s.driver.List(ctx, params)
-}
-
-// Inspect delegates to the driver to inspect a container.
-func (
- s *Service,
-) Inspect(
- ctx context.Context,
- id string,
-) (*runtime.ContainerDetail, error) {
- return s.driver.Inspect(ctx, id)
-}
-
-// Exec delegates to the driver to execute a command in a container.
-func (
- s *Service,
-) Exec(
- ctx context.Context,
- id string,
- params runtime.ExecParams,
-) (*runtime.ExecResult, error) {
- return s.driver.Exec(ctx, id, params)
-}
-
-// Pull delegates to the driver to pull a container image.
-func (
- s *Service,
-) Pull(
- ctx context.Context,
- image string,
-) (*runtime.PullResult, error) {
- return s.driver.Pull(ctx, image)
-}
diff --git a/internal/provider/container/provider_public_test.go b/internal/provider/container/provider_public_test.go
deleted file mode 100644
index cae5f40b..00000000
--- a/internal/provider/container/provider_public_test.go
+++ /dev/null
@@ -1,544 +0,0 @@
-package container_test
-
-import (
- "context"
- "errors"
- "testing"
- "time"
-
- "github.com/golang/mock/gomock"
- "github.com/stretchr/testify/suite"
-
- "github.com/retr0h/osapi/internal/provider/container"
- "github.com/retr0h/osapi/internal/provider/container/runtime"
- runtimeMocks "github.com/retr0h/osapi/internal/provider/container/runtime/mocks"
-)
-
-type ProviderPublicTestSuite struct {
- suite.Suite
-
- mockCtrl *gomock.Controller
- mockDriver *runtimeMocks.MockDriver
- service *container.Service
- ctx context.Context
-}
-
-func (s *ProviderPublicTestSuite) SetupTest() {
- s.mockCtrl = gomock.NewController(s.T())
- s.mockDriver = runtimeMocks.NewMockDriver(s.mockCtrl)
- s.service = container.New(s.mockDriver)
- s.ctx = context.Background()
-}
-
-func (s *ProviderPublicTestSuite) TearDownTest() {
- s.mockCtrl.Finish()
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestNew() {
- tests := []struct {
- name string
- validateFunc func(p container.Provider)
- }{
- {
- name: "returns non-nil provider",
- validateFunc: func(p container.Provider) {
- s.NotNil(p)
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- var driver runtime.Driver // nil driver for unit test
- p := container.New(driver)
- tt.validateFunc(p)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestCreate() {
- tests := []struct {
- name string
- params runtime.CreateParams
- setupMock func()
- validateFunc func(*runtime.Container, error)
- }{
- {
- name: "delegates to driver and returns result",
- params: runtime.CreateParams{
- Image: "nginx:latest",
- Name: "web",
- },
- setupMock: func() {
- s.mockDriver.EXPECT().
- Create(gomock.Any(), runtime.CreateParams{
- Image: "nginx:latest",
- Name: "web",
- }).
- Return(&runtime.Container{
- ID: "abc123",
- Name: "web",
- Image: "nginx:latest",
- State: "created",
- }, nil)
- },
- validateFunc: func(
- c *runtime.Container,
- err error,
- ) {
- s.NoError(err)
- s.NotNil(c)
- s.Equal("abc123", c.ID)
- s.Equal("web", c.Name)
- },
- },
- {
- name: "returns error from driver",
- params: runtime.CreateParams{
- Image: "invalid:image",
- },
- setupMock: func() {
- s.mockDriver.EXPECT().
- Create(gomock.Any(), gomock.Any()).
- Return(nil, errors.New("image not found"))
- },
- validateFunc: func(
- c *runtime.Container,
- err error,
- ) {
- s.Error(err)
- s.Nil(c)
- s.Contains(err.Error(), "image not found")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- c, err := s.service.Create(s.ctx, tt.params)
- tt.validateFunc(c, err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestStart() {
- tests := []struct {
- name string
- id string
- setupMock func()
- validateFunc func(error)
- }{
- {
- name: "delegates to driver and returns nil",
- id: "abc123",
- setupMock: func() {
- s.mockDriver.EXPECT().
- Start(gomock.Any(), "abc123").
- Return(nil)
- },
- validateFunc: func(err error) {
- s.NoError(err)
- },
- },
- {
- name: "returns error from driver",
- id: "abc123",
- setupMock: func() {
- s.mockDriver.EXPECT().
- Start(gomock.Any(), "abc123").
- Return(errors.New("container not found"))
- },
- validateFunc: func(err error) {
- s.Error(err)
- s.Contains(err.Error(), "container not found")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- err := s.service.Start(s.ctx, tt.id)
- tt.validateFunc(err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestStop() {
- timeout := 10 * time.Second
- tests := []struct {
- name string
- id string
- timeout *time.Duration
- setupMock func()
- validateFunc func(error)
- }{
- {
- name: "delegates to driver with timeout",
- id: "abc123",
- timeout: &timeout,
- setupMock: func() {
- s.mockDriver.EXPECT().
- Stop(gomock.Any(), "abc123", &timeout).
- Return(nil)
- },
- validateFunc: func(err error) {
- s.NoError(err)
- },
- },
- {
- name: "delegates to driver without timeout",
- id: "abc123",
- timeout: nil,
- setupMock: func() {
- s.mockDriver.EXPECT().
- Stop(gomock.Any(), "abc123", (*time.Duration)(nil)).
- Return(nil)
- },
- validateFunc: func(err error) {
- s.NoError(err)
- },
- },
- {
- name: "returns error from driver",
- id: "abc123",
- timeout: &timeout,
- setupMock: func() {
- s.mockDriver.EXPECT().
- Stop(gomock.Any(), "abc123", gomock.Any()).
- Return(errors.New("stop failed"))
- },
- validateFunc: func(err error) {
- s.Error(err)
- s.Contains(err.Error(), "stop failed")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- err := s.service.Stop(s.ctx, tt.id, tt.timeout)
- tt.validateFunc(err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestRemove() {
- tests := []struct {
- name string
- id string
- force bool
- setupMock func()
- validateFunc func(error)
- }{
- {
- name: "delegates to driver with force",
- id: "abc123",
- force: true,
- setupMock: func() {
- s.mockDriver.EXPECT().
- Remove(gomock.Any(), "abc123", true).
- Return(nil)
- },
- validateFunc: func(err error) {
- s.NoError(err)
- },
- },
- {
- name: "delegates to driver without force",
- id: "abc123",
- force: false,
- setupMock: func() {
- s.mockDriver.EXPECT().
- Remove(gomock.Any(), "abc123", false).
- Return(nil)
- },
- validateFunc: func(err error) {
- s.NoError(err)
- },
- },
- {
- name: "returns error from driver",
- id: "abc123",
- force: true,
- setupMock: func() {
- s.mockDriver.EXPECT().
- Remove(gomock.Any(), "abc123", true).
- Return(errors.New("remove failed"))
- },
- validateFunc: func(err error) {
- s.Error(err)
- s.Contains(err.Error(), "remove failed")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- err := s.service.Remove(s.ctx, tt.id, tt.force)
- tt.validateFunc(err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestList() {
- tests := []struct {
- name string
- params runtime.ListParams
- setupMock func()
- validateFunc func([]runtime.Container, error)
- }{
- {
- name: "delegates to driver and returns containers",
- params: runtime.ListParams{
- State: "running",
- Limit: 10,
- },
- setupMock: func() {
- s.mockDriver.EXPECT().
- List(gomock.Any(), runtime.ListParams{
- State: "running",
- Limit: 10,
- }).
- Return([]runtime.Container{
- {ID: "abc123", Name: "web", State: "running"},
- }, nil)
- },
- validateFunc: func(
- containers []runtime.Container,
- err error,
- ) {
- s.NoError(err)
- s.Len(containers, 1)
- s.Equal("abc123", containers[0].ID)
- },
- },
- {
- name: "returns error from driver",
- params: runtime.ListParams{State: "all"},
- setupMock: func() {
- s.mockDriver.EXPECT().
- List(gomock.Any(), gomock.Any()).
- Return(nil, errors.New("list failed"))
- },
- validateFunc: func(
- containers []runtime.Container,
- err error,
- ) {
- s.Error(err)
- s.Nil(containers)
- s.Contains(err.Error(), "list failed")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- containers, err := s.service.List(s.ctx, tt.params)
- tt.validateFunc(containers, err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestInspect() {
- tests := []struct {
- name string
- id string
- setupMock func()
- validateFunc func(*runtime.ContainerDetail, error)
- }{
- {
- name: "delegates to driver and returns detail",
- id: "abc123",
- setupMock: func() {
- s.mockDriver.EXPECT().
- Inspect(gomock.Any(), "abc123").
- Return(&runtime.ContainerDetail{
- Container: runtime.Container{ID: "abc123"},
- }, nil)
- },
- validateFunc: func(
- detail *runtime.ContainerDetail,
- err error,
- ) {
- s.NoError(err)
- s.NotNil(detail)
- s.Equal("abc123", detail.ID)
- },
- },
- {
- name: "returns error from driver",
- id: "abc123",
- setupMock: func() {
- s.mockDriver.EXPECT().
- Inspect(gomock.Any(), "abc123").
- Return(nil, errors.New("inspect failed"))
- },
- validateFunc: func(
- detail *runtime.ContainerDetail,
- err error,
- ) {
- s.Error(err)
- s.Nil(detail)
- s.Contains(err.Error(), "inspect failed")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- detail, err := s.service.Inspect(s.ctx, tt.id)
- tt.validateFunc(detail, err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestExec() {
- tests := []struct {
- name string
- id string
- params runtime.ExecParams
- setupMock func()
- validateFunc func(*runtime.ExecResult, error)
- }{
- {
- name: "delegates to driver and returns result",
- id: "abc123",
- params: runtime.ExecParams{
- Command: []string{"ls", "-la"},
- },
- setupMock: func() {
- s.mockDriver.EXPECT().
- Exec(gomock.Any(), "abc123", runtime.ExecParams{
- Command: []string{"ls", "-la"},
- }).
- Return(&runtime.ExecResult{
- Stdout: "output",
- ExitCode: 0,
- }, nil)
- },
- validateFunc: func(
- result *runtime.ExecResult,
- err error,
- ) {
- s.NoError(err)
- s.NotNil(result)
- s.Equal("output", result.Stdout)
- s.Equal(0, result.ExitCode)
- },
- },
- {
- name: "returns error from driver",
- id: "abc123",
- params: runtime.ExecParams{
- Command: []string{"ls"},
- },
- setupMock: func() {
- s.mockDriver.EXPECT().
- Exec(gomock.Any(), "abc123", gomock.Any()).
- Return(nil, errors.New("exec failed"))
- },
- validateFunc: func(
- result *runtime.ExecResult,
- err error,
- ) {
- s.Error(err)
- s.Nil(result)
- s.Contains(err.Error(), "exec failed")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- result, err := s.service.Exec(s.ctx, tt.id, tt.params)
- tt.validateFunc(result, err)
- })
- }
-}
-
-func (
- s *ProviderPublicTestSuite,
-) TestPull() {
- tests := []struct {
- name string
- image string
- setupMock func()
- validateFunc func(*runtime.PullResult, error)
- }{
- {
- name: "delegates to driver and returns result",
- image: "nginx:latest",
- setupMock: func() {
- s.mockDriver.EXPECT().
- Pull(gomock.Any(), "nginx:latest").
- Return(&runtime.PullResult{
- ImageID: "sha256:abc",
- Tag: "latest",
- Size: 2048,
- }, nil)
- },
- validateFunc: func(
- result *runtime.PullResult,
- err error,
- ) {
- s.NoError(err)
- s.NotNil(result)
- s.Equal("sha256:abc", result.ImageID)
- s.Equal("latest", result.Tag)
- s.Equal(int64(2048), result.Size)
- },
- },
- {
- name: "returns error from driver",
- image: "invalid:image",
- setupMock: func() {
- s.mockDriver.EXPECT().
- Pull(gomock.Any(), "invalid:image").
- Return(nil, errors.New("pull failed"))
- },
- validateFunc: func(
- result *runtime.PullResult,
- err error,
- ) {
- s.Error(err)
- s.Nil(result)
- s.Contains(err.Error(), "pull failed")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- tt.setupMock()
- result, err := s.service.Pull(s.ctx, tt.image)
- tt.validateFunc(result, err)
- })
- }
-}
-
-func TestProviderPublicTestSuite(t *testing.T) {
- suite.Run(t, new(ProviderPublicTestSuite))
-}
diff --git a/internal/provider/container/runtime/mocks/driver.gen.go b/internal/provider/container/runtime/mocks/driver.gen.go
deleted file mode 100644
index e1793ff4..00000000
--- a/internal/provider/container/runtime/mocks/driver.gen.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// Code generated by MockGen. DO NOT EDIT.
-// Source: ../driver.go
-
-// Package mocks is a generated GoMock package.
-package mocks
-
-import (
- context "context"
- reflect "reflect"
- time "time"
-
- gomock "github.com/golang/mock/gomock"
- runtime "github.com/retr0h/osapi/internal/provider/container/runtime"
-)
-
-// MockDriver is a mock of Driver interface.
-type MockDriver struct {
- ctrl *gomock.Controller
- recorder *MockDriverMockRecorder
-}
-
-// MockDriverMockRecorder is the mock recorder for MockDriver.
-type MockDriverMockRecorder struct {
- mock *MockDriver
-}
-
-// NewMockDriver creates a new mock instance.
-func NewMockDriver(ctrl *gomock.Controller) *MockDriver {
- mock := &MockDriver{ctrl: ctrl}
- mock.recorder = &MockDriverMockRecorder{mock}
- return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockDriver) EXPECT() *MockDriverMockRecorder {
- return m.recorder
-}
-
-// Create mocks base method.
-func (m *MockDriver) Create(ctx context.Context, params runtime.CreateParams) (*runtime.Container, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Create", ctx, params)
- ret0, _ := ret[0].(*runtime.Container)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// Create indicates an expected call of Create.
-func (mr *MockDriverMockRecorder) Create(ctx, params interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockDriver)(nil).Create), ctx, params)
-}
-
-// Exec mocks base method.
-func (m *MockDriver) Exec(ctx context.Context, id string, params runtime.ExecParams) (*runtime.ExecResult, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Exec", ctx, id, params)
- ret0, _ := ret[0].(*runtime.ExecResult)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// Exec indicates an expected call of Exec.
-func (mr *MockDriverMockRecorder) Exec(ctx, id, params interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exec", reflect.TypeOf((*MockDriver)(nil).Exec), ctx, id, params)
-}
-
-// Inspect mocks base method.
-func (m *MockDriver) Inspect(ctx context.Context, id string) (*runtime.ContainerDetail, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Inspect", ctx, id)
- ret0, _ := ret[0].(*runtime.ContainerDetail)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// Inspect indicates an expected call of Inspect.
-func (mr *MockDriverMockRecorder) Inspect(ctx, id interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Inspect", reflect.TypeOf((*MockDriver)(nil).Inspect), ctx, id)
-}
-
-// List mocks base method.
-func (m *MockDriver) List(ctx context.Context, params runtime.ListParams) ([]runtime.Container, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "List", ctx, params)
- ret0, _ := ret[0].([]runtime.Container)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// List indicates an expected call of List.
-func (mr *MockDriverMockRecorder) List(ctx, params interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockDriver)(nil).List), ctx, params)
-}
-
-// Ping mocks base method.
-func (m *MockDriver) Ping(ctx context.Context) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Ping", ctx)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Ping indicates an expected call of Ping.
-func (mr *MockDriverMockRecorder) Ping(ctx interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockDriver)(nil).Ping), ctx)
-}
-
-// Pull mocks base method.
-func (m *MockDriver) Pull(ctx context.Context, image string) (*runtime.PullResult, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Pull", ctx, image)
- ret0, _ := ret[0].(*runtime.PullResult)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// Pull indicates an expected call of Pull.
-func (mr *MockDriverMockRecorder) Pull(ctx, image interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Pull", reflect.TypeOf((*MockDriver)(nil).Pull), ctx, image)
-}
-
-// Remove mocks base method.
-func (m *MockDriver) Remove(ctx context.Context, id string, force bool) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Remove", ctx, id, force)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Remove indicates an expected call of Remove.
-func (mr *MockDriverMockRecorder) Remove(ctx, id, force interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockDriver)(nil).Remove), ctx, id, force)
-}
-
-// Start mocks base method.
-func (m *MockDriver) Start(ctx context.Context, id string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Start", ctx, id)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Start indicates an expected call of Start.
-func (mr *MockDriverMockRecorder) Start(ctx, id interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockDriver)(nil).Start), ctx, id)
-}
-
-// Stop mocks base method.
-func (m *MockDriver) Stop(ctx context.Context, id string, timeout *time.Duration) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Stop", ctx, id, timeout)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Stop indicates an expected call of Stop.
-func (mr *MockDriverMockRecorder) Stop(ctx, id, timeout interface{}) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockDriver)(nil).Stop), ctx, id, timeout)
-}
diff --git a/internal/provider/container/types.go b/internal/provider/container/types.go
deleted file mode 100644
index b1833cff..00000000
--- a/internal/provider/container/types.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Package container provides the container management provider.
-package container
-
-import (
- "context"
- "time"
-
- "github.com/retr0h/osapi/internal/provider/container/runtime"
-)
-
-// Provider defines the container management interface.
-// All methods accept context.Context for cancellation and timeout propagation,
-// which is important since the Docker daemon is a remote service.
-type Provider interface {
- Create(
- ctx context.Context,
- params runtime.CreateParams,
- ) (*runtime.Container, error)
-
- Start(
- ctx context.Context,
- id string,
- ) error
-
- Stop(
- ctx context.Context,
- id string,
- timeout *time.Duration,
- ) error
-
- Remove(
- ctx context.Context,
- id string,
- force bool,
- ) error
-
- List(
- ctx context.Context,
- params runtime.ListParams,
- ) ([]runtime.Container, error)
-
- Inspect(
- ctx context.Context,
- id string,
- ) (*runtime.ContainerDetail, error)
-
- Exec(
- ctx context.Context,
- id string,
- params runtime.ExecParams,
- ) (*runtime.ExecResult, error)
-
- Pull(
- ctx context.Context,
- image string,
- ) (*runtime.PullResult, error)
-}
diff --git a/internal/provider/container/runtime/docker/docker.go b/internal/provider/docker/docker.go
similarity index 81%
rename from internal/provider/container/runtime/docker/docker.go
rename to internal/provider/docker/docker.go
index 4afda96a..5e66128e 100644
--- a/internal/provider/container/runtime/docker/docker.go
+++ b/internal/provider/docker/docker.go
@@ -1,4 +1,4 @@
-// Package docker implements the runtime.Driver interface using the Docker Engine API.
+// Package docker provides the Docker container management provider using the Docker Engine API.
package docker
import (
@@ -18,17 +18,15 @@ import (
"github.com/docker/docker/api/types/network"
dockerclient "github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
-
- "github.com/retr0h/osapi/internal/provider/container/runtime"
)
-// Driver implements runtime.Driver using the Docker Engine API.
-type Driver struct {
+// Client implements Driver using the Docker Engine API.
+type Client struct {
client dockerclient.APIClient
}
-// New creates a new Docker driver using default client options.
-func New() (*Driver, error) {
+// New creates a new Docker provider using default client options.
+func New() (*Client, error) {
cli, err := dockerclient.NewClientWithOpts(
dockerclient.FromEnv,
dockerclient.WithAPIVersionNegotiation(),
@@ -37,18 +35,18 @@ func New() (*Driver, error) {
return nil, fmt.Errorf("create docker client: %w", err)
}
- return &Driver{client: cli}, nil
+ return &Client{client: cli}, nil
}
-// NewWithClient creates a Docker driver with an injected client (for testing).
+// NewWithClient creates a Docker provider with an injected client (for testing).
func NewWithClient(
client dockerclient.APIClient,
-) *Driver {
- return &Driver{client: client}
+) *Client {
+ return &Client{client: client}
}
// Ping verifies connectivity to the Docker daemon.
-func (d *Driver) Ping(
+func (d *Client) Ping(
ctx context.Context,
) error {
_, err := d.client.Ping(ctx)
@@ -60,10 +58,10 @@ func (d *Driver) Ping(
}
// Create creates a new container from the given parameters.
-func (d *Driver) Create(
+func (d *Client) Create(
ctx context.Context,
- params runtime.CreateParams,
-) (*runtime.Container, error) {
+ params CreateParams,
+) (*Container, error) {
// Build Docker container configuration
config := &container.Config{
Image: params.Image,
@@ -131,39 +129,43 @@ func (d *Driver) Create(
// Start the container if AutoStart is enabled
if params.AutoStart {
- if err := d.Start(ctx, resp.ID); err != nil {
+ if _, err := d.Start(ctx, resp.ID); err != nil {
return nil, fmt.Errorf("auto-start container: %w", err)
}
}
// Return container summary
- return &runtime.Container{
+ return &Container{
ID: resp.ID,
Name: params.Name,
Image: params.Image,
State: "created",
Created: time.Now(),
+ Changed: true,
}, nil
}
// Start starts a stopped container.
-func (d *Driver) Start(
+func (d *Client) Start(
ctx context.Context,
id string,
-) error {
+) (*ActionResult, error) {
if err := d.client.ContainerStart(ctx, id, container.StartOptions{}); err != nil {
- return fmt.Errorf("start container: %w", err)
+ return nil, fmt.Errorf("start container: %w", err)
}
- return nil
+ return &ActionResult{
+ Message: "Container started successfully",
+ Changed: true,
+ }, nil
}
// Stop stops a running container with an optional timeout.
-func (d *Driver) Stop(
+func (d *Client) Stop(
ctx context.Context,
id string,
timeout *time.Duration,
-) error {
+) (*ActionResult, error) {
opts := container.StopOptions{}
if timeout != nil {
seconds := int(timeout.Seconds())
@@ -171,34 +173,40 @@ func (d *Driver) Stop(
}
if err := d.client.ContainerStop(ctx, id, opts); err != nil {
- return fmt.Errorf("stop container: %w", err)
+ return nil, fmt.Errorf("stop container: %w", err)
}
- return nil
+ return &ActionResult{
+ Message: "Container stopped successfully",
+ Changed: true,
+ }, nil
}
// Remove removes a container.
-func (d *Driver) Remove(
+func (d *Client) Remove(
ctx context.Context,
id string,
force bool,
-) error {
+) (*ActionResult, error) {
opts := container.RemoveOptions{
Force: force,
}
if err := d.client.ContainerRemove(ctx, id, opts); err != nil {
- return fmt.Errorf("remove container: %w", err)
+ return nil, fmt.Errorf("remove container: %w", err)
}
- return nil
+ return &ActionResult{
+ Message: "Container removed successfully",
+ Changed: true,
+ }, nil
}
// List returns a list of containers matching the given parameters.
-func (d *Driver) List(
+func (d *Client) List(
ctx context.Context,
- params runtime.ListParams,
-) ([]runtime.Container, error) {
+ params ListParams,
+) ([]Container, error) {
opts := container.ListOptions{}
// Apply state filter
@@ -224,8 +232,8 @@ func (d *Driver) List(
return nil, fmt.Errorf("list containers: %w", err)
}
- // Convert to runtime.Container
- result := make([]runtime.Container, 0, len(containers))
+ // Convert to Container
+ result := make([]Container, 0, len(containers))
for _, c := range containers {
name := ""
if len(c.Names) > 0 {
@@ -233,7 +241,7 @@ func (d *Driver) List(
name = strings.TrimPrefix(c.Names[0], "/")
}
- result = append(result, runtime.Container{
+ result = append(result, Container{
ID: c.ID,
Name: name,
Image: c.Image,
@@ -246,10 +254,10 @@ func (d *Driver) List(
}
// Inspect returns detailed information about a container.
-func (d *Driver) Inspect(
+func (d *Client) Inspect(
ctx context.Context,
id string,
-) (*runtime.ContainerDetail, error) {
+) (*ContainerDetail, error) {
resp, err := d.client.ContainerInspect(ctx, id)
if err != nil {
return nil, fmt.Errorf("inspect container: %w", err)
@@ -268,8 +276,8 @@ func (d *Driver) Inspect(
created = time.Now()
}
- detail := &runtime.ContainerDetail{
- Container: runtime.Container{
+ detail := &ContainerDetail{
+ Container: Container{
ID: resp.ID,
Name: name,
Image: resp.Config.Image,
@@ -281,7 +289,7 @@ func (d *Driver) Inspect(
// Add network settings
if resp.NetworkSettings != nil {
for _, netConfig := range resp.NetworkSettings.Networks {
- detail.NetworkSettings = &runtime.NetworkSettings{
+ detail.NetworkSettings = &NetworkSettings{
IPAddress: netConfig.IPAddress,
Gateway: netConfig.Gateway,
}
@@ -291,12 +299,12 @@ func (d *Driver) Inspect(
// Add port mappings
if resp.HostConfig != nil && resp.HostConfig.PortBindings != nil {
- ports := make([]runtime.PortMapping, 0)
+ ports := make([]PortMapping, 0)
for containerPort, bindings := range resp.HostConfig.PortBindings {
for _, binding := range bindings {
hostPort, _ := strconv.Atoi(binding.HostPort)
cPort, _ := strconv.Atoi(containerPort.Port())
- ports = append(ports, runtime.PortMapping{
+ ports = append(ports, PortMapping{
Host: hostPort,
Container: cPort,
})
@@ -307,9 +315,9 @@ func (d *Driver) Inspect(
// Add mounts
if len(resp.Mounts) > 0 {
- mounts := make([]runtime.VolumeMapping, 0, len(resp.Mounts))
+ mounts := make([]VolumeMapping, 0, len(resp.Mounts))
for _, m := range resp.Mounts {
- mounts = append(mounts, runtime.VolumeMapping{
+ mounts = append(mounts, VolumeMapping{
Host: m.Source,
Container: m.Destination,
})
@@ -326,11 +334,11 @@ func (d *Driver) Inspect(
}
// Exec executes a command in a running container.
-func (d *Driver) Exec(
+func (d *Client) Exec(
ctx context.Context,
id string,
- params runtime.ExecParams,
-) (*runtime.ExecResult, error) {
+ params ExecParams,
+) (*ExecResult, error) {
// Create exec configuration
execConfig := container.ExecOptions{
Cmd: params.Command,
@@ -375,18 +383,19 @@ func (d *Driver) Exec(
return nil, fmt.Errorf("inspect exec: %w", err)
}
- return &runtime.ExecResult{
+ return &ExecResult{
Stdout: stdout.String(),
Stderr: stderr.String(),
ExitCode: inspectResp.ExitCode,
+ Changed: true,
}, nil
}
// Pull pulls a container image from a registry.
-func (d *Driver) Pull(
+func (d *Client) Pull(
ctx context.Context,
imageName string,
-) (*runtime.PullResult, error) {
+) (*PullResult, error) {
pullResp, err := d.client.ImagePull(ctx, imageName, image.PullOptions{})
if err != nil {
return nil, fmt.Errorf("pull image: %w", err)
@@ -422,10 +431,11 @@ func (d *Driver) Pull(
}
}
- result := &runtime.PullResult{
+ result := &PullResult{
ImageID: inspectResp.ID,
Tag: tag,
Size: inspectResp.Size,
+ Changed: true,
}
// Extract digest from last event if available
diff --git a/internal/provider/container/runtime/docker/docker_public_test.go b/internal/provider/docker/docker_public_test.go
similarity index 91%
rename from internal/provider/container/runtime/docker/docker_public_test.go
rename to internal/provider/docker/docker_public_test.go
index 74525ae7..6806de4c 100644
--- a/internal/provider/container/runtime/docker/docker_public_test.go
+++ b/internal/provider/docker/docker_public_test.go
@@ -21,8 +21,7 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/suite"
- "github.com/retr0h/osapi/internal/provider/container/runtime"
- "github.com/retr0h/osapi/internal/provider/container/runtime/docker"
+ dockerprov "github.com/retr0h/osapi/internal/provider/docker"
)
// mockDockerClient embeds dockerclient.APIClient and overrides specific methods for testing.
@@ -259,12 +258,12 @@ func (s *DockerDriverPublicTestSuite) TestNew() {
tests := []struct {
name string
setupEnv func() (cleanup func())
- validateFunc func(d runtime.Driver, err error)
+ validateFunc func(d dockerprov.Provider, err error)
}{
{
name: "returns non-nil driver",
validateFunc: func(
- d runtime.Driver,
+ d dockerprov.Provider,
err error,
) {
s.NoError(err)
@@ -286,7 +285,7 @@ func (s *DockerDriverPublicTestSuite) TestNew() {
}
},
validateFunc: func(
- d runtime.Driver,
+ d dockerprov.Provider,
err error,
) {
s.Error(err)
@@ -303,7 +302,7 @@ func (s *DockerDriverPublicTestSuite) TestNew() {
defer cleanup()
}
- d, err := docker.New()
+ d, err := dockerprov.New()
tt.validateFunc(d, err)
})
}
@@ -350,7 +349,7 @@ func (s *DockerDriverPublicTestSuite) TestPing() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
+ d := dockerprov.NewWithClient(tt.mockClient)
err := d.Ping(s.ctx)
tt.validateFunc(err)
})
@@ -361,8 +360,8 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
tests := []struct {
name string
mockClient *mockDockerClient
- params runtime.CreateParams
- validateFunc func(c *runtime.Container, err error)
+ params dockerprov.CreateParams
+ validateFunc func(c *dockerprov.Container, err error)
}{
{
name: "successful container creation",
@@ -378,12 +377,12 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return container.CreateResponse{ID: "test-id"}, nil
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "nginx:latest",
Name: "test-nginx",
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -412,13 +411,13 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return nil
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "nginx:latest",
Name: "test-nginx-auto",
AutoStart: true,
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -442,13 +441,13 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return container.CreateResponse{ID: "cmd-id"}, nil
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "alpine:latest",
Name: "test-cmd",
Command: []string{"echo", "hello"},
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -473,13 +472,13 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return container.CreateResponse{ID: "env-id"}, nil
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "alpine:latest",
Name: "test-env",
Env: map[string]string{"FOO": "bar"},
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -507,15 +506,15 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return container.CreateResponse{ID: "ports-id"}, nil
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "nginx:latest",
Name: "test-ports",
- Ports: []runtime.PortMapping{
+ Ports: []dockerprov.PortMapping{
{Host: 8080, Container: 80},
},
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -541,15 +540,15 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return container.CreateResponse{ID: "vols-id"}, nil
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "nginx:latest",
Name: "test-vols",
- Volumes: []runtime.VolumeMapping{
+ Volumes: []dockerprov.VolumeMapping{
{Host: "/host/data", Container: "/container/data"},
},
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -571,12 +570,12 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return container.CreateResponse{}, fmt.Errorf("image not found")
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "nonexistent:latest",
Name: "test-fail",
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.Error(err)
@@ -605,13 +604,13 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
return fmt.Errorf("start failed")
},
},
- params: runtime.CreateParams{
+ params: dockerprov.CreateParams{
Image: "nginx:latest",
Name: "test-autostart-fail",
AutoStart: true,
},
validateFunc: func(
- c *runtime.Container,
+ c *dockerprov.Container,
err error,
) {
s.Error(err)
@@ -623,7 +622,7 @@ func (s *DockerDriverPublicTestSuite) TestCreate() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
+ d := dockerprov.NewWithClient(tt.mockClient)
c, err := d.Create(s.ctx, tt.params)
tt.validateFunc(c, err)
})
@@ -678,8 +677,8 @@ func (s *DockerDriverPublicTestSuite) TestStart() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
- err := d.Start(s.ctx, tt.containerID)
+ d := dockerprov.NewWithClient(tt.mockClient)
+ _, err := d.Start(s.ctx, tt.containerID)
tt.validateFunc(err)
})
}
@@ -760,8 +759,8 @@ func (s *DockerDriverPublicTestSuite) TestStop() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
- err := d.Stop(s.ctx, tt.containerID, tt.timeout)
+ d := dockerprov.NewWithClient(tt.mockClient)
+ _, err := d.Stop(s.ctx, tt.containerID, tt.timeout)
tt.validateFunc(err)
})
}
@@ -818,8 +817,8 @@ func (s *DockerDriverPublicTestSuite) TestRemove() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
- err := d.Remove(s.ctx, tt.containerID, tt.force)
+ d := dockerprov.NewWithClient(tt.mockClient)
+ _, err := d.Remove(s.ctx, tt.containerID, tt.force)
tt.validateFunc(err)
})
}
@@ -829,8 +828,8 @@ func (s *DockerDriverPublicTestSuite) TestList() {
tests := []struct {
name string
mockClient *mockDockerClient
- params runtime.ListParams
- validateFunc func(containers []runtime.Container, err error)
+ params dockerprov.ListParams
+ validateFunc func(containers []dockerprov.Container, err error)
}{
{
name: "successful list all containers",
@@ -852,9 +851,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
}, nil
},
},
- params: runtime.ListParams{State: "all"},
+ params: dockerprov.ListParams{State: "all"},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -874,9 +873,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
return []container.Summary{}, nil
},
},
- params: runtime.ListParams{State: "running"},
+ params: dockerprov.ListParams{State: "running"},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -896,9 +895,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
return []container.Summary{}, nil
},
},
- params: runtime.ListParams{State: "stopped"},
+ params: dockerprov.ListParams{State: "stopped"},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -917,9 +916,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
return []container.Summary{}, nil
},
},
- params: runtime.ListParams{State: ""},
+ params: dockerprov.ListParams{State: ""},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -938,9 +937,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
return []container.Summary{}, nil
},
},
- params: runtime.ListParams{State: "all", Limit: 5},
+ params: dockerprov.ListParams{State: "all", Limit: 5},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -965,9 +964,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
}, nil
},
},
- params: runtime.ListParams{State: "all"},
+ params: dockerprov.ListParams{State: "all"},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.NoError(err)
@@ -985,9 +984,9 @@ func (s *DockerDriverPublicTestSuite) TestList() {
return nil, fmt.Errorf("daemon error")
},
},
- params: runtime.ListParams{State: "all"},
+ params: dockerprov.ListParams{State: "all"},
validateFunc: func(
- containers []runtime.Container,
+ containers []dockerprov.Container,
err error,
) {
s.Error(err)
@@ -999,7 +998,7 @@ func (s *DockerDriverPublicTestSuite) TestList() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
+ d := dockerprov.NewWithClient(tt.mockClient)
containers, err := d.List(s.ctx, tt.params)
tt.validateFunc(containers, err)
})
@@ -1011,7 +1010,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
name string
mockClient *mockDockerClient
containerID string
- validateFunc func(detail *runtime.ContainerDetail, err error)
+ validateFunc func(detail *dockerprov.ContainerDetail, err error)
}{
{
name: "successful inspect",
@@ -1033,7 +1032,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "test-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1062,7 +1061,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "nil-state-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1090,7 +1089,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "bad-time-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1126,7 +1125,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "net-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1165,7 +1164,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "ports-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1201,7 +1200,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "mounts-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1236,7 +1235,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "health-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.NoError(err)
@@ -1256,7 +1255,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
},
containerID: "missing-id",
validateFunc: func(
- detail *runtime.ContainerDetail,
+ detail *dockerprov.ContainerDetail,
err error,
) {
s.Error(err)
@@ -1268,7 +1267,7 @@ func (s *DockerDriverPublicTestSuite) TestInspect() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
+ d := dockerprov.NewWithClient(tt.mockClient)
detail, err := d.Inspect(s.ctx, tt.containerID)
tt.validateFunc(detail, err)
})
@@ -1280,8 +1279,8 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
name string
mockClient *mockDockerClient
containerID string
- params runtime.ExecParams
- validateFunc func(result *runtime.ExecResult, err error)
+ params dockerprov.ExecParams
+ validateFunc func(result *dockerprov.ExecResult, err error)
}{
{
name: "successful exec",
@@ -1312,11 +1311,11 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "test-id",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"echo", "hello"},
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.NoError(err)
@@ -1353,12 +1352,12 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "test-id",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"env"},
Env: map[string]string{"MY_VAR": "value"},
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.NoError(err)
@@ -1392,12 +1391,12 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "test-id",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"pwd"},
WorkingDir: "/app",
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.NoError(err)
@@ -1416,11 +1415,11 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "stopped-id",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"ls"},
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.Error(err)
@@ -1447,11 +1446,11 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "test-id",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"ls"},
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.Error(err)
@@ -1478,11 +1477,11 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "container-1",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"ls"},
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.Error(err)
@@ -1515,11 +1514,11 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
},
},
containerID: "test-id",
- params: runtime.ExecParams{
+ params: dockerprov.ExecParams{
Command: []string{"ls"},
},
validateFunc: func(
- result *runtime.ExecResult,
+ result *dockerprov.ExecResult,
err error,
) {
s.Error(err)
@@ -1531,7 +1530,7 @@ func (s *DockerDriverPublicTestSuite) TestExec() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
+ d := dockerprov.NewWithClient(tt.mockClient)
result, err := d.Exec(s.ctx, tt.containerID, tt.params)
tt.validateFunc(result, err)
})
@@ -1543,7 +1542,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
name string
mockClient *mockDockerClient
imageName string
- validateFunc func(result *runtime.PullResult, err error)
+ validateFunc func(result *dockerprov.PullResult, err error)
}{
{
name: "successful image pull",
@@ -1569,7 +1568,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
},
imageName: "nginx:latest",
validateFunc: func(
- result *runtime.PullResult,
+ result *dockerprov.PullResult,
err error,
) {
s.NoError(err)
@@ -1606,7 +1605,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
},
imageName: "nginx:1.25",
validateFunc: func(
- result *runtime.PullResult,
+ result *dockerprov.PullResult,
err error,
) {
s.NoError(err)
@@ -1628,7 +1627,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
},
imageName: "nonexistent:latest",
validateFunc: func(
- result *runtime.PullResult,
+ result *dockerprov.PullResult,
err error,
) {
s.Error(err)
@@ -1650,7 +1649,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
},
imageName: "nginx:latest",
validateFunc: func(
- result *runtime.PullResult,
+ result *dockerprov.PullResult,
err error,
) {
s.Error(err)
@@ -1682,7 +1681,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
},
imageName: "custom-image",
validateFunc: func(
- result *runtime.PullResult,
+ result *dockerprov.PullResult,
err error,
) {
s.NoError(err)
@@ -1710,7 +1709,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
},
imageName: "nginx:latest",
validateFunc: func(
- result *runtime.PullResult,
+ result *dockerprov.PullResult,
err error,
) {
s.Error(err)
@@ -1722,7 +1721,7 @@ func (s *DockerDriverPublicTestSuite) TestPull() {
for _, tt := range tests {
s.Run(tt.name, func() {
- d := docker.NewWithClient(tt.mockClient)
+ d := dockerprov.NewWithClient(tt.mockClient)
result, err := d.Pull(s.ctx, tt.imageName)
tt.validateFunc(result, err)
})
diff --git a/internal/provider/container/mocks/generate.go b/internal/provider/docker/mocks/generate.go
similarity index 100%
rename from internal/provider/container/mocks/generate.go
rename to internal/provider/docker/mocks/generate.go
diff --git a/internal/provider/container/mocks/types.gen.go b/internal/provider/docker/mocks/types.gen.go
similarity index 75%
rename from internal/provider/container/mocks/types.gen.go
rename to internal/provider/docker/mocks/types.gen.go
index abb2ca60..33c658ac 100644
--- a/internal/provider/container/mocks/types.gen.go
+++ b/internal/provider/docker/mocks/types.gen.go
@@ -10,7 +10,7 @@ import (
time "time"
gomock "github.com/golang/mock/gomock"
- runtime "github.com/retr0h/osapi/internal/provider/container/runtime"
+ docker "github.com/retr0h/osapi/internal/provider/docker"
)
// MockProvider is a mock of Provider interface.
@@ -37,10 +37,10 @@ func (m *MockProvider) EXPECT() *MockProviderMockRecorder {
}
// Create mocks base method.
-func (m *MockProvider) Create(ctx context.Context, params runtime.CreateParams) (*runtime.Container, error) {
+func (m *MockProvider) Create(ctx context.Context, params docker.CreateParams) (*docker.Container, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Create", ctx, params)
- ret0, _ := ret[0].(*runtime.Container)
+ ret0, _ := ret[0].(*docker.Container)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -52,10 +52,10 @@ func (mr *MockProviderMockRecorder) Create(ctx, params interface{}) *gomock.Call
}
// Exec mocks base method.
-func (m *MockProvider) Exec(ctx context.Context, id string, params runtime.ExecParams) (*runtime.ExecResult, error) {
+func (m *MockProvider) Exec(ctx context.Context, id string, params docker.ExecParams) (*docker.ExecResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Exec", ctx, id, params)
- ret0, _ := ret[0].(*runtime.ExecResult)
+ ret0, _ := ret[0].(*docker.ExecResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -67,10 +67,10 @@ func (mr *MockProviderMockRecorder) Exec(ctx, id, params interface{}) *gomock.Ca
}
// Inspect mocks base method.
-func (m *MockProvider) Inspect(ctx context.Context, id string) (*runtime.ContainerDetail, error) {
+func (m *MockProvider) Inspect(ctx context.Context, id string) (*docker.ContainerDetail, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Inspect", ctx, id)
- ret0, _ := ret[0].(*runtime.ContainerDetail)
+ ret0, _ := ret[0].(*docker.ContainerDetail)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -82,10 +82,10 @@ func (mr *MockProviderMockRecorder) Inspect(ctx, id interface{}) *gomock.Call {
}
// List mocks base method.
-func (m *MockProvider) List(ctx context.Context, params runtime.ListParams) ([]runtime.Container, error) {
+func (m *MockProvider) List(ctx context.Context, params docker.ListParams) ([]docker.Container, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "List", ctx, params)
- ret0, _ := ret[0].([]runtime.Container)
+ ret0, _ := ret[0].([]docker.Container)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -96,11 +96,25 @@ func (mr *MockProviderMockRecorder) List(ctx, params interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockProvider)(nil).List), ctx, params)
}
+// Ping mocks base method.
+func (m *MockProvider) Ping(ctx context.Context) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Ping", ctx)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// Ping indicates an expected call of Ping.
+func (mr *MockProviderMockRecorder) Ping(ctx interface{}) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockProvider)(nil).Ping), ctx)
+}
+
// Pull mocks base method.
-func (m *MockProvider) Pull(ctx context.Context, image string) (*runtime.PullResult, error) {
+func (m *MockProvider) Pull(ctx context.Context, image string) (*docker.PullResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Pull", ctx, image)
- ret0, _ := ret[0].(*runtime.PullResult)
+ ret0, _ := ret[0].(*docker.PullResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -112,11 +126,12 @@ func (mr *MockProviderMockRecorder) Pull(ctx, image interface{}) *gomock.Call {
}
// Remove mocks base method.
-func (m *MockProvider) Remove(ctx context.Context, id string, force bool) error {
+func (m *MockProvider) Remove(ctx context.Context, id string, force bool) (*docker.ActionResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Remove", ctx, id, force)
- ret0, _ := ret[0].(error)
- return ret0
+ ret0, _ := ret[0].(*docker.ActionResult)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
}
// Remove indicates an expected call of Remove.
@@ -126,11 +141,12 @@ func (mr *MockProviderMockRecorder) Remove(ctx, id, force interface{}) *gomock.C
}
// Start mocks base method.
-func (m *MockProvider) Start(ctx context.Context, id string) error {
+func (m *MockProvider) Start(ctx context.Context, id string) (*docker.ActionResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Start", ctx, id)
- ret0, _ := ret[0].(error)
- return ret0
+ ret0, _ := ret[0].(*docker.ActionResult)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
}
// Start indicates an expected call of Start.
@@ -140,11 +156,12 @@ func (mr *MockProviderMockRecorder) Start(ctx, id interface{}) *gomock.Call {
}
// Stop mocks base method.
-func (m *MockProvider) Stop(ctx context.Context, id string, timeout *time.Duration) error {
+func (m *MockProvider) Stop(ctx context.Context, id string, timeout *time.Duration) (*docker.ActionResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Stop", ctx, id, timeout)
- ret0, _ := ret[0].(error)
- return ret0
+ ret0, _ := ret[0].(*docker.ActionResult)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
}
// Stop indicates an expected call of Stop.
diff --git a/internal/provider/container/runtime/driver.go b/internal/provider/docker/types.go
similarity index 83%
rename from internal/provider/container/runtime/driver.go
rename to internal/provider/docker/types.go
index 6df455c8..17f6f281 100644
--- a/internal/provider/container/runtime/driver.go
+++ b/internal/provider/docker/types.go
@@ -1,14 +1,15 @@
-// Package runtime defines the container runtime driver interface.
-package runtime
+// Package docker provides the Docker container management provider.
+package docker
import (
"context"
"time"
)
-// Driver defines container runtime operations.
-// Implementations: Docker (now), LXD/Podman (later).
-type Driver interface {
+// Provider defines the Docker container management interface.
+// All methods accept context.Context for cancellation and timeout propagation,
+// which is important since the Docker daemon is a remote service.
+type Provider interface {
Ping(
ctx context.Context,
) error
@@ -21,19 +22,19 @@ type Driver interface {
Start(
ctx context.Context,
id string,
- ) error
+ ) (*ActionResult, error)
Stop(
ctx context.Context,
id string,
timeout *time.Duration,
- ) error
+ ) (*ActionResult, error)
Remove(
ctx context.Context,
id string,
force bool,
- ) error
+ ) (*ActionResult, error)
List(
ctx context.Context,
@@ -102,6 +103,13 @@ type Container struct {
Image string `json:"image"`
State string `json:"state"`
Created time.Time `json:"created"`
+ Changed bool `json:"changed"`
+}
+
+// ActionResult holds the result of a lifecycle action (start, stop, remove).
+type ActionResult struct {
+ Message string `json:"message"`
+ Changed bool `json:"changed"`
}
// ContainerDetail holds detailed info for a container.
@@ -134,6 +142,7 @@ type ExecResult struct {
Stdout string `json:"stdout"`
Stderr string `json:"stderr"`
ExitCode int `json:"exit_code"`
+ Changed bool `json:"changed"`
}
// PullResult contains the result of an image pull.
@@ -141,4 +150,5 @@ type PullResult struct {
ImageID string `json:"image_id"`
Tag string `json:"tag"`
Size int64 `json:"size"`
+ Changed bool `json:"changed"`
}
diff --git a/internal/provider/registry/registry.go b/internal/provider/registry/registry.go
deleted file mode 100644
index f9a05f3f..00000000
--- a/internal/provider/registry/registry.go
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-// Package registry provides a runtime registry for provider operations.
-package registry
-
-import "context"
-
-// OperationSpec defines how to create params and run an operation.
-type OperationSpec struct {
- NewParams func() any
- Run func(ctx context.Context, params any) (any, error)
-}
-
-// Registration describes a provider and its operations.
-type Registration struct {
- Name string
- Operations map[string]OperationSpec
-}
-
-// Registry holds provider registrations.
-type Registry struct {
- providers map[string]Registration
-}
-
-// New creates a new empty registry.
-func New() *Registry {
- return &Registry{
- providers: make(map[string]Registration),
- }
-}
-
-// Register adds a provider registration.
-func (r *Registry) Register(
- reg Registration,
-) {
- r.providers[reg.Name] = reg
-}
-
-// Lookup finds an operation spec by provider and operation name.
-func (r *Registry) Lookup(
- provider string,
- operation string,
-) (*OperationSpec, bool) {
- reg, ok := r.providers[provider]
- if !ok {
- return nil, false
- }
-
- spec, ok := reg.Operations[operation]
- if !ok {
- return nil, false
- }
-
- return &spec, true
-}
diff --git a/internal/provider/registry/registry_public_test.go b/internal/provider/registry/registry_public_test.go
deleted file mode 100644
index 4befa466..00000000
--- a/internal/provider/registry/registry_public_test.go
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package registry_test
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/suite"
-
- "github.com/retr0h/osapi/internal/provider/registry"
-)
-
-type RegistryPublicTestSuite struct {
- suite.Suite
-}
-
-func (suite *RegistryPublicTestSuite) SetupTest() {}
-
-func (suite *RegistryPublicTestSuite) TearDownTest() {}
-
-func (suite *RegistryPublicTestSuite) TestLookup() {
- tests := []struct {
- name string
- register bool
- provider string
- operation string
- validateFunc func(spec *registry.OperationSpec, found bool)
- }{
- {
- name: "when registered provider found",
- register: true,
- provider: "container",
- operation: "create",
- validateFunc: func(spec *registry.OperationSpec, found bool) {
- suite.True(found)
- suite.NotNil(spec)
- suite.NotNil(spec.NewParams)
- suite.NotNil(spec.Run)
- },
- },
- {
- name: "when unregistered provider not found",
- register: false,
- provider: "nonexistent",
- operation: "create",
- validateFunc: func(spec *registry.OperationSpec, found bool) {
- suite.False(found)
- suite.Nil(spec)
- },
- },
- {
- name: "when registered provider wrong operation",
- register: true,
- provider: "container",
- operation: "nonexistent",
- validateFunc: func(spec *registry.OperationSpec, found bool) {
- suite.False(found)
- suite.Nil(spec)
- },
- },
- {
- name: "when run returns expected result",
- register: true,
- provider: "container",
- operation: "create",
- validateFunc: func(spec *registry.OperationSpec, found bool) {
- suite.Require().True(found)
- suite.Require().NotNil(spec)
-
- params := spec.NewParams()
- suite.Equal("default-params", params)
-
- result, err := spec.Run(context.Background(), params)
- suite.NoError(err)
- suite.Equal("created", result)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- r := registry.New()
-
- if tc.register {
- r.Register(registry.Registration{
- Name: "container",
- Operations: map[string]registry.OperationSpec{
- "create": {
- NewParams: func() any {
- return "default-params"
- },
- Run: func(
- _ context.Context,
- _ any,
- ) (any, error) {
- return "created", nil
- },
- },
- },
- })
- }
-
- spec, found := r.Lookup(tc.provider, tc.operation)
- tc.validateFunc(spec, found)
- })
- }
-}
-
-// In order for `go test` to run this suite, we need to create
-// a normal test function and pass our suite to suite.Run.
-func TestRegistryPublicTestSuite(t *testing.T) {
- suite.Run(t, new(RegistryPublicTestSuite))
-}
diff --git a/pkg/sdk/client/container.go b/pkg/sdk/client/docker.go
similarity index 63%
rename from pkg/sdk/client/container.go
rename to pkg/sdk/client/docker.go
index 85981c4e..5e8cc585 100644
--- a/pkg/sdk/client/container.go
+++ b/pkg/sdk/client/docker.go
@@ -27,20 +27,20 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// ContainerService provides container management operations.
-type ContainerService struct {
+// DockerService provides Docker container management operations.
+type DockerService struct {
client *gen.ClientWithResponses
}
// Create creates a new container on the target host.
-func (s *ContainerService) Create(
+func (s *DockerService) Create(
ctx context.Context,
hostname string,
- body gen.ContainerCreateRequest,
-) (*Response[Collection[ContainerResult]], error) {
- resp, err := s.client.PostNodeContainerWithResponse(ctx, hostname, body)
+ body gen.DockerCreateRequest,
+) (*Response[Collection[DockerResult]], error) {
+ resp, err := s.client.PostNodeContainerDockerWithResponse(ctx, hostname, body)
if err != nil {
- return nil, fmt.Errorf("create container: %w", err)
+ return nil, fmt.Errorf("docker create: %w", err)
}
if err := checkError(
@@ -60,18 +60,18 @@ func (s *ContainerService) Create(
}}
}
- return NewResponse(containerResultCollectionFromGen(resp.JSON202), resp.Body), nil
+ return NewResponse(dockerResultCollectionFromGen(resp.JSON202), resp.Body), nil
}
// List lists containers on the target host, optionally filtered by state.
-func (s *ContainerService) List(
+func (s *DockerService) List(
ctx context.Context,
hostname string,
- params *gen.GetNodeContainerParams,
-) (*Response[Collection[ContainerListResult]], error) {
- resp, err := s.client.GetNodeContainerWithResponse(ctx, hostname, params)
+ params *gen.GetNodeContainerDockerParams,
+) (*Response[Collection[DockerListResult]], error) {
+ resp, err := s.client.GetNodeContainerDockerWithResponse(ctx, hostname, params)
if err != nil {
- return nil, fmt.Errorf("list containers: %w", err)
+ return nil, fmt.Errorf("docker list: %w", err)
}
if err := checkError(
@@ -91,18 +91,18 @@ func (s *ContainerService) List(
}}
}
- return NewResponse(containerListCollectionFromGen(resp.JSON200), resp.Body), nil
+ return NewResponse(dockerListCollectionFromGen(resp.JSON200), resp.Body), nil
}
// Inspect retrieves detailed information about a specific container.
-func (s *ContainerService) Inspect(
+func (s *DockerService) Inspect(
ctx context.Context,
hostname string,
id string,
-) (*Response[Collection[ContainerDetailResult]], error) {
- resp, err := s.client.GetNodeContainerByIDWithResponse(ctx, hostname, id)
+) (*Response[Collection[DockerDetailResult]], error) {
+ resp, err := s.client.GetNodeContainerDockerByIDWithResponse(ctx, hostname, id)
if err != nil {
- return nil, fmt.Errorf("inspect container: %w", err)
+ return nil, fmt.Errorf("docker inspect: %w", err)
}
if err := checkError(
@@ -123,18 +123,18 @@ func (s *ContainerService) Inspect(
}}
}
- return NewResponse(containerDetailCollectionFromGen(resp.JSON200), resp.Body), nil
+ return NewResponse(dockerDetailCollectionFromGen(resp.JSON200), resp.Body), nil
}
// Start starts a stopped container on the target host.
-func (s *ContainerService) Start(
+func (s *DockerService) Start(
ctx context.Context,
hostname string,
id string,
-) (*Response[Collection[ContainerActionResult]], error) {
- resp, err := s.client.PostNodeContainerStartWithResponse(ctx, hostname, id)
+) (*Response[Collection[DockerActionResult]], error) {
+ resp, err := s.client.PostNodeContainerDockerStartWithResponse(ctx, hostname, id)
if err != nil {
- return nil, fmt.Errorf("start container: %w", err)
+ return nil, fmt.Errorf("docker start: %w", err)
}
if err := checkError(
@@ -155,19 +155,19 @@ func (s *ContainerService) Start(
}}
}
- return NewResponse(containerActionCollectionFromGen(resp.JSON202), resp.Body), nil
+ return NewResponse(dockerActionCollectionFromGen(resp.JSON202), resp.Body), nil
}
// Stop stops a running container on the target host.
-func (s *ContainerService) Stop(
+func (s *DockerService) Stop(
ctx context.Context,
hostname string,
id string,
- body gen.ContainerStopRequest,
-) (*Response[Collection[ContainerActionResult]], error) {
- resp, err := s.client.PostNodeContainerStopWithResponse(ctx, hostname, id, body)
+ body gen.DockerStopRequest,
+) (*Response[Collection[DockerActionResult]], error) {
+ resp, err := s.client.PostNodeContainerDockerStopWithResponse(ctx, hostname, id, body)
if err != nil {
- return nil, fmt.Errorf("stop container: %w", err)
+ return nil, fmt.Errorf("docker stop: %w", err)
}
if err := checkError(
@@ -188,19 +188,19 @@ func (s *ContainerService) Stop(
}}
}
- return NewResponse(containerActionCollectionFromGen(resp.JSON202), resp.Body), nil
+ return NewResponse(dockerActionCollectionFromGen(resp.JSON202), resp.Body), nil
}
// Remove removes a container from the target host.
-func (s *ContainerService) Remove(
+func (s *DockerService) Remove(
ctx context.Context,
hostname string,
id string,
- params *gen.DeleteNodeContainerByIDParams,
-) (*Response[Collection[ContainerActionResult]], error) {
- resp, err := s.client.DeleteNodeContainerByIDWithResponse(ctx, hostname, id, params)
+ params *gen.DeleteNodeContainerDockerByIDParams,
+) (*Response[Collection[DockerActionResult]], error) {
+ resp, err := s.client.DeleteNodeContainerDockerByIDWithResponse(ctx, hostname, id, params)
if err != nil {
- return nil, fmt.Errorf("remove container: %w", err)
+ return nil, fmt.Errorf("docker remove: %w", err)
}
if err := checkError(
@@ -221,19 +221,19 @@ func (s *ContainerService) Remove(
}}
}
- return NewResponse(containerActionCollectionFromGen(resp.JSON202), resp.Body), nil
+ return NewResponse(dockerActionCollectionFromGen(resp.JSON202), resp.Body), nil
}
// Exec executes a command inside a running container on the target host.
-func (s *ContainerService) Exec(
+func (s *DockerService) Exec(
ctx context.Context,
hostname string,
id string,
- body gen.ContainerExecRequest,
-) (*Response[Collection[ContainerExecResult]], error) {
- resp, err := s.client.PostNodeContainerExecWithResponse(ctx, hostname, id, body)
+ body gen.DockerExecRequest,
+) (*Response[Collection[DockerExecResult]], error) {
+ resp, err := s.client.PostNodeContainerDockerExecWithResponse(ctx, hostname, id, body)
if err != nil {
- return nil, fmt.Errorf("exec in container: %w", err)
+ return nil, fmt.Errorf("docker exec: %w", err)
}
if err := checkError(
@@ -254,18 +254,18 @@ func (s *ContainerService) Exec(
}}
}
- return NewResponse(containerExecCollectionFromGen(resp.JSON202), resp.Body), nil
+ return NewResponse(dockerExecCollectionFromGen(resp.JSON202), resp.Body), nil
}
// Pull pulls a container image on the target host.
-func (s *ContainerService) Pull(
+func (s *DockerService) Pull(
ctx context.Context,
hostname string,
- body gen.ContainerPullRequest,
-) (*Response[Collection[ContainerPullResult]], error) {
- resp, err := s.client.PostNodeContainerPullWithResponse(ctx, hostname, body)
+ body gen.DockerPullRequest,
+) (*Response[Collection[DockerPullResult]], error) {
+ resp, err := s.client.PostNodeContainerDockerPullWithResponse(ctx, hostname, body)
if err != nil {
- return nil, fmt.Errorf("pull image: %w", err)
+ return nil, fmt.Errorf("docker pull: %w", err)
}
if err := checkError(
@@ -285,5 +285,5 @@ func (s *ContainerService) Pull(
}}
}
- return NewResponse(containerPullCollectionFromGen(resp.JSON202), resp.Body), nil
+ return NewResponse(dockerPullCollectionFromGen(resp.JSON202), resp.Body), nil
}
diff --git a/pkg/sdk/client/container_public_test.go b/pkg/sdk/client/docker_public_test.go
similarity index 83%
rename from pkg/sdk/client/container_public_test.go
rename to pkg/sdk/client/docker_public_test.go
index 70fdf78e..57bb154b 100644
--- a/pkg/sdk/client/container_public_test.go
+++ b/pkg/sdk/client/docker_public_test.go
@@ -34,22 +34,22 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-type ContainerPublicTestSuite struct {
+type DockerPublicTestSuite struct {
suite.Suite
ctx context.Context
}
-func (suite *ContainerPublicTestSuite) SetupTest() {
+func (suite *DockerPublicTestSuite) SetupTest() {
suite.ctx = context.Background()
}
-func (suite *ContainerPublicTestSuite) TestCreate() {
+func (suite *DockerPublicTestSuite) TestCreate() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerResult]], error)
}{
{
name: "when creating container returns result",
@@ -63,7 +63,7 @@ func (suite *ContainerPublicTestSuite) TestCreate() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerResult]],
+ resp *client.Response[client.Collection[client.DockerResult]],
err error,
) {
suite.NoError(err)
@@ -87,7 +87,7 @@ func (suite *ContainerPublicTestSuite) TestCreate() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerResult]],
+ resp *client.Response[client.Collection[client.DockerResult]],
err error,
) {
suite.Error(err)
@@ -102,12 +102,12 @@ func (suite *ContainerPublicTestSuite) TestCreate() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerResult]],
+ resp *client.Response[client.Collection[client.DockerResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "create container")
+ suite.Contains(err.Error(), "docker create")
},
},
{
@@ -116,7 +116,7 @@ func (suite *ContainerPublicTestSuite) TestCreate() {
w.WriteHeader(http.StatusAccepted)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerResult]],
+ resp *client.Response[client.Collection[client.DockerResult]],
err error,
) {
suite.Error(err)
@@ -153,10 +153,10 @@ func (suite *ContainerPublicTestSuite) TestCreate() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Create(
+ resp, err := sut.Docker.Create(
suite.ctx,
"_any",
- gen.ContainerCreateRequest{
+ gen.DockerCreateRequest{
Image: "nginx:latest",
Name: strPtr("my-nginx"),
},
@@ -166,12 +166,12 @@ func (suite *ContainerPublicTestSuite) TestCreate() {
}
}
-func (suite *ContainerPublicTestSuite) TestList() {
+func (suite *DockerPublicTestSuite) TestList() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerListResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerListResult]], error)
}{
{
name: "when listing containers returns results",
@@ -185,7 +185,7 @@ func (suite *ContainerPublicTestSuite) TestList() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerListResult]],
+ resp *client.Response[client.Collection[client.DockerListResult]],
err error,
) {
suite.NoError(err)
@@ -206,7 +206,7 @@ func (suite *ContainerPublicTestSuite) TestList() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerListResult]],
+ resp *client.Response[client.Collection[client.DockerListResult]],
err error,
) {
suite.Error(err)
@@ -221,12 +221,12 @@ func (suite *ContainerPublicTestSuite) TestList() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerListResult]],
+ resp *client.Response[client.Collection[client.DockerListResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "list containers")
+ suite.Contains(err.Error(), "docker list")
},
},
{
@@ -235,7 +235,7 @@ func (suite *ContainerPublicTestSuite) TestList() {
w.WriteHeader(http.StatusOK)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerListResult]],
+ resp *client.Response[client.Collection[client.DockerListResult]],
err error,
) {
suite.Error(err)
@@ -272,18 +272,18 @@ func (suite *ContainerPublicTestSuite) TestList() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.List(suite.ctx, "_any", nil)
+ resp, err := sut.Docker.List(suite.ctx, "_any", nil)
tc.validateFunc(resp, err)
})
}
}
-func (suite *ContainerPublicTestSuite) TestInspect() {
+func (suite *DockerPublicTestSuite) TestInspect() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerDetailResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerDetailResult]], error)
}{
{
name: "when inspecting container returns result",
@@ -297,7 +297,7 @@ func (suite *ContainerPublicTestSuite) TestInspect() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerDetailResult]],
+ resp *client.Response[client.Collection[client.DockerDetailResult]],
err error,
) {
suite.NoError(err)
@@ -327,7 +327,7 @@ func (suite *ContainerPublicTestSuite) TestInspect() {
_, _ = w.Write([]byte(`{"error":"container not found"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerDetailResult]],
+ resp *client.Response[client.Collection[client.DockerDetailResult]],
err error,
) {
suite.Error(err)
@@ -346,7 +346,7 @@ func (suite *ContainerPublicTestSuite) TestInspect() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerDetailResult]],
+ resp *client.Response[client.Collection[client.DockerDetailResult]],
err error,
) {
suite.Error(err)
@@ -361,12 +361,12 @@ func (suite *ContainerPublicTestSuite) TestInspect() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerDetailResult]],
+ resp *client.Response[client.Collection[client.DockerDetailResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "inspect container")
+ suite.Contains(err.Error(), "docker inspect")
},
},
{
@@ -375,7 +375,7 @@ func (suite *ContainerPublicTestSuite) TestInspect() {
w.WriteHeader(http.StatusOK)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerDetailResult]],
+ resp *client.Response[client.Collection[client.DockerDetailResult]],
err error,
) {
suite.Error(err)
@@ -412,18 +412,18 @@ func (suite *ContainerPublicTestSuite) TestInspect() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Inspect(suite.ctx, "_any", "abc123")
+ resp, err := sut.Docker.Inspect(suite.ctx, "_any", "abc123")
tc.validateFunc(resp, err)
})
}
}
-func (suite *ContainerPublicTestSuite) TestStart() {
+func (suite *DockerPublicTestSuite) TestStart() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerActionResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerActionResult]], error)
}{
{
name: "when starting container returns result",
@@ -437,7 +437,7 @@ func (suite *ContainerPublicTestSuite) TestStart() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.NoError(err)
@@ -458,7 +458,7 @@ func (suite *ContainerPublicTestSuite) TestStart() {
_, _ = w.Write([]byte(`{"error":"container not found"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -477,7 +477,7 @@ func (suite *ContainerPublicTestSuite) TestStart() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -492,12 +492,12 @@ func (suite *ContainerPublicTestSuite) TestStart() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "start container")
+ suite.Contains(err.Error(), "docker start")
},
},
{
@@ -506,7 +506,7 @@ func (suite *ContainerPublicTestSuite) TestStart() {
w.WriteHeader(http.StatusAccepted)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -543,18 +543,18 @@ func (suite *ContainerPublicTestSuite) TestStart() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Start(suite.ctx, "_any", "abc123")
+ resp, err := sut.Docker.Start(suite.ctx, "_any", "abc123")
tc.validateFunc(resp, err)
})
}
}
-func (suite *ContainerPublicTestSuite) TestStop() {
+func (suite *DockerPublicTestSuite) TestStop() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerActionResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerActionResult]], error)
}{
{
name: "when stopping container returns result",
@@ -568,7 +568,7 @@ func (suite *ContainerPublicTestSuite) TestStop() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.NoError(err)
@@ -589,7 +589,7 @@ func (suite *ContainerPublicTestSuite) TestStop() {
_, _ = w.Write([]byte(`{"error":"container not found"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -608,7 +608,7 @@ func (suite *ContainerPublicTestSuite) TestStop() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -623,12 +623,12 @@ func (suite *ContainerPublicTestSuite) TestStop() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "stop container")
+ suite.Contains(err.Error(), "docker stop")
},
},
{
@@ -637,7 +637,7 @@ func (suite *ContainerPublicTestSuite) TestStop() {
w.WriteHeader(http.StatusAccepted)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -674,23 +674,23 @@ func (suite *ContainerPublicTestSuite) TestStop() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Stop(
+ resp, err := sut.Docker.Stop(
suite.ctx,
"_any",
"abc123",
- gen.ContainerStopRequest{},
+ gen.DockerStopRequest{},
)
tc.validateFunc(resp, err)
})
}
}
-func (suite *ContainerPublicTestSuite) TestRemove() {
+func (suite *DockerPublicTestSuite) TestRemove() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerActionResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerActionResult]], error)
}{
{
name: "when removing container returns result",
@@ -704,7 +704,7 @@ func (suite *ContainerPublicTestSuite) TestRemove() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.NoError(err)
@@ -725,7 +725,7 @@ func (suite *ContainerPublicTestSuite) TestRemove() {
_, _ = w.Write([]byte(`{"error":"container not found"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -744,7 +744,7 @@ func (suite *ContainerPublicTestSuite) TestRemove() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -759,12 +759,12 @@ func (suite *ContainerPublicTestSuite) TestRemove() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "remove container")
+ suite.Contains(err.Error(), "docker remove")
},
},
{
@@ -773,7 +773,7 @@ func (suite *ContainerPublicTestSuite) TestRemove() {
w.WriteHeader(http.StatusAccepted)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerActionResult]],
+ resp *client.Response[client.Collection[client.DockerActionResult]],
err error,
) {
suite.Error(err)
@@ -810,18 +810,18 @@ func (suite *ContainerPublicTestSuite) TestRemove() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Remove(suite.ctx, "_any", "abc123", nil)
+ resp, err := sut.Docker.Remove(suite.ctx, "_any", "abc123", nil)
tc.validateFunc(resp, err)
})
}
}
-func (suite *ContainerPublicTestSuite) TestExec() {
+func (suite *DockerPublicTestSuite) TestExec() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerExecResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerExecResult]], error)
}{
{
name: "when executing command returns result",
@@ -835,7 +835,7 @@ func (suite *ContainerPublicTestSuite) TestExec() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerExecResult]],
+ resp *client.Response[client.Collection[client.DockerExecResult]],
err error,
) {
suite.NoError(err)
@@ -857,7 +857,7 @@ func (suite *ContainerPublicTestSuite) TestExec() {
_, _ = w.Write([]byte(`{"error":"container not found"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerExecResult]],
+ resp *client.Response[client.Collection[client.DockerExecResult]],
err error,
) {
suite.Error(err)
@@ -876,7 +876,7 @@ func (suite *ContainerPublicTestSuite) TestExec() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerExecResult]],
+ resp *client.Response[client.Collection[client.DockerExecResult]],
err error,
) {
suite.Error(err)
@@ -891,12 +891,12 @@ func (suite *ContainerPublicTestSuite) TestExec() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerExecResult]],
+ resp *client.Response[client.Collection[client.DockerExecResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "exec in container")
+ suite.Contains(err.Error(), "docker exec")
},
},
{
@@ -905,7 +905,7 @@ func (suite *ContainerPublicTestSuite) TestExec() {
w.WriteHeader(http.StatusAccepted)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerExecResult]],
+ resp *client.Response[client.Collection[client.DockerExecResult]],
err error,
) {
suite.Error(err)
@@ -942,11 +942,11 @@ func (suite *ContainerPublicTestSuite) TestExec() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Exec(
+ resp, err := sut.Docker.Exec(
suite.ctx,
"_any",
"abc123",
- gen.ContainerExecRequest{
+ gen.DockerExecRequest{
Command: []string{"echo", "hello"},
},
)
@@ -955,12 +955,12 @@ func (suite *ContainerPublicTestSuite) TestExec() {
}
}
-func (suite *ContainerPublicTestSuite) TestPull() {
+func (suite *DockerPublicTestSuite) TestPull() {
tests := []struct {
name string
handler http.HandlerFunc
serverURL string
- validateFunc func(*client.Response[client.Collection[client.ContainerPullResult]], error)
+ validateFunc func(*client.Response[client.Collection[client.DockerPullResult]], error)
}{
{
name: "when pulling image returns result",
@@ -974,7 +974,7 @@ func (suite *ContainerPublicTestSuite) TestPull() {
)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerPullResult]],
+ resp *client.Response[client.Collection[client.DockerPullResult]],
err error,
) {
suite.NoError(err)
@@ -996,7 +996,7 @@ func (suite *ContainerPublicTestSuite) TestPull() {
_, _ = w.Write([]byte(`{"error":"forbidden"}`))
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerPullResult]],
+ resp *client.Response[client.Collection[client.DockerPullResult]],
err error,
) {
suite.Error(err)
@@ -1011,12 +1011,12 @@ func (suite *ContainerPublicTestSuite) TestPull() {
name: "when client HTTP call fails returns error",
serverURL: "http://127.0.0.1:0",
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerPullResult]],
+ resp *client.Response[client.Collection[client.DockerPullResult]],
err error,
) {
suite.Error(err)
suite.Nil(resp)
- suite.Contains(err.Error(), "pull image")
+ suite.Contains(err.Error(), "docker pull")
},
},
{
@@ -1025,7 +1025,7 @@ func (suite *ContainerPublicTestSuite) TestPull() {
w.WriteHeader(http.StatusAccepted)
},
validateFunc: func(
- resp *client.Response[client.Collection[client.ContainerPullResult]],
+ resp *client.Response[client.Collection[client.DockerPullResult]],
err error,
) {
suite.Error(err)
@@ -1062,10 +1062,10 @@ func (suite *ContainerPublicTestSuite) TestPull() {
client.WithLogger(slog.Default()),
)
- resp, err := sut.Container.Pull(
+ resp, err := sut.Docker.Pull(
suite.ctx,
"_any",
- gen.ContainerPullRequest{
+ gen.DockerPullRequest{
Image: "nginx:latest",
},
)
@@ -1080,6 +1080,6 @@ func strPtr(
return &s
}
-func TestContainerPublicTestSuite(t *testing.T) {
- suite.Run(t, new(ContainerPublicTestSuite))
+func TestDockerPublicTestSuite(t *testing.T) {
+ suite.Run(t, new(DockerPublicTestSuite))
}
diff --git a/pkg/sdk/client/container_types.go b/pkg/sdk/client/docker_types.go
similarity index 58%
rename from pkg/sdk/client/container_types.go
rename to pkg/sdk/client/docker_types.go
index 937def43..248531fb 100644
--- a/pkg/sdk/client/container_types.go
+++ b/pkg/sdk/client/docker_types.go
@@ -24,8 +24,8 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-// ContainerResult represents a container create result from a single agent.
-type ContainerResult struct {
+// DockerResult represents a docker container create result from a single agent.
+type DockerResult struct {
Hostname string
ID string
Name string
@@ -36,16 +36,16 @@ type ContainerResult struct {
Error string
}
-// ContainerListResult represents a container list result from a single agent.
-type ContainerListResult struct {
+// DockerListResult represents a docker container list result from a single agent.
+type DockerListResult struct {
Hostname string
- Containers []ContainerSummaryItem
+ Containers []DockerSummaryItem
Changed bool
Error string
}
-// ContainerSummaryItem represents a brief container summary.
-type ContainerSummaryItem struct {
+// DockerSummaryItem represents a brief docker container summary.
+type DockerSummaryItem struct {
ID string
Name string
Image string
@@ -53,8 +53,8 @@ type ContainerSummaryItem struct {
Created string
}
-// ContainerDetailResult represents a container inspect result from a single agent.
-type ContainerDetailResult struct {
+// DockerDetailResult represents a docker container inspect result from a single agent.
+type DockerDetailResult struct {
Hostname string
ID string
Name string
@@ -70,8 +70,8 @@ type ContainerDetailResult struct {
Error string
}
-// ContainerActionResult represents a container lifecycle action result from a single agent.
-type ContainerActionResult struct {
+// DockerActionResult represents a docker container lifecycle action result from a single agent.
+type DockerActionResult struct {
Hostname string
ID string
Message string
@@ -79,8 +79,8 @@ type ContainerActionResult struct {
Error string
}
-// ContainerExecResult represents a container exec result from a single agent.
-type ContainerExecResult struct {
+// DockerExecResult represents a docker container exec result from a single agent.
+type DockerExecResult struct {
Hostname string
Stdout string
Stderr string
@@ -89,8 +89,8 @@ type ContainerExecResult struct {
Error string
}
-// ContainerPullResult represents an image pull result from a single agent.
-type ContainerPullResult struct {
+// DockerPullResult represents a docker image pull result from a single agent.
+type DockerPullResult struct {
Hostname string
ImageID string
Tag string
@@ -99,14 +99,14 @@ type ContainerPullResult struct {
Error string
}
-// containerResultCollectionFromGen converts a gen.ContainerResultCollectionResponse
-// to a Collection[ContainerResult].
-func containerResultCollectionFromGen(
- g *gen.ContainerResultCollectionResponse,
-) Collection[ContainerResult] {
- results := make([]ContainerResult, 0, len(g.Results))
+// dockerResultCollectionFromGen converts a gen.DockerResultCollectionResponse
+// to a Collection[DockerResult].
+func dockerResultCollectionFromGen(
+ g *gen.DockerResultCollectionResponse,
+) Collection[DockerResult] {
+ results := make([]DockerResult, 0, len(g.Results))
for _, r := range g.Results {
- results = append(results, ContainerResult{
+ results = append(results, DockerResult{
Hostname: r.Hostname,
ID: derefString(r.Id),
Name: derefString(r.Name),
@@ -118,29 +118,29 @@ func containerResultCollectionFromGen(
})
}
- return Collection[ContainerResult]{
+ return Collection[DockerResult]{
Results: results,
JobID: jobIDFromGen(g.JobId),
}
}
-// containerListCollectionFromGen converts a gen.ContainerListCollectionResponse
-// to a Collection[ContainerListResult].
-func containerListCollectionFromGen(
- g *gen.ContainerListCollectionResponse,
-) Collection[ContainerListResult] {
- results := make([]ContainerListResult, 0, len(g.Results))
+// dockerListCollectionFromGen converts a gen.DockerListCollectionResponse
+// to a Collection[DockerListResult].
+func dockerListCollectionFromGen(
+ g *gen.DockerListCollectionResponse,
+) Collection[DockerListResult] {
+ results := make([]DockerListResult, 0, len(g.Results))
for _, r := range g.Results {
- item := ContainerListResult{
+ item := DockerListResult{
Hostname: r.Hostname,
Changed: derefBool(r.Changed),
Error: derefString(r.Error),
}
if r.Containers != nil {
- containers := make([]ContainerSummaryItem, 0, len(*r.Containers))
+ containers := make([]DockerSummaryItem, 0, len(*r.Containers))
for _, c := range *r.Containers {
- containers = append(containers, ContainerSummaryItem{
+ containers = append(containers, DockerSummaryItem{
ID: derefString(c.Id),
Name: derefString(c.Name),
Image: derefString(c.Image),
@@ -155,20 +155,20 @@ func containerListCollectionFromGen(
results = append(results, item)
}
- return Collection[ContainerListResult]{
+ return Collection[DockerListResult]{
Results: results,
JobID: jobIDFromGen(g.JobId),
}
}
-// containerDetailCollectionFromGen converts a gen.ContainerDetailCollectionResponse
-// to a Collection[ContainerDetailResult].
-func containerDetailCollectionFromGen(
- g *gen.ContainerDetailCollectionResponse,
-) Collection[ContainerDetailResult] {
- results := make([]ContainerDetailResult, 0, len(g.Results))
+// dockerDetailCollectionFromGen converts a gen.DockerDetailCollectionResponse
+// to a Collection[DockerDetailResult].
+func dockerDetailCollectionFromGen(
+ g *gen.DockerDetailCollectionResponse,
+) Collection[DockerDetailResult] {
+ results := make([]DockerDetailResult, 0, len(g.Results))
for _, r := range g.Results {
- item := ContainerDetailResult{
+ item := DockerDetailResult{
Hostname: r.Hostname,
ID: derefString(r.Id),
Name: derefString(r.Name),
@@ -199,20 +199,20 @@ func containerDetailCollectionFromGen(
results = append(results, item)
}
- return Collection[ContainerDetailResult]{
+ return Collection[DockerDetailResult]{
Results: results,
JobID: jobIDFromGen(g.JobId),
}
}
-// containerActionCollectionFromGen converts a gen.ContainerActionCollectionResponse
-// to a Collection[ContainerActionResult].
-func containerActionCollectionFromGen(
- g *gen.ContainerActionCollectionResponse,
-) Collection[ContainerActionResult] {
- results := make([]ContainerActionResult, 0, len(g.Results))
+// dockerActionCollectionFromGen converts a gen.DockerActionCollectionResponse
+// to a Collection[DockerActionResult].
+func dockerActionCollectionFromGen(
+ g *gen.DockerActionCollectionResponse,
+) Collection[DockerActionResult] {
+ results := make([]DockerActionResult, 0, len(g.Results))
for _, r := range g.Results {
- results = append(results, ContainerActionResult{
+ results = append(results, DockerActionResult{
Hostname: r.Hostname,
ID: derefString(r.Id),
Message: derefString(r.Message),
@@ -221,20 +221,20 @@ func containerActionCollectionFromGen(
})
}
- return Collection[ContainerActionResult]{
+ return Collection[DockerActionResult]{
Results: results,
JobID: jobIDFromGen(g.JobId),
}
}
-// containerExecCollectionFromGen converts a gen.ContainerExecCollectionResponse
-// to a Collection[ContainerExecResult].
-func containerExecCollectionFromGen(
- g *gen.ContainerExecCollectionResponse,
-) Collection[ContainerExecResult] {
- results := make([]ContainerExecResult, 0, len(g.Results))
+// dockerExecCollectionFromGen converts a gen.DockerExecCollectionResponse
+// to a Collection[DockerExecResult].
+func dockerExecCollectionFromGen(
+ g *gen.DockerExecCollectionResponse,
+) Collection[DockerExecResult] {
+ results := make([]DockerExecResult, 0, len(g.Results))
for _, r := range g.Results {
- results = append(results, ContainerExecResult{
+ results = append(results, DockerExecResult{
Hostname: r.Hostname,
Stdout: derefString(r.Stdout),
Stderr: derefString(r.Stderr),
@@ -244,20 +244,20 @@ func containerExecCollectionFromGen(
})
}
- return Collection[ContainerExecResult]{
+ return Collection[DockerExecResult]{
Results: results,
JobID: jobIDFromGen(g.JobId),
}
}
-// containerPullCollectionFromGen converts a gen.ContainerPullCollectionResponse
-// to a Collection[ContainerPullResult].
-func containerPullCollectionFromGen(
- g *gen.ContainerPullCollectionResponse,
-) Collection[ContainerPullResult] {
- results := make([]ContainerPullResult, 0, len(g.Results))
+// dockerPullCollectionFromGen converts a gen.DockerPullCollectionResponse
+// to a Collection[DockerPullResult].
+func dockerPullCollectionFromGen(
+ g *gen.DockerPullCollectionResponse,
+) Collection[DockerPullResult] {
+ results := make([]DockerPullResult, 0, len(g.Results))
for _, r := range g.Results {
- results = append(results, ContainerPullResult{
+ results = append(results, DockerPullResult{
Hostname: r.Hostname,
ImageID: derefString(r.ImageId),
Tag: derefString(r.Tag),
@@ -267,7 +267,7 @@ func containerPullCollectionFromGen(
})
}
- return Collection[ContainerPullResult]{
+ return Collection[DockerPullResult]{
Results: results,
JobID: jobIDFromGen(g.JobId),
}
diff --git a/pkg/sdk/client/container_types_test.go b/pkg/sdk/client/docker_types_test.go
similarity index 73%
rename from pkg/sdk/client/container_types_test.go
rename to pkg/sdk/client/docker_types_test.go
index 164e6fc4..c7ac560c 100644
--- a/pkg/sdk/client/container_types_test.go
+++ b/pkg/sdk/client/docker_types_test.go
@@ -29,11 +29,11 @@ import (
"github.com/retr0h/osapi/pkg/sdk/client/gen"
)
-type ContainerTypesTestSuite struct {
+type DockerTypesTestSuite struct {
suite.Suite
}
-func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
+func (suite *DockerTypesTestSuite) TestDockerResultCollectionFromGen() {
testUUID := openapi_types.UUID{
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b, 0x41, 0xd4,
@@ -43,12 +43,12 @@ func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
tests := []struct {
name string
- input *gen.ContainerResultCollectionResponse
- validateFunc func(Collection[ContainerResult])
+ input *gen.DockerResultCollectionResponse
+ validateFunc func(Collection[DockerResult])
}{
{
name: "when all fields are populated",
- input: func() *gen.ContainerResultCollectionResponse {
+ input: func() *gen.DockerResultCollectionResponse {
id := "abc123"
name := "my-nginx"
image := "nginx:latest"
@@ -56,9 +56,9 @@ func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
created := "2026-01-01T00:00:00Z"
changed := true
- return &gen.ContainerResultCollectionResponse{
+ return &gen.DockerResultCollectionResponse{
JobId: &testUUID,
- Results: []gen.ContainerResponse{
+ Results: []gen.DockerResponse{
{
Hostname: "web-01",
Id: &id,
@@ -71,7 +71,7 @@ func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerResult]) {
+ validateFunc: func(c Collection[DockerResult]) {
suite.Equal("550e8400-e29b-41d4-a716-446655440000", c.JobID)
suite.Require().Len(c.Results, 1)
@@ -88,11 +88,11 @@ func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
},
{
name: "when minimal with error",
- input: func() *gen.ContainerResultCollectionResponse {
+ input: func() *gen.DockerResultCollectionResponse {
errMsg := "image not found"
- return &gen.ContainerResultCollectionResponse{
- Results: []gen.ContainerResponse{
+ return &gen.DockerResultCollectionResponse{
+ Results: []gen.DockerResponse{
{
Hostname: "web-01",
Error: &errMsg,
@@ -100,7 +100,7 @@ func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerResult]) {
+ validateFunc: func(c Collection[DockerResult]) {
suite.Empty(c.JobID)
suite.Require().Len(c.Results, 1)
@@ -119,13 +119,13 @@ func (suite *ContainerTypesTestSuite) TestContainerResultCollectionFromGen() {
for _, tc := range tests {
suite.Run(tc.name, func() {
- result := containerResultCollectionFromGen(tc.input)
+ result := dockerResultCollectionFromGen(tc.input)
tc.validateFunc(result)
})
}
}
-func (suite *ContainerTypesTestSuite) TestContainerListCollectionFromGen() {
+func (suite *DockerTypesTestSuite) TestDockerListCollectionFromGen() {
testUUID := openapi_types.UUID{
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b, 0x41, 0xd4,
@@ -135,19 +135,19 @@ func (suite *ContainerTypesTestSuite) TestContainerListCollectionFromGen() {
tests := []struct {
name string
- input *gen.ContainerListCollectionResponse
- validateFunc func(Collection[ContainerListResult])
+ input *gen.DockerListCollectionResponse
+ validateFunc func(Collection[DockerListResult])
}{
{
name: "when containers are populated",
- input: func() *gen.ContainerListCollectionResponse {
+ input: func() *gen.DockerListCollectionResponse {
changed := false
id := "abc123"
name := "my-nginx"
image := "nginx:latest"
state := "running"
created := "2026-01-01T00:00:00Z"
- containers := []gen.ContainerSummary{
+ containers := []gen.DockerSummary{
{
Id: &id,
Name: &name,
@@ -157,9 +157,9 @@ func (suite *ContainerTypesTestSuite) TestContainerListCollectionFromGen() {
},
}
- return &gen.ContainerListCollectionResponse{
+ return &gen.DockerListCollectionResponse{
JobId: &testUUID,
- Results: []gen.ContainerListItem{
+ Results: []gen.DockerListItem{
{
Hostname: "web-01",
Changed: &changed,
@@ -168,7 +168,7 @@ func (suite *ContainerTypesTestSuite) TestContainerListCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerListResult]) {
+ validateFunc: func(c Collection[DockerListResult]) {
suite.Equal("550e8400-e29b-41d4-a716-446655440000", c.JobID)
suite.Require().Len(c.Results, 1)
@@ -186,12 +186,12 @@ func (suite *ContainerTypesTestSuite) TestContainerListCollectionFromGen() {
},
{
name: "when containers is nil",
- input: &gen.ContainerListCollectionResponse{
- Results: []gen.ContainerListItem{
+ input: &gen.DockerListCollectionResponse{
+ Results: []gen.DockerListItem{
{Hostname: "web-01"},
},
},
- validateFunc: func(c Collection[ContainerListResult]) {
+ validateFunc: func(c Collection[DockerListResult]) {
suite.Empty(c.JobID)
suite.Require().Len(c.Results, 1)
suite.Equal("web-01", c.Results[0].Hostname)
@@ -203,13 +203,13 @@ func (suite *ContainerTypesTestSuite) TestContainerListCollectionFromGen() {
for _, tc := range tests {
suite.Run(tc.name, func() {
- result := containerListCollectionFromGen(tc.input)
+ result := dockerListCollectionFromGen(tc.input)
tc.validateFunc(result)
})
}
}
-func (suite *ContainerTypesTestSuite) TestContainerDetailCollectionFromGen() {
+func (suite *DockerTypesTestSuite) TestDockerDetailCollectionFromGen() {
testUUID := openapi_types.UUID{
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b, 0x41, 0xd4,
@@ -219,12 +219,12 @@ func (suite *ContainerTypesTestSuite) TestContainerDetailCollectionFromGen() {
tests := []struct {
name string
- input *gen.ContainerDetailCollectionResponse
- validateFunc func(Collection[ContainerDetailResult])
+ input *gen.DockerDetailCollectionResponse
+ validateFunc func(Collection[DockerDetailResult])
}{
{
name: "when all fields are populated",
- input: func() *gen.ContainerDetailCollectionResponse {
+ input: func() *gen.DockerDetailCollectionResponse {
id := "abc123"
name := "my-nginx"
image := "nginx:latest"
@@ -237,9 +237,9 @@ func (suite *ContainerTypesTestSuite) TestContainerDetailCollectionFromGen() {
env := []string{"FOO=bar", "BAZ=qux"}
networkSettings := map[string]string{"ip": "172.17.0.2"}
- return &gen.ContainerDetailCollectionResponse{
+ return &gen.DockerDetailCollectionResponse{
JobId: &testUUID,
- Results: []gen.ContainerDetailResponse{
+ Results: []gen.DockerDetailResponse{
{
Hostname: "web-01",
Id: &id,
@@ -257,7 +257,7 @@ func (suite *ContainerTypesTestSuite) TestContainerDetailCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerDetailResult]) {
+ validateFunc: func(c Collection[DockerDetailResult]) {
suite.Equal("550e8400-e29b-41d4-a716-446655440000", c.JobID)
suite.Require().Len(c.Results, 1)
@@ -279,12 +279,12 @@ func (suite *ContainerTypesTestSuite) TestContainerDetailCollectionFromGen() {
},
{
name: "when optional fields are nil",
- input: &gen.ContainerDetailCollectionResponse{
- Results: []gen.ContainerDetailResponse{
+ input: &gen.DockerDetailCollectionResponse{
+ Results: []gen.DockerDetailResponse{
{Hostname: "web-01"},
},
},
- validateFunc: func(c Collection[ContainerDetailResult]) {
+ validateFunc: func(c Collection[DockerDetailResult]) {
suite.Empty(c.JobID)
suite.Require().Len(c.Results, 1)
@@ -308,13 +308,13 @@ func (suite *ContainerTypesTestSuite) TestContainerDetailCollectionFromGen() {
for _, tc := range tests {
suite.Run(tc.name, func() {
- result := containerDetailCollectionFromGen(tc.input)
+ result := dockerDetailCollectionFromGen(tc.input)
tc.validateFunc(result)
})
}
}
-func (suite *ContainerTypesTestSuite) TestContainerActionCollectionFromGen() {
+func (suite *DockerTypesTestSuite) TestDockerActionCollectionFromGen() {
testUUID := openapi_types.UUID{
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b, 0x41, 0xd4,
@@ -324,19 +324,19 @@ func (suite *ContainerTypesTestSuite) TestContainerActionCollectionFromGen() {
tests := []struct {
name string
- input *gen.ContainerActionCollectionResponse
- validateFunc func(Collection[ContainerActionResult])
+ input *gen.DockerActionCollectionResponse
+ validateFunc func(Collection[DockerActionResult])
}{
{
name: "when all fields are populated",
- input: func() *gen.ContainerActionCollectionResponse {
+ input: func() *gen.DockerActionCollectionResponse {
id := "abc123"
message := "container started"
changed := true
- return &gen.ContainerActionCollectionResponse{
+ return &gen.DockerActionCollectionResponse{
JobId: &testUUID,
- Results: []gen.ContainerActionResultItem{
+ Results: []gen.DockerActionResultItem{
{
Hostname: "web-01",
Id: &id,
@@ -346,7 +346,7 @@ func (suite *ContainerTypesTestSuite) TestContainerActionCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerActionResult]) {
+ validateFunc: func(c Collection[DockerActionResult]) {
suite.Equal("550e8400-e29b-41d4-a716-446655440000", c.JobID)
suite.Require().Len(c.Results, 1)
@@ -360,11 +360,11 @@ func (suite *ContainerTypesTestSuite) TestContainerActionCollectionFromGen() {
},
{
name: "when minimal with error",
- input: func() *gen.ContainerActionCollectionResponse {
+ input: func() *gen.DockerActionCollectionResponse {
errMsg := "container not found"
- return &gen.ContainerActionCollectionResponse{
- Results: []gen.ContainerActionResultItem{
+ return &gen.DockerActionCollectionResponse{
+ Results: []gen.DockerActionResultItem{
{
Hostname: "web-01",
Error: &errMsg,
@@ -372,7 +372,7 @@ func (suite *ContainerTypesTestSuite) TestContainerActionCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerActionResult]) {
+ validateFunc: func(c Collection[DockerActionResult]) {
suite.Empty(c.JobID)
suite.Require().Len(c.Results, 1)
@@ -388,13 +388,13 @@ func (suite *ContainerTypesTestSuite) TestContainerActionCollectionFromGen() {
for _, tc := range tests {
suite.Run(tc.name, func() {
- result := containerActionCollectionFromGen(tc.input)
+ result := dockerActionCollectionFromGen(tc.input)
tc.validateFunc(result)
})
}
}
-func (suite *ContainerTypesTestSuite) TestContainerExecCollectionFromGen() {
+func (suite *DockerTypesTestSuite) TestDockerExecCollectionFromGen() {
testUUID := openapi_types.UUID{
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b, 0x41, 0xd4,
@@ -404,20 +404,20 @@ func (suite *ContainerTypesTestSuite) TestContainerExecCollectionFromGen() {
tests := []struct {
name string
- input *gen.ContainerExecCollectionResponse
- validateFunc func(Collection[ContainerExecResult])
+ input *gen.DockerExecCollectionResponse
+ validateFunc func(Collection[DockerExecResult])
}{
{
name: "when all fields are populated",
- input: func() *gen.ContainerExecCollectionResponse {
+ input: func() *gen.DockerExecCollectionResponse {
stdout := "hello world\n"
stderr := "warning: something\n"
exitCode := 0
changed := true
- return &gen.ContainerExecCollectionResponse{
+ return &gen.DockerExecCollectionResponse{
JobId: &testUUID,
- Results: []gen.ContainerExecResultItem{
+ Results: []gen.DockerExecResultItem{
{
Hostname: "web-01",
Stdout: &stdout,
@@ -428,7 +428,7 @@ func (suite *ContainerTypesTestSuite) TestContainerExecCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerExecResult]) {
+ validateFunc: func(c Collection[DockerExecResult]) {
suite.Equal("550e8400-e29b-41d4-a716-446655440000", c.JobID)
suite.Require().Len(c.Results, 1)
@@ -443,12 +443,12 @@ func (suite *ContainerTypesTestSuite) TestContainerExecCollectionFromGen() {
},
{
name: "when minimal with error",
- input: func() *gen.ContainerExecCollectionResponse {
+ input: func() *gen.DockerExecCollectionResponse {
errMsg := "exec failed"
exitCode := 1
- return &gen.ContainerExecCollectionResponse{
- Results: []gen.ContainerExecResultItem{
+ return &gen.DockerExecCollectionResponse{
+ Results: []gen.DockerExecResultItem{
{
Hostname: "web-01",
Error: &errMsg,
@@ -457,7 +457,7 @@ func (suite *ContainerTypesTestSuite) TestContainerExecCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerExecResult]) {
+ validateFunc: func(c Collection[DockerExecResult]) {
suite.Empty(c.JobID)
suite.Require().Len(c.Results, 1)
@@ -474,13 +474,13 @@ func (suite *ContainerTypesTestSuite) TestContainerExecCollectionFromGen() {
for _, tc := range tests {
suite.Run(tc.name, func() {
- result := containerExecCollectionFromGen(tc.input)
+ result := dockerExecCollectionFromGen(tc.input)
tc.validateFunc(result)
})
}
}
-func (suite *ContainerTypesTestSuite) TestContainerPullCollectionFromGen() {
+func (suite *DockerTypesTestSuite) TestDockerPullCollectionFromGen() {
testUUID := openapi_types.UUID{
0x55, 0x0e, 0x84, 0x00,
0xe2, 0x9b, 0x41, 0xd4,
@@ -490,20 +490,20 @@ func (suite *ContainerTypesTestSuite) TestContainerPullCollectionFromGen() {
tests := []struct {
name string
- input *gen.ContainerPullCollectionResponse
- validateFunc func(Collection[ContainerPullResult])
+ input *gen.DockerPullCollectionResponse
+ validateFunc func(Collection[DockerPullResult])
}{
{
name: "when all fields are populated",
- input: func() *gen.ContainerPullCollectionResponse {
+ input: func() *gen.DockerPullCollectionResponse {
imageID := "sha256:abc123"
tag := "latest"
size := int64(52428800)
changed := true
- return &gen.ContainerPullCollectionResponse{
+ return &gen.DockerPullCollectionResponse{
JobId: &testUUID,
- Results: []gen.ContainerPullResultItem{
+ Results: []gen.DockerPullResultItem{
{
Hostname: "web-01",
ImageId: &imageID,
@@ -514,7 +514,7 @@ func (suite *ContainerTypesTestSuite) TestContainerPullCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerPullResult]) {
+ validateFunc: func(c Collection[DockerPullResult]) {
suite.Equal("550e8400-e29b-41d4-a716-446655440000", c.JobID)
suite.Require().Len(c.Results, 1)
@@ -529,11 +529,11 @@ func (suite *ContainerTypesTestSuite) TestContainerPullCollectionFromGen() {
},
{
name: "when minimal with error",
- input: func() *gen.ContainerPullCollectionResponse {
+ input: func() *gen.DockerPullCollectionResponse {
errMsg := "pull failed: image not found"
- return &gen.ContainerPullCollectionResponse{
- Results: []gen.ContainerPullResultItem{
+ return &gen.DockerPullCollectionResponse{
+ Results: []gen.DockerPullResultItem{
{
Hostname: "web-01",
Error: &errMsg,
@@ -541,7 +541,7 @@ func (suite *ContainerTypesTestSuite) TestContainerPullCollectionFromGen() {
},
}
}(),
- validateFunc: func(c Collection[ContainerPullResult]) {
+ validateFunc: func(c Collection[DockerPullResult]) {
suite.Empty(c.JobID)
suite.Require().Len(c.Results, 1)
@@ -558,12 +558,12 @@ func (suite *ContainerTypesTestSuite) TestContainerPullCollectionFromGen() {
for _, tc := range tests {
suite.Run(tc.name, func() {
- result := containerPullCollectionFromGen(tc.input)
+ result := dockerPullCollectionFromGen(tc.input)
tc.validateFunc(result)
})
}
}
-func TestContainerTypesTestSuite(t *testing.T) {
- suite.Run(t, new(ContainerTypesTestSuite))
+func TestDockerTypesTestSuite(t *testing.T) {
+ suite.Run(t, new(DockerTypesTestSuite))
}
diff --git a/pkg/sdk/client/gen/client.gen.go b/pkg/sdk/client/gen/client.gen.go
index 4e597011..f7cb1f41 100644
--- a/pkg/sdk/client/gen/client.gen.go
+++ b/pkg/sdk/client/gen/client.gen.go
@@ -76,11 +76,11 @@ const (
GetJobParamsStatusSubmitted GetJobParamsStatus = "submitted"
)
-// Defines values for GetNodeContainerParamsState.
+// Defines values for GetNodeContainerDockerParamsState.
const (
- All GetNodeContainerParamsState = "all"
- Running GetNodeContainerParamsState = "running"
- Stopped GetNodeContainerParamsState = "stopped"
+ All GetNodeContainerDockerParamsState = "all"
+ Running GetNodeContainerDockerParamsState = "running"
+ Stopped GetNodeContainerDockerParamsState = "stopped"
)
// AgentDetail defines model for AgentDetail.
@@ -309,15 +309,126 @@ type ConsumerStats struct {
Total int `json:"total"`
}
-// ContainerActionCollectionResponse defines model for ContainerActionCollectionResponse.
-type ContainerActionCollectionResponse struct {
+// CreateJobResponse defines model for CreateJobResponse.
+type CreateJobResponse struct {
+ // JobId Unique identifier for the created job.
+ JobId openapi_types.UUID `json:"job_id"`
+
+ // Revision The KV revision number.
+ Revision *int64 `json:"revision,omitempty"`
+
+ // Status Initial status of the job.
+ Status string `json:"status"`
+
+ // Timestamp Creation timestamp.
+ Timestamp *string `json:"timestamp,omitempty"`
+}
+
+// DNSConfigCollectionResponse defines model for DNSConfigCollectionResponse.
+type DNSConfigCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DNSConfigResponse `json:"results"`
+}
+
+// DNSConfigResponse defines model for DNSConfigResponse.
+type DNSConfigResponse struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Hostname The hostname of the agent that served this config.
+ Hostname string `json:"hostname"`
+
+ // SearchDomains List of search domains.
+ SearchDomains *[]string `json:"search_domains,omitempty"`
+
+ // Servers List of configured DNS servers.
+ Servers *[]string `json:"servers,omitempty"`
+}
+
+// DNSConfigUpdateRequest defines model for DNSConfigUpdateRequest.
+type DNSConfigUpdateRequest struct {
+ // InterfaceName The name of the network interface to apply DNS configuration to. Accepts alphanumeric names or @fact. references.
+ InterfaceName string `json:"interface_name" validate:"required,alphanum_or_fact"`
+
+ // SearchDomains New list of search domains to configure.
+ SearchDomains *[]string `json:"search_domains,omitempty" validate:"required_without=Servers,omitempty,dive,hostname,min=1"`
+
+ // Servers New list of DNS servers to configure.
+ Servers *[]string `json:"servers,omitempty" validate:"required_without=SearchDomains,omitempty,dive,ip,min=1"`
+}
+
+// DNSUpdateCollectionResponse defines model for DNSUpdateCollectionResponse.
+type DNSUpdateCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DNSUpdateResultItem `json:"results"`
+}
+
+// DNSUpdateResultItem defines model for DNSUpdateResultItem.
+type DNSUpdateResultItem struct {
+ // Changed Whether the DNS configuration was actually modified.
+ Changed *bool `json:"changed,omitempty"`
+ Error *string `json:"error,omitempty"`
+ Hostname string `json:"hostname"`
+ Status DNSUpdateResultItemStatus `json:"status"`
+}
+
+// DNSUpdateResultItemStatus defines model for DNSUpdateResultItem.Status.
+type DNSUpdateResultItemStatus string
+
+// DiskCollectionResponse defines model for DiskCollectionResponse.
+type DiskCollectionResponse struct {
+ // JobId The job ID used to process this request.
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DiskResultItem `json:"results"`
+}
+
+// DiskResponse Local disk usage information.
+type DiskResponse struct {
+ // Free Free disk space in bytes.
+ Free int `json:"free"`
+
+ // Name Disk identifier, e.g., "/dev/sda1".
+ Name string `json:"name"`
+
+ // Total Total disk space in bytes.
+ Total int `json:"total"`
+
+ // Used Used disk space in bytes.
+ Used int `json:"used"`
+}
+
+// DiskResultItem defines model for DiskResultItem.
+type DiskResultItem struct {
+ // Changed Whether the operation modified system state.
+ Changed *bool `json:"changed,omitempty"`
+
+ // Disks List of local disk usage information.
+ Disks *DisksResponse `json:"disks,omitempty"`
+
+ // Error Error message if the agent failed.
+ Error *string `json:"error,omitempty"`
+
+ // Hostname The hostname of the agent.
+ Hostname string `json:"hostname"`
+}
+
+// DisksResponse List of local disk usage information.
+type DisksResponse = []DiskResponse
+
+// DockerActionCollectionResponse defines model for DockerActionCollectionResponse.
+type DockerActionCollectionResponse struct {
// JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerActionResultItem `json:"results"`
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerActionResultItem `json:"results"`
}
-// ContainerActionResultItem Result of a container lifecycle action.
-type ContainerActionResultItem struct {
+// DockerActionResultItem Result of a container lifecycle action.
+type DockerActionResultItem struct {
// Changed Whether the operation modified system state.
Changed *bool `json:"changed,omitempty"`
@@ -334,8 +445,8 @@ type ContainerActionResultItem struct {
Message *string `json:"message,omitempty"`
}
-// ContainerCreateRequest defines model for ContainerCreateRequest.
-type ContainerCreateRequest struct {
+// DockerCreateRequest defines model for DockerCreateRequest.
+type DockerCreateRequest struct {
// AutoStart Whether to start the container immediately after creation. Defaults to true.
AutoStart *bool `json:"auto_start,omitempty"`
@@ -358,15 +469,15 @@ type ContainerCreateRequest struct {
Volumes *[]string `json:"volumes,omitempty"`
}
-// ContainerDetailCollectionResponse defines model for ContainerDetailCollectionResponse.
-type ContainerDetailCollectionResponse struct {
+// DockerDetailCollectionResponse defines model for DockerDetailCollectionResponse.
+type DockerDetailCollectionResponse struct {
// JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerDetailResponse `json:"results"`
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerDetailResponse `json:"results"`
}
-// ContainerDetailResponse Detailed information about a container.
-type ContainerDetailResponse struct {
+// DockerDetailResponse Detailed information about a container.
+type DockerDetailResponse struct {
// Changed Whether the operation modified system state.
Changed *bool `json:"changed,omitempty"`
@@ -407,15 +518,15 @@ type ContainerDetailResponse struct {
State *string `json:"state,omitempty"`
}
-// ContainerExecCollectionResponse defines model for ContainerExecCollectionResponse.
-type ContainerExecCollectionResponse struct {
+// DockerExecCollectionResponse defines model for DockerExecCollectionResponse.
+type DockerExecCollectionResponse struct {
// JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerExecResultItem `json:"results"`
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerExecResultItem `json:"results"`
}
-// ContainerExecRequest defines model for ContainerExecRequest.
-type ContainerExecRequest struct {
+// DockerExecRequest defines model for DockerExecRequest.
+type DockerExecRequest struct {
// Command Command to execute inside the container.
Command []string `json:"command" validate:"required,min=1"`
@@ -426,8 +537,8 @@ type ContainerExecRequest struct {
WorkingDir *string `json:"working_dir,omitempty"`
}
-// ContainerExecResultItem Result of a command execution inside a container.
-type ContainerExecResultItem struct {
+// DockerExecResultItem Result of a command execution inside a container.
+type DockerExecResultItem struct {
// Changed Whether the operation modified system state.
Changed *bool `json:"changed,omitempty"`
@@ -447,20 +558,20 @@ type ContainerExecResultItem struct {
Stdout *string `json:"stdout,omitempty"`
}
-// ContainerListCollectionResponse defines model for ContainerListCollectionResponse.
-type ContainerListCollectionResponse struct {
+// DockerListCollectionResponse defines model for DockerListCollectionResponse.
+type DockerListCollectionResponse struct {
// JobId The job ID used to process this request.
JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerListItem `json:"results"`
+ Results []DockerListItem `json:"results"`
}
-// ContainerListItem Container summary for list operations.
-type ContainerListItem struct {
+// DockerListItem Container summary for list operations.
+type DockerListItem struct {
// Changed Whether the operation modified system state.
Changed *bool `json:"changed,omitempty"`
// Containers List of containers on this agent.
- Containers *[]ContainerSummary `json:"containers,omitempty"`
+ Containers *[]DockerSummary `json:"containers,omitempty"`
// Error Error message if the agent failed.
Error *string `json:"error,omitempty"`
@@ -469,21 +580,21 @@ type ContainerListItem struct {
Hostname string `json:"hostname"`
}
-// ContainerPullCollectionResponse defines model for ContainerPullCollectionResponse.
-type ContainerPullCollectionResponse struct {
+// DockerPullCollectionResponse defines model for DockerPullCollectionResponse.
+type DockerPullCollectionResponse struct {
// JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerPullResultItem `json:"results"`
+ JobId *openapi_types.UUID `json:"job_id,omitempty"`
+ Results []DockerPullResultItem `json:"results"`
}
-// ContainerPullRequest defines model for ContainerPullRequest.
-type ContainerPullRequest struct {
+// DockerPullRequest defines model for DockerPullRequest.
+type DockerPullRequest struct {
// Image Image reference to pull (e.g., "nginx:latest", "docker.io/library/alpine:3.18").
Image string `json:"image" validate:"required,min=1"`
}
-// ContainerPullResultItem Result of an image pull operation.
-type ContainerPullResultItem struct {
+// DockerPullResultItem Result of an image pull operation.
+type DockerPullResultItem struct {
// Changed Whether the operation modified system state.
Changed *bool `json:"changed,omitempty"`
@@ -503,8 +614,8 @@ type ContainerPullResultItem struct {
Tag *string `json:"tag,omitempty"`
}
-// ContainerResponse Summary information about a container.
-type ContainerResponse struct {
+// DockerResponse Summary information about a container.
+type DockerResponse struct {
// Changed Whether the operation modified system state.
Changed *bool `json:"changed,omitempty"`
@@ -530,21 +641,21 @@ type ContainerResponse struct {
State *string `json:"state,omitempty"`
}
-// ContainerResultCollectionResponse defines model for ContainerResultCollectionResponse.
-type ContainerResultCollectionResponse struct {
+// DockerResultCollectionResponse defines model for DockerResultCollectionResponse.
+type DockerResultCollectionResponse struct {
// JobId The job ID used to process this request.
JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []ContainerResponse `json:"results"`
+ Results []DockerResponse `json:"results"`
}
-// ContainerStopRequest defines model for ContainerStopRequest.
-type ContainerStopRequest struct {
+// DockerStopRequest defines model for DockerStopRequest.
+type DockerStopRequest struct {
// Timeout Seconds to wait before killing the container. Defaults to 10.
Timeout *int `json:"timeout,omitempty" validate:"omitempty,min=0,max=300"`
}
-// ContainerSummary Brief container summary.
-type ContainerSummary struct {
+// DockerSummary Brief container summary.
+type DockerSummary struct {
// Created Container creation timestamp.
Created *string `json:"created,omitempty"`
@@ -561,117 +672,6 @@ type ContainerSummary struct {
State *string `json:"state,omitempty"`
}
-// CreateJobResponse defines model for CreateJobResponse.
-type CreateJobResponse struct {
- // JobId Unique identifier for the created job.
- JobId openapi_types.UUID `json:"job_id"`
-
- // Revision The KV revision number.
- Revision *int64 `json:"revision,omitempty"`
-
- // Status Initial status of the job.
- Status string `json:"status"`
-
- // Timestamp Creation timestamp.
- Timestamp *string `json:"timestamp,omitempty"`
-}
-
-// DNSConfigCollectionResponse defines model for DNSConfigCollectionResponse.
-type DNSConfigCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []DNSConfigResponse `json:"results"`
-}
-
-// DNSConfigResponse defines model for DNSConfigResponse.
-type DNSConfigResponse struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Hostname The hostname of the agent that served this config.
- Hostname string `json:"hostname"`
-
- // SearchDomains List of search domains.
- SearchDomains *[]string `json:"search_domains,omitempty"`
-
- // Servers List of configured DNS servers.
- Servers *[]string `json:"servers,omitempty"`
-}
-
-// DNSConfigUpdateRequest defines model for DNSConfigUpdateRequest.
-type DNSConfigUpdateRequest struct {
- // InterfaceName The name of the network interface to apply DNS configuration to. Accepts alphanumeric names or @fact. references.
- InterfaceName string `json:"interface_name" validate:"required,alphanum_or_fact"`
-
- // SearchDomains New list of search domains to configure.
- SearchDomains *[]string `json:"search_domains,omitempty" validate:"required_without=Servers,omitempty,dive,hostname,min=1"`
-
- // Servers New list of DNS servers to configure.
- Servers *[]string `json:"servers,omitempty" validate:"required_without=SearchDomains,omitempty,dive,ip,min=1"`
-}
-
-// DNSUpdateCollectionResponse defines model for DNSUpdateCollectionResponse.
-type DNSUpdateCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []DNSUpdateResultItem `json:"results"`
-}
-
-// DNSUpdateResultItem defines model for DNSUpdateResultItem.
-type DNSUpdateResultItem struct {
- // Changed Whether the DNS configuration was actually modified.
- Changed *bool `json:"changed,omitempty"`
- Error *string `json:"error,omitempty"`
- Hostname string `json:"hostname"`
- Status DNSUpdateResultItemStatus `json:"status"`
-}
-
-// DNSUpdateResultItemStatus defines model for DNSUpdateResultItem.Status.
-type DNSUpdateResultItemStatus string
-
-// DiskCollectionResponse defines model for DiskCollectionResponse.
-type DiskCollectionResponse struct {
- // JobId The job ID used to process this request.
- JobId *openapi_types.UUID `json:"job_id,omitempty"`
- Results []DiskResultItem `json:"results"`
-}
-
-// DiskResponse Local disk usage information.
-type DiskResponse struct {
- // Free Free disk space in bytes.
- Free int `json:"free"`
-
- // Name Disk identifier, e.g., "/dev/sda1".
- Name string `json:"name"`
-
- // Total Total disk space in bytes.
- Total int `json:"total"`
-
- // Used Used disk space in bytes.
- Used int `json:"used"`
-}
-
-// DiskResultItem defines model for DiskResultItem.
-type DiskResultItem struct {
- // Changed Whether the operation modified system state.
- Changed *bool `json:"changed,omitempty"`
-
- // Disks List of local disk usage information.
- Disks *DisksResponse `json:"disks,omitempty"`
-
- // Error Error message if the agent failed.
- Error *string `json:"error,omitempty"`
-
- // Hostname The hostname of the agent.
- Hostname string `json:"hostname"`
-}
-
-// DisksResponse List of local disk usage information.
-type DisksResponse = []DiskResponse
-
// ErrorResponse defines model for ErrorResponse.
type ErrorResponse struct {
// Code The error code.
@@ -1297,8 +1297,8 @@ type UptimeResponse struct {
Uptime *string `json:"uptime,omitempty"`
}
-// ContainerId defines model for ContainerId.
-type ContainerId = string
+// DockerId defines model for DockerId.
+type DockerId = string
// FileName defines model for FileName.
type FileName = string
@@ -1351,20 +1351,20 @@ type GetJobParams struct {
// GetJobParamsStatus defines parameters for GetJob.
type GetJobParamsStatus string
-// GetNodeContainerParams defines parameters for GetNodeContainer.
-type GetNodeContainerParams struct {
+// GetNodeContainerDockerParams defines parameters for GetNodeContainerDocker.
+type GetNodeContainerDockerParams struct {
// State Filter containers by state. Defaults to "all".
- State *GetNodeContainerParamsState `form:"state,omitempty" json:"state,omitempty" validate:"omitempty,oneof=running stopped all"`
+ State *GetNodeContainerDockerParamsState `form:"state,omitempty" json:"state,omitempty" validate:"omitempty,oneof=running stopped all"`
// Limit Maximum number of containers to return.
Limit *int `form:"limit,omitempty" json:"limit,omitempty" validate:"omitempty,min=1,max=100"`
}
-// GetNodeContainerParamsState defines parameters for GetNodeContainer.
-type GetNodeContainerParamsState string
+// GetNodeContainerDockerParamsState defines parameters for GetNodeContainerDocker.
+type GetNodeContainerDockerParamsState string
-// DeleteNodeContainerByIDParams defines parameters for DeleteNodeContainerByID.
-type DeleteNodeContainerByIDParams struct {
+// DeleteNodeContainerDockerByIDParams defines parameters for DeleteNodeContainerDockerByID.
+type DeleteNodeContainerDockerByIDParams struct {
// Force Force removal of a running container.
Force *bool `form:"force,omitempty" json:"force,omitempty" validate:"omitempty"`
}
@@ -1387,17 +1387,17 @@ type PostNodeCommandExecJSONRequestBody = CommandExecRequest
// PostNodeCommandShellJSONRequestBody defines body for PostNodeCommandShell for application/json ContentType.
type PostNodeCommandShellJSONRequestBody = CommandShellRequest
-// PostNodeContainerJSONRequestBody defines body for PostNodeContainer for application/json ContentType.
-type PostNodeContainerJSONRequestBody = ContainerCreateRequest
+// PostNodeContainerDockerJSONRequestBody defines body for PostNodeContainerDocker for application/json ContentType.
+type PostNodeContainerDockerJSONRequestBody = DockerCreateRequest
-// PostNodeContainerPullJSONRequestBody defines body for PostNodeContainerPull for application/json ContentType.
-type PostNodeContainerPullJSONRequestBody = ContainerPullRequest
+// PostNodeContainerDockerPullJSONRequestBody defines body for PostNodeContainerDockerPull for application/json ContentType.
+type PostNodeContainerDockerPullJSONRequestBody = DockerPullRequest
-// PostNodeContainerExecJSONRequestBody defines body for PostNodeContainerExec for application/json ContentType.
-type PostNodeContainerExecJSONRequestBody = ContainerExecRequest
+// PostNodeContainerDockerExecJSONRequestBody defines body for PostNodeContainerDockerExec for application/json ContentType.
+type PostNodeContainerDockerExecJSONRequestBody = DockerExecRequest
-// PostNodeContainerStopJSONRequestBody defines body for PostNodeContainerStop for application/json ContentType.
-type PostNodeContainerStopJSONRequestBody = ContainerStopRequest
+// PostNodeContainerDockerStopJSONRequestBody defines body for PostNodeContainerDockerStop for application/json ContentType.
+type PostNodeContainerDockerStopJSONRequestBody = DockerStopRequest
// PostNodeFileDeployJSONRequestBody defines body for PostNodeFileDeploy for application/json ContentType.
type PostNodeFileDeployJSONRequestBody = FileDeployRequest
@@ -1553,37 +1553,37 @@ type ClientInterface interface {
PostNodeCommandShell(ctx context.Context, hostname Hostname, body PostNodeCommandShellJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
- // GetNodeContainer request
- GetNodeContainer(ctx context.Context, hostname Hostname, params *GetNodeContainerParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetNodeContainerDocker request
+ GetNodeContainerDocker(ctx context.Context, hostname Hostname, params *GetNodeContainerDockerParams, reqEditors ...RequestEditorFn) (*http.Response, error)
- // PostNodeContainerWithBody request with any body
- PostNodeContainerWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // PostNodeContainerDockerWithBody request with any body
+ PostNodeContainerDockerWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
- PostNodeContainer(ctx context.Context, hostname Hostname, body PostNodeContainerJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ PostNodeContainerDocker(ctx context.Context, hostname Hostname, body PostNodeContainerDockerJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
- // PostNodeContainerPullWithBody request with any body
- PostNodeContainerPullWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // PostNodeContainerDockerPullWithBody request with any body
+ PostNodeContainerDockerPullWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
- PostNodeContainerPull(ctx context.Context, hostname Hostname, body PostNodeContainerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ PostNodeContainerDockerPull(ctx context.Context, hostname Hostname, body PostNodeContainerDockerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
- // DeleteNodeContainerByID request
- DeleteNodeContainerByID(ctx context.Context, hostname Hostname, id ContainerId, params *DeleteNodeContainerByIDParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // DeleteNodeContainerDockerByID request
+ DeleteNodeContainerDockerByID(ctx context.Context, hostname Hostname, id DockerId, params *DeleteNodeContainerDockerByIDParams, reqEditors ...RequestEditorFn) (*http.Response, error)
- // GetNodeContainerByID request
- GetNodeContainerByID(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetNodeContainerDockerByID request
+ GetNodeContainerDockerByID(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*http.Response, error)
- // PostNodeContainerExecWithBody request with any body
- PostNodeContainerExecWithBody(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // PostNodeContainerDockerExecWithBody request with any body
+ PostNodeContainerDockerExecWithBody(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
- PostNodeContainerExec(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ PostNodeContainerDockerExec(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
- // PostNodeContainerStart request
- PostNodeContainerStart(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // PostNodeContainerDockerStart request
+ PostNodeContainerDockerStart(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*http.Response, error)
- // PostNodeContainerStopWithBody request with any body
- PostNodeContainerStopWithBody(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // PostNodeContainerDockerStopWithBody request with any body
+ PostNodeContainerDockerStopWithBody(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
- PostNodeContainerStop(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ PostNodeContainerDockerStop(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetNodeDisk request
GetNodeDisk(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -1918,8 +1918,8 @@ func (c *Client) PostNodeCommandShell(ctx context.Context, hostname Hostname, bo
return c.Client.Do(req)
}
-func (c *Client) GetNodeContainer(ctx context.Context, hostname Hostname, params *GetNodeContainerParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewGetNodeContainerRequest(c.Server, hostname, params)
+func (c *Client) GetNodeContainerDocker(ctx context.Context, hostname Hostname, params *GetNodeContainerDockerParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetNodeContainerDockerRequest(c.Server, hostname, params)
if err != nil {
return nil, err
}
@@ -1930,8 +1930,8 @@ func (c *Client) GetNodeContainer(ctx context.Context, hostname Hostname, params
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerRequestWithBody(c.Server, hostname, contentType, body)
+func (c *Client) PostNodeContainerDockerWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerRequestWithBody(c.Server, hostname, contentType, body)
if err != nil {
return nil, err
}
@@ -1942,8 +1942,8 @@ func (c *Client) PostNodeContainerWithBody(ctx context.Context, hostname Hostnam
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainer(ctx context.Context, hostname Hostname, body PostNodeContainerJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerRequest(c.Server, hostname, body)
+func (c *Client) PostNodeContainerDocker(ctx context.Context, hostname Hostname, body PostNodeContainerDockerJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerRequest(c.Server, hostname, body)
if err != nil {
return nil, err
}
@@ -1954,8 +1954,8 @@ func (c *Client) PostNodeContainer(ctx context.Context, hostname Hostname, body
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerPullWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerPullRequestWithBody(c.Server, hostname, contentType, body)
+func (c *Client) PostNodeContainerDockerPullWithBody(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerPullRequestWithBody(c.Server, hostname, contentType, body)
if err != nil {
return nil, err
}
@@ -1966,8 +1966,8 @@ func (c *Client) PostNodeContainerPullWithBody(ctx context.Context, hostname Hos
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerPull(ctx context.Context, hostname Hostname, body PostNodeContainerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerPullRequest(c.Server, hostname, body)
+func (c *Client) PostNodeContainerDockerPull(ctx context.Context, hostname Hostname, body PostNodeContainerDockerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerPullRequest(c.Server, hostname, body)
if err != nil {
return nil, err
}
@@ -1978,8 +1978,8 @@ func (c *Client) PostNodeContainerPull(ctx context.Context, hostname Hostname, b
return c.Client.Do(req)
}
-func (c *Client) DeleteNodeContainerByID(ctx context.Context, hostname Hostname, id ContainerId, params *DeleteNodeContainerByIDParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewDeleteNodeContainerByIDRequest(c.Server, hostname, id, params)
+func (c *Client) DeleteNodeContainerDockerByID(ctx context.Context, hostname Hostname, id DockerId, params *DeleteNodeContainerDockerByIDParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewDeleteNodeContainerDockerByIDRequest(c.Server, hostname, id, params)
if err != nil {
return nil, err
}
@@ -1990,8 +1990,8 @@ func (c *Client) DeleteNodeContainerByID(ctx context.Context, hostname Hostname,
return c.Client.Do(req)
}
-func (c *Client) GetNodeContainerByID(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewGetNodeContainerByIDRequest(c.Server, hostname, id)
+func (c *Client) GetNodeContainerDockerByID(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetNodeContainerDockerByIDRequest(c.Server, hostname, id)
if err != nil {
return nil, err
}
@@ -2002,8 +2002,8 @@ func (c *Client) GetNodeContainerByID(ctx context.Context, hostname Hostname, id
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerExecWithBody(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerExecRequestWithBody(c.Server, hostname, id, contentType, body)
+func (c *Client) PostNodeContainerDockerExecWithBody(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerExecRequestWithBody(c.Server, hostname, id, contentType, body)
if err != nil {
return nil, err
}
@@ -2014,8 +2014,8 @@ func (c *Client) PostNodeContainerExecWithBody(ctx context.Context, hostname Hos
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerExec(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerExecRequest(c.Server, hostname, id, body)
+func (c *Client) PostNodeContainerDockerExec(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerExecRequest(c.Server, hostname, id, body)
if err != nil {
return nil, err
}
@@ -2026,8 +2026,8 @@ func (c *Client) PostNodeContainerExec(ctx context.Context, hostname Hostname, i
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerStart(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerStartRequest(c.Server, hostname, id)
+func (c *Client) PostNodeContainerDockerStart(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerStartRequest(c.Server, hostname, id)
if err != nil {
return nil, err
}
@@ -2038,8 +2038,8 @@ func (c *Client) PostNodeContainerStart(ctx context.Context, hostname Hostname,
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerStopWithBody(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerStopRequestWithBody(c.Server, hostname, id, contentType, body)
+func (c *Client) PostNodeContainerDockerStopWithBody(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerStopRequestWithBody(c.Server, hostname, id, contentType, body)
if err != nil {
return nil, err
}
@@ -2050,8 +2050,8 @@ func (c *Client) PostNodeContainerStopWithBody(ctx context.Context, hostname Hos
return c.Client.Do(req)
}
-func (c *Client) PostNodeContainerStop(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
- req, err := NewPostNodeContainerStopRequest(c.Server, hostname, id, body)
+func (c *Client) PostNodeContainerDockerStop(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostNodeContainerDockerStopRequest(c.Server, hostname, id, body)
if err != nil {
return nil, err
}
@@ -3060,8 +3060,8 @@ func NewPostNodeCommandShellRequestWithBody(server string, hostname Hostname, co
return req, nil
}
-// NewGetNodeContainerRequest generates requests for GetNodeContainer
-func NewGetNodeContainerRequest(server string, hostname Hostname, params *GetNodeContainerParams) (*http.Request, error) {
+// NewGetNodeContainerDockerRequest generates requests for GetNodeContainerDocker
+func NewGetNodeContainerDockerRequest(server string, hostname Hostname, params *GetNodeContainerDockerParams) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3076,7 +3076,7 @@ func NewGetNodeContainerRequest(server string, hostname Hostname, params *GetNod
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container", pathParam0)
+ operationPath := fmt.Sprintf("/node/%s/container/docker", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3132,19 +3132,19 @@ func NewGetNodeContainerRequest(server string, hostname Hostname, params *GetNod
return req, nil
}
-// NewPostNodeContainerRequest calls the generic PostNodeContainer builder with application/json body
-func NewPostNodeContainerRequest(server string, hostname Hostname, body PostNodeContainerJSONRequestBody) (*http.Request, error) {
+// NewPostNodeContainerDockerRequest calls the generic PostNodeContainerDocker builder with application/json body
+func NewPostNodeContainerDockerRequest(server string, hostname Hostname, body PostNodeContainerDockerJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
- return NewPostNodeContainerRequestWithBody(server, hostname, "application/json", bodyReader)
+ return NewPostNodeContainerDockerRequestWithBody(server, hostname, "application/json", bodyReader)
}
-// NewPostNodeContainerRequestWithBody generates requests for PostNodeContainer with any type of body
-func NewPostNodeContainerRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) {
+// NewPostNodeContainerDockerRequestWithBody generates requests for PostNodeContainerDocker with any type of body
+func NewPostNodeContainerDockerRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3159,7 +3159,7 @@ func NewPostNodeContainerRequestWithBody(server string, hostname Hostname, conte
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container", pathParam0)
+ operationPath := fmt.Sprintf("/node/%s/container/docker", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3179,19 +3179,19 @@ func NewPostNodeContainerRequestWithBody(server string, hostname Hostname, conte
return req, nil
}
-// NewPostNodeContainerPullRequest calls the generic PostNodeContainerPull builder with application/json body
-func NewPostNodeContainerPullRequest(server string, hostname Hostname, body PostNodeContainerPullJSONRequestBody) (*http.Request, error) {
+// NewPostNodeContainerDockerPullRequest calls the generic PostNodeContainerDockerPull builder with application/json body
+func NewPostNodeContainerDockerPullRequest(server string, hostname Hostname, body PostNodeContainerDockerPullJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
- return NewPostNodeContainerPullRequestWithBody(server, hostname, "application/json", bodyReader)
+ return NewPostNodeContainerDockerPullRequestWithBody(server, hostname, "application/json", bodyReader)
}
-// NewPostNodeContainerPullRequestWithBody generates requests for PostNodeContainerPull with any type of body
-func NewPostNodeContainerPullRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) {
+// NewPostNodeContainerDockerPullRequestWithBody generates requests for PostNodeContainerDockerPull with any type of body
+func NewPostNodeContainerDockerPullRequestWithBody(server string, hostname Hostname, contentType string, body io.Reader) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3206,7 +3206,7 @@ func NewPostNodeContainerPullRequestWithBody(server string, hostname Hostname, c
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container/pull", pathParam0)
+ operationPath := fmt.Sprintf("/node/%s/container/docker/pull", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3226,8 +3226,8 @@ func NewPostNodeContainerPullRequestWithBody(server string, hostname Hostname, c
return req, nil
}
-// NewDeleteNodeContainerByIDRequest generates requests for DeleteNodeContainerByID
-func NewDeleteNodeContainerByIDRequest(server string, hostname Hostname, id ContainerId, params *DeleteNodeContainerByIDParams) (*http.Request, error) {
+// NewDeleteNodeContainerDockerByIDRequest generates requests for DeleteNodeContainerDockerByID
+func NewDeleteNodeContainerDockerByIDRequest(server string, hostname Hostname, id DockerId, params *DeleteNodeContainerDockerByIDParams) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3249,7 +3249,7 @@ func NewDeleteNodeContainerByIDRequest(server string, hostname Hostname, id Cont
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container/%s", pathParam0, pathParam1)
+ operationPath := fmt.Sprintf("/node/%s/container/docker/%s", pathParam0, pathParam1)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3289,8 +3289,8 @@ func NewDeleteNodeContainerByIDRequest(server string, hostname Hostname, id Cont
return req, nil
}
-// NewGetNodeContainerByIDRequest generates requests for GetNodeContainerByID
-func NewGetNodeContainerByIDRequest(server string, hostname Hostname, id ContainerId) (*http.Request, error) {
+// NewGetNodeContainerDockerByIDRequest generates requests for GetNodeContainerDockerByID
+func NewGetNodeContainerDockerByIDRequest(server string, hostname Hostname, id DockerId) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3312,7 +3312,7 @@ func NewGetNodeContainerByIDRequest(server string, hostname Hostname, id Contain
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container/%s", pathParam0, pathParam1)
+ operationPath := fmt.Sprintf("/node/%s/container/docker/%s", pathParam0, pathParam1)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3330,19 +3330,19 @@ func NewGetNodeContainerByIDRequest(server string, hostname Hostname, id Contain
return req, nil
}
-// NewPostNodeContainerExecRequest calls the generic PostNodeContainerExec builder with application/json body
-func NewPostNodeContainerExecRequest(server string, hostname Hostname, id ContainerId, body PostNodeContainerExecJSONRequestBody) (*http.Request, error) {
+// NewPostNodeContainerDockerExecRequest calls the generic PostNodeContainerDockerExec builder with application/json body
+func NewPostNodeContainerDockerExecRequest(server string, hostname Hostname, id DockerId, body PostNodeContainerDockerExecJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
- return NewPostNodeContainerExecRequestWithBody(server, hostname, id, "application/json", bodyReader)
+ return NewPostNodeContainerDockerExecRequestWithBody(server, hostname, id, "application/json", bodyReader)
}
-// NewPostNodeContainerExecRequestWithBody generates requests for PostNodeContainerExec with any type of body
-func NewPostNodeContainerExecRequestWithBody(server string, hostname Hostname, id ContainerId, contentType string, body io.Reader) (*http.Request, error) {
+// NewPostNodeContainerDockerExecRequestWithBody generates requests for PostNodeContainerDockerExec with any type of body
+func NewPostNodeContainerDockerExecRequestWithBody(server string, hostname Hostname, id DockerId, contentType string, body io.Reader) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3364,7 +3364,7 @@ func NewPostNodeContainerExecRequestWithBody(server string, hostname Hostname, i
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container/%s/exec", pathParam0, pathParam1)
+ operationPath := fmt.Sprintf("/node/%s/container/docker/%s/exec", pathParam0, pathParam1)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3384,8 +3384,8 @@ func NewPostNodeContainerExecRequestWithBody(server string, hostname Hostname, i
return req, nil
}
-// NewPostNodeContainerStartRequest generates requests for PostNodeContainerStart
-func NewPostNodeContainerStartRequest(server string, hostname Hostname, id ContainerId) (*http.Request, error) {
+// NewPostNodeContainerDockerStartRequest generates requests for PostNodeContainerDockerStart
+func NewPostNodeContainerDockerStartRequest(server string, hostname Hostname, id DockerId) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3407,7 +3407,7 @@ func NewPostNodeContainerStartRequest(server string, hostname Hostname, id Conta
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container/%s/start", pathParam0, pathParam1)
+ operationPath := fmt.Sprintf("/node/%s/container/docker/%s/start", pathParam0, pathParam1)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -3425,19 +3425,19 @@ func NewPostNodeContainerStartRequest(server string, hostname Hostname, id Conta
return req, nil
}
-// NewPostNodeContainerStopRequest calls the generic PostNodeContainerStop builder with application/json body
-func NewPostNodeContainerStopRequest(server string, hostname Hostname, id ContainerId, body PostNodeContainerStopJSONRequestBody) (*http.Request, error) {
+// NewPostNodeContainerDockerStopRequest calls the generic PostNodeContainerDockerStop builder with application/json body
+func NewPostNodeContainerDockerStopRequest(server string, hostname Hostname, id DockerId, body PostNodeContainerDockerStopJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
- return NewPostNodeContainerStopRequestWithBody(server, hostname, id, "application/json", bodyReader)
+ return NewPostNodeContainerDockerStopRequestWithBody(server, hostname, id, "application/json", bodyReader)
}
-// NewPostNodeContainerStopRequestWithBody generates requests for PostNodeContainerStop with any type of body
-func NewPostNodeContainerStopRequestWithBody(server string, hostname Hostname, id ContainerId, contentType string, body io.Reader) (*http.Request, error) {
+// NewPostNodeContainerDockerStopRequestWithBody generates requests for PostNodeContainerDockerStop with any type of body
+func NewPostNodeContainerDockerStopRequestWithBody(server string, hostname Hostname, id DockerId, contentType string, body io.Reader) (*http.Request, error) {
var err error
var pathParam0 string
@@ -3459,7 +3459,7 @@ func NewPostNodeContainerStopRequestWithBody(server string, hostname Hostname, i
return nil, err
}
- operationPath := fmt.Sprintf("/node/%s/container/%s/stop", pathParam0, pathParam1)
+ operationPath := fmt.Sprintf("/node/%s/container/docker/%s/stop", pathParam0, pathParam1)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -4051,37 +4051,37 @@ type ClientWithResponsesInterface interface {
PostNodeCommandShellWithResponse(ctx context.Context, hostname Hostname, body PostNodeCommandShellJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeCommandShellResponse, error)
- // GetNodeContainerWithResponse request
- GetNodeContainerWithResponse(ctx context.Context, hostname Hostname, params *GetNodeContainerParams, reqEditors ...RequestEditorFn) (*GetNodeContainerResponse, error)
+ // GetNodeContainerDockerWithResponse request
+ GetNodeContainerDockerWithResponse(ctx context.Context, hostname Hostname, params *GetNodeContainerDockerParams, reqEditors ...RequestEditorFn) (*GetNodeContainerDockerResponse, error)
- // PostNodeContainerWithBodyWithResponse request with any body
- PostNodeContainerWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerResponse, error)
+ // PostNodeContainerDockerWithBodyWithResponse request with any body
+ PostNodeContainerDockerWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerResponse, error)
- PostNodeContainerWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerResponse, error)
+ PostNodeContainerDockerWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerDockerJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerResponse, error)
- // PostNodeContainerPullWithBodyWithResponse request with any body
- PostNodeContainerPullWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerPullResponse, error)
+ // PostNodeContainerDockerPullWithBodyWithResponse request with any body
+ PostNodeContainerDockerPullWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerPullResponse, error)
- PostNodeContainerPullWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerPullResponse, error)
+ PostNodeContainerDockerPullWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerDockerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerPullResponse, error)
- // DeleteNodeContainerByIDWithResponse request
- DeleteNodeContainerByIDWithResponse(ctx context.Context, hostname Hostname, id ContainerId, params *DeleteNodeContainerByIDParams, reqEditors ...RequestEditorFn) (*DeleteNodeContainerByIDResponse, error)
+ // DeleteNodeContainerDockerByIDWithResponse request
+ DeleteNodeContainerDockerByIDWithResponse(ctx context.Context, hostname Hostname, id DockerId, params *DeleteNodeContainerDockerByIDParams, reqEditors ...RequestEditorFn) (*DeleteNodeContainerDockerByIDResponse, error)
- // GetNodeContainerByIDWithResponse request
- GetNodeContainerByIDWithResponse(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*GetNodeContainerByIDResponse, error)
+ // GetNodeContainerDockerByIDWithResponse request
+ GetNodeContainerDockerByIDWithResponse(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*GetNodeContainerDockerByIDResponse, error)
- // PostNodeContainerExecWithBodyWithResponse request with any body
- PostNodeContainerExecWithBodyWithResponse(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerExecResponse, error)
+ // PostNodeContainerDockerExecWithBodyWithResponse request with any body
+ PostNodeContainerDockerExecWithBodyWithResponse(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerExecResponse, error)
- PostNodeContainerExecWithResponse(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerExecResponse, error)
+ PostNodeContainerDockerExecWithResponse(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerExecResponse, error)
- // PostNodeContainerStartWithResponse request
- PostNodeContainerStartWithResponse(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*PostNodeContainerStartResponse, error)
+ // PostNodeContainerDockerStartWithResponse request
+ PostNodeContainerDockerStartWithResponse(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerStartResponse, error)
- // PostNodeContainerStopWithBodyWithResponse request with any body
- PostNodeContainerStopWithBodyWithResponse(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerStopResponse, error)
+ // PostNodeContainerDockerStopWithBodyWithResponse request with any body
+ PostNodeContainerDockerStopWithBodyWithResponse(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerStopResponse, error)
- PostNodeContainerStopWithResponse(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerStopResponse, error)
+ PostNodeContainerDockerStopWithResponse(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerStopResponse, error)
// GetNodeDiskWithResponse request
GetNodeDiskWithResponse(ctx context.Context, hostname Hostname, reqEditors ...RequestEditorFn) (*GetNodeDiskResponse, error)
@@ -4675,10 +4675,10 @@ func (r PostNodeCommandShellResponse) StatusCode() int {
return 0
}
-type GetNodeContainerResponse struct {
+type GetNodeContainerDockerResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON200 *ContainerListCollectionResponse
+ JSON200 *DockerListCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4686,7 +4686,7 @@ type GetNodeContainerResponse struct {
}
// Status returns HTTPResponse.Status
-func (r GetNodeContainerResponse) Status() string {
+func (r GetNodeContainerDockerResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4694,17 +4694,17 @@ func (r GetNodeContainerResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetNodeContainerResponse) StatusCode() int {
+func (r GetNodeContainerDockerResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type PostNodeContainerResponse struct {
+type PostNodeContainerDockerResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *ContainerResultCollectionResponse
+ JSON202 *DockerResultCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4712,7 +4712,7 @@ type PostNodeContainerResponse struct {
}
// Status returns HTTPResponse.Status
-func (r PostNodeContainerResponse) Status() string {
+func (r PostNodeContainerDockerResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4720,17 +4720,17 @@ func (r PostNodeContainerResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r PostNodeContainerResponse) StatusCode() int {
+func (r PostNodeContainerDockerResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type PostNodeContainerPullResponse struct {
+type PostNodeContainerDockerPullResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *ContainerPullCollectionResponse
+ JSON202 *DockerPullCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4738,7 +4738,7 @@ type PostNodeContainerPullResponse struct {
}
// Status returns HTTPResponse.Status
-func (r PostNodeContainerPullResponse) Status() string {
+func (r PostNodeContainerDockerPullResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4746,17 +4746,17 @@ func (r PostNodeContainerPullResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r PostNodeContainerPullResponse) StatusCode() int {
+func (r PostNodeContainerDockerPullResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type DeleteNodeContainerByIDResponse struct {
+type DeleteNodeContainerDockerByIDResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *ContainerActionCollectionResponse
+ JSON202 *DockerActionCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4765,7 +4765,7 @@ type DeleteNodeContainerByIDResponse struct {
}
// Status returns HTTPResponse.Status
-func (r DeleteNodeContainerByIDResponse) Status() string {
+func (r DeleteNodeContainerDockerByIDResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4773,17 +4773,17 @@ func (r DeleteNodeContainerByIDResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r DeleteNodeContainerByIDResponse) StatusCode() int {
+func (r DeleteNodeContainerDockerByIDResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetNodeContainerByIDResponse struct {
+type GetNodeContainerDockerByIDResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON200 *ContainerDetailCollectionResponse
+ JSON200 *DockerDetailCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4792,7 +4792,7 @@ type GetNodeContainerByIDResponse struct {
}
// Status returns HTTPResponse.Status
-func (r GetNodeContainerByIDResponse) Status() string {
+func (r GetNodeContainerDockerByIDResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4800,17 +4800,17 @@ func (r GetNodeContainerByIDResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetNodeContainerByIDResponse) StatusCode() int {
+func (r GetNodeContainerDockerByIDResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type PostNodeContainerExecResponse struct {
+type PostNodeContainerDockerExecResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *ContainerExecCollectionResponse
+ JSON202 *DockerExecCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4819,7 +4819,7 @@ type PostNodeContainerExecResponse struct {
}
// Status returns HTTPResponse.Status
-func (r PostNodeContainerExecResponse) Status() string {
+func (r PostNodeContainerDockerExecResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4827,17 +4827,17 @@ func (r PostNodeContainerExecResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r PostNodeContainerExecResponse) StatusCode() int {
+func (r PostNodeContainerDockerExecResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type PostNodeContainerStartResponse struct {
+type PostNodeContainerDockerStartResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *ContainerActionCollectionResponse
+ JSON202 *DockerActionCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4846,7 +4846,7 @@ type PostNodeContainerStartResponse struct {
}
// Status returns HTTPResponse.Status
-func (r PostNodeContainerStartResponse) Status() string {
+func (r PostNodeContainerDockerStartResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4854,17 +4854,17 @@ func (r PostNodeContainerStartResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r PostNodeContainerStartResponse) StatusCode() int {
+func (r PostNodeContainerDockerStartResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type PostNodeContainerStopResponse struct {
+type PostNodeContainerDockerStopResponse struct {
Body []byte
HTTPResponse *http.Response
- JSON202 *ContainerActionCollectionResponse
+ JSON202 *DockerActionCollectionResponse
JSON400 *ErrorResponse
JSON401 *ErrorResponse
JSON403 *ErrorResponse
@@ -4873,7 +4873,7 @@ type PostNodeContainerStopResponse struct {
}
// Status returns HTTPResponse.Status
-func (r PostNodeContainerStopResponse) Status() string {
+func (r PostNodeContainerDockerStopResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -4881,7 +4881,7 @@ func (r PostNodeContainerStopResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r PostNodeContainerStopResponse) StatusCode() int {
+func (r PostNodeContainerDockerStopResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
@@ -5409,108 +5409,108 @@ func (c *ClientWithResponses) PostNodeCommandShellWithResponse(ctx context.Conte
return ParsePostNodeCommandShellResponse(rsp)
}
-// GetNodeContainerWithResponse request returning *GetNodeContainerResponse
-func (c *ClientWithResponses) GetNodeContainerWithResponse(ctx context.Context, hostname Hostname, params *GetNodeContainerParams, reqEditors ...RequestEditorFn) (*GetNodeContainerResponse, error) {
- rsp, err := c.GetNodeContainer(ctx, hostname, params, reqEditors...)
+// GetNodeContainerDockerWithResponse request returning *GetNodeContainerDockerResponse
+func (c *ClientWithResponses) GetNodeContainerDockerWithResponse(ctx context.Context, hostname Hostname, params *GetNodeContainerDockerParams, reqEditors ...RequestEditorFn) (*GetNodeContainerDockerResponse, error) {
+ rsp, err := c.GetNodeContainerDocker(ctx, hostname, params, reqEditors...)
if err != nil {
return nil, err
}
- return ParseGetNodeContainerResponse(rsp)
+ return ParseGetNodeContainerDockerResponse(rsp)
}
-// PostNodeContainerWithBodyWithResponse request with arbitrary body returning *PostNodeContainerResponse
-func (c *ClientWithResponses) PostNodeContainerWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerResponse, error) {
- rsp, err := c.PostNodeContainerWithBody(ctx, hostname, contentType, body, reqEditors...)
+// PostNodeContainerDockerWithBodyWithResponse request with arbitrary body returning *PostNodeContainerDockerResponse
+func (c *ClientWithResponses) PostNodeContainerDockerWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerResponse, error) {
+ rsp, err := c.PostNodeContainerDockerWithBody(ctx, hostname, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerResponse(rsp)
+ return ParsePostNodeContainerDockerResponse(rsp)
}
-func (c *ClientWithResponses) PostNodeContainerWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerResponse, error) {
- rsp, err := c.PostNodeContainer(ctx, hostname, body, reqEditors...)
+func (c *ClientWithResponses) PostNodeContainerDockerWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerDockerJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerResponse, error) {
+ rsp, err := c.PostNodeContainerDocker(ctx, hostname, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerResponse(rsp)
+ return ParsePostNodeContainerDockerResponse(rsp)
}
-// PostNodeContainerPullWithBodyWithResponse request with arbitrary body returning *PostNodeContainerPullResponse
-func (c *ClientWithResponses) PostNodeContainerPullWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerPullResponse, error) {
- rsp, err := c.PostNodeContainerPullWithBody(ctx, hostname, contentType, body, reqEditors...)
+// PostNodeContainerDockerPullWithBodyWithResponse request with arbitrary body returning *PostNodeContainerDockerPullResponse
+func (c *ClientWithResponses) PostNodeContainerDockerPullWithBodyWithResponse(ctx context.Context, hostname Hostname, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerPullResponse, error) {
+ rsp, err := c.PostNodeContainerDockerPullWithBody(ctx, hostname, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerPullResponse(rsp)
+ return ParsePostNodeContainerDockerPullResponse(rsp)
}
-func (c *ClientWithResponses) PostNodeContainerPullWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerPullResponse, error) {
- rsp, err := c.PostNodeContainerPull(ctx, hostname, body, reqEditors...)
+func (c *ClientWithResponses) PostNodeContainerDockerPullWithResponse(ctx context.Context, hostname Hostname, body PostNodeContainerDockerPullJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerPullResponse, error) {
+ rsp, err := c.PostNodeContainerDockerPull(ctx, hostname, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerPullResponse(rsp)
+ return ParsePostNodeContainerDockerPullResponse(rsp)
}
-// DeleteNodeContainerByIDWithResponse request returning *DeleteNodeContainerByIDResponse
-func (c *ClientWithResponses) DeleteNodeContainerByIDWithResponse(ctx context.Context, hostname Hostname, id ContainerId, params *DeleteNodeContainerByIDParams, reqEditors ...RequestEditorFn) (*DeleteNodeContainerByIDResponse, error) {
- rsp, err := c.DeleteNodeContainerByID(ctx, hostname, id, params, reqEditors...)
+// DeleteNodeContainerDockerByIDWithResponse request returning *DeleteNodeContainerDockerByIDResponse
+func (c *ClientWithResponses) DeleteNodeContainerDockerByIDWithResponse(ctx context.Context, hostname Hostname, id DockerId, params *DeleteNodeContainerDockerByIDParams, reqEditors ...RequestEditorFn) (*DeleteNodeContainerDockerByIDResponse, error) {
+ rsp, err := c.DeleteNodeContainerDockerByID(ctx, hostname, id, params, reqEditors...)
if err != nil {
return nil, err
}
- return ParseDeleteNodeContainerByIDResponse(rsp)
+ return ParseDeleteNodeContainerDockerByIDResponse(rsp)
}
-// GetNodeContainerByIDWithResponse request returning *GetNodeContainerByIDResponse
-func (c *ClientWithResponses) GetNodeContainerByIDWithResponse(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*GetNodeContainerByIDResponse, error) {
- rsp, err := c.GetNodeContainerByID(ctx, hostname, id, reqEditors...)
+// GetNodeContainerDockerByIDWithResponse request returning *GetNodeContainerDockerByIDResponse
+func (c *ClientWithResponses) GetNodeContainerDockerByIDWithResponse(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*GetNodeContainerDockerByIDResponse, error) {
+ rsp, err := c.GetNodeContainerDockerByID(ctx, hostname, id, reqEditors...)
if err != nil {
return nil, err
}
- return ParseGetNodeContainerByIDResponse(rsp)
+ return ParseGetNodeContainerDockerByIDResponse(rsp)
}
-// PostNodeContainerExecWithBodyWithResponse request with arbitrary body returning *PostNodeContainerExecResponse
-func (c *ClientWithResponses) PostNodeContainerExecWithBodyWithResponse(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerExecResponse, error) {
- rsp, err := c.PostNodeContainerExecWithBody(ctx, hostname, id, contentType, body, reqEditors...)
+// PostNodeContainerDockerExecWithBodyWithResponse request with arbitrary body returning *PostNodeContainerDockerExecResponse
+func (c *ClientWithResponses) PostNodeContainerDockerExecWithBodyWithResponse(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerExecResponse, error) {
+ rsp, err := c.PostNodeContainerDockerExecWithBody(ctx, hostname, id, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerExecResponse(rsp)
+ return ParsePostNodeContainerDockerExecResponse(rsp)
}
-func (c *ClientWithResponses) PostNodeContainerExecWithResponse(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerExecResponse, error) {
- rsp, err := c.PostNodeContainerExec(ctx, hostname, id, body, reqEditors...)
+func (c *ClientWithResponses) PostNodeContainerDockerExecWithResponse(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerExecJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerExecResponse, error) {
+ rsp, err := c.PostNodeContainerDockerExec(ctx, hostname, id, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerExecResponse(rsp)
+ return ParsePostNodeContainerDockerExecResponse(rsp)
}
-// PostNodeContainerStartWithResponse request returning *PostNodeContainerStartResponse
-func (c *ClientWithResponses) PostNodeContainerStartWithResponse(ctx context.Context, hostname Hostname, id ContainerId, reqEditors ...RequestEditorFn) (*PostNodeContainerStartResponse, error) {
- rsp, err := c.PostNodeContainerStart(ctx, hostname, id, reqEditors...)
+// PostNodeContainerDockerStartWithResponse request returning *PostNodeContainerDockerStartResponse
+func (c *ClientWithResponses) PostNodeContainerDockerStartWithResponse(ctx context.Context, hostname Hostname, id DockerId, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerStartResponse, error) {
+ rsp, err := c.PostNodeContainerDockerStart(ctx, hostname, id, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerStartResponse(rsp)
+ return ParsePostNodeContainerDockerStartResponse(rsp)
}
-// PostNodeContainerStopWithBodyWithResponse request with arbitrary body returning *PostNodeContainerStopResponse
-func (c *ClientWithResponses) PostNodeContainerStopWithBodyWithResponse(ctx context.Context, hostname Hostname, id ContainerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerStopResponse, error) {
- rsp, err := c.PostNodeContainerStopWithBody(ctx, hostname, id, contentType, body, reqEditors...)
+// PostNodeContainerDockerStopWithBodyWithResponse request with arbitrary body returning *PostNodeContainerDockerStopResponse
+func (c *ClientWithResponses) PostNodeContainerDockerStopWithBodyWithResponse(ctx context.Context, hostname Hostname, id DockerId, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerStopResponse, error) {
+ rsp, err := c.PostNodeContainerDockerStopWithBody(ctx, hostname, id, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerStopResponse(rsp)
+ return ParsePostNodeContainerDockerStopResponse(rsp)
}
-func (c *ClientWithResponses) PostNodeContainerStopWithResponse(ctx context.Context, hostname Hostname, id ContainerId, body PostNodeContainerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerStopResponse, error) {
- rsp, err := c.PostNodeContainerStop(ctx, hostname, id, body, reqEditors...)
+func (c *ClientWithResponses) PostNodeContainerDockerStopWithResponse(ctx context.Context, hostname Hostname, id DockerId, body PostNodeContainerDockerStopJSONRequestBody, reqEditors ...RequestEditorFn) (*PostNodeContainerDockerStopResponse, error) {
+ rsp, err := c.PostNodeContainerDockerStop(ctx, hostname, id, body, reqEditors...)
if err != nil {
return nil, err
}
- return ParsePostNodeContainerStopResponse(rsp)
+ return ParsePostNodeContainerDockerStopResponse(rsp)
}
// GetNodeDiskWithResponse request returning *GetNodeDiskResponse
@@ -6770,22 +6770,22 @@ func ParsePostNodeCommandShellResponse(rsp *http.Response) (*PostNodeCommandShel
return response, nil
}
-// ParseGetNodeContainerResponse parses an HTTP response from a GetNodeContainerWithResponse call
-func ParseGetNodeContainerResponse(rsp *http.Response) (*GetNodeContainerResponse, error) {
+// ParseGetNodeContainerDockerResponse parses an HTTP response from a GetNodeContainerDockerWithResponse call
+func ParseGetNodeContainerDockerResponse(rsp *http.Response) (*GetNodeContainerDockerResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &GetNodeContainerResponse{
+ response := &GetNodeContainerDockerResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest ContainerListCollectionResponse
+ var dest DockerListCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -6824,22 +6824,22 @@ func ParseGetNodeContainerResponse(rsp *http.Response) (*GetNodeContainerRespons
return response, nil
}
-// ParsePostNodeContainerResponse parses an HTTP response from a PostNodeContainerWithResponse call
-func ParsePostNodeContainerResponse(rsp *http.Response) (*PostNodeContainerResponse, error) {
+// ParsePostNodeContainerDockerResponse parses an HTTP response from a PostNodeContainerDockerWithResponse call
+func ParsePostNodeContainerDockerResponse(rsp *http.Response) (*PostNodeContainerDockerResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &PostNodeContainerResponse{
+ response := &PostNodeContainerDockerResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
- var dest ContainerResultCollectionResponse
+ var dest DockerResultCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -6878,22 +6878,22 @@ func ParsePostNodeContainerResponse(rsp *http.Response) (*PostNodeContainerRespo
return response, nil
}
-// ParsePostNodeContainerPullResponse parses an HTTP response from a PostNodeContainerPullWithResponse call
-func ParsePostNodeContainerPullResponse(rsp *http.Response) (*PostNodeContainerPullResponse, error) {
+// ParsePostNodeContainerDockerPullResponse parses an HTTP response from a PostNodeContainerDockerPullWithResponse call
+func ParsePostNodeContainerDockerPullResponse(rsp *http.Response) (*PostNodeContainerDockerPullResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &PostNodeContainerPullResponse{
+ response := &PostNodeContainerDockerPullResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
- var dest ContainerPullCollectionResponse
+ var dest DockerPullCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -6932,22 +6932,22 @@ func ParsePostNodeContainerPullResponse(rsp *http.Response) (*PostNodeContainerP
return response, nil
}
-// ParseDeleteNodeContainerByIDResponse parses an HTTP response from a DeleteNodeContainerByIDWithResponse call
-func ParseDeleteNodeContainerByIDResponse(rsp *http.Response) (*DeleteNodeContainerByIDResponse, error) {
+// ParseDeleteNodeContainerDockerByIDResponse parses an HTTP response from a DeleteNodeContainerDockerByIDWithResponse call
+func ParseDeleteNodeContainerDockerByIDResponse(rsp *http.Response) (*DeleteNodeContainerDockerByIDResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &DeleteNodeContainerByIDResponse{
+ response := &DeleteNodeContainerDockerByIDResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
- var dest ContainerActionCollectionResponse
+ var dest DockerActionCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -6993,22 +6993,22 @@ func ParseDeleteNodeContainerByIDResponse(rsp *http.Response) (*DeleteNodeContai
return response, nil
}
-// ParseGetNodeContainerByIDResponse parses an HTTP response from a GetNodeContainerByIDWithResponse call
-func ParseGetNodeContainerByIDResponse(rsp *http.Response) (*GetNodeContainerByIDResponse, error) {
+// ParseGetNodeContainerDockerByIDResponse parses an HTTP response from a GetNodeContainerDockerByIDWithResponse call
+func ParseGetNodeContainerDockerByIDResponse(rsp *http.Response) (*GetNodeContainerDockerByIDResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &GetNodeContainerByIDResponse{
+ response := &GetNodeContainerDockerByIDResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
- var dest ContainerDetailCollectionResponse
+ var dest DockerDetailCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -7054,22 +7054,22 @@ func ParseGetNodeContainerByIDResponse(rsp *http.Response) (*GetNodeContainerByI
return response, nil
}
-// ParsePostNodeContainerExecResponse parses an HTTP response from a PostNodeContainerExecWithResponse call
-func ParsePostNodeContainerExecResponse(rsp *http.Response) (*PostNodeContainerExecResponse, error) {
+// ParsePostNodeContainerDockerExecResponse parses an HTTP response from a PostNodeContainerDockerExecWithResponse call
+func ParsePostNodeContainerDockerExecResponse(rsp *http.Response) (*PostNodeContainerDockerExecResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &PostNodeContainerExecResponse{
+ response := &PostNodeContainerDockerExecResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
- var dest ContainerExecCollectionResponse
+ var dest DockerExecCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -7115,22 +7115,22 @@ func ParsePostNodeContainerExecResponse(rsp *http.Response) (*PostNodeContainerE
return response, nil
}
-// ParsePostNodeContainerStartResponse parses an HTTP response from a PostNodeContainerStartWithResponse call
-func ParsePostNodeContainerStartResponse(rsp *http.Response) (*PostNodeContainerStartResponse, error) {
+// ParsePostNodeContainerDockerStartResponse parses an HTTP response from a PostNodeContainerDockerStartWithResponse call
+func ParsePostNodeContainerDockerStartResponse(rsp *http.Response) (*PostNodeContainerDockerStartResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &PostNodeContainerStartResponse{
+ response := &PostNodeContainerDockerStartResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
- var dest ContainerActionCollectionResponse
+ var dest DockerActionCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
@@ -7176,22 +7176,22 @@ func ParsePostNodeContainerStartResponse(rsp *http.Response) (*PostNodeContainer
return response, nil
}
-// ParsePostNodeContainerStopResponse parses an HTTP response from a PostNodeContainerStopWithResponse call
-func ParsePostNodeContainerStopResponse(rsp *http.Response) (*PostNodeContainerStopResponse, error) {
+// ParsePostNodeContainerDockerStopResponse parses an HTTP response from a PostNodeContainerDockerStopWithResponse call
+func ParsePostNodeContainerDockerStopResponse(rsp *http.Response) (*PostNodeContainerDockerStopResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
- response := &PostNodeContainerStopResponse{
+ response := &PostNodeContainerDockerStopResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 202:
- var dest ContainerActionCollectionResponse
+ var dest DockerActionCollectionResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
diff --git a/pkg/sdk/client/osapi.go b/pkg/sdk/client/osapi.go
index 0a13e381..fc6981c4 100644
--- a/pkg/sdk/client/osapi.go
+++ b/pkg/sdk/client/osapi.go
@@ -66,9 +66,9 @@ type Client struct {
// File provides file management operations (upload, list, get, delete).
File *FileService
- // Container provides container management operations (create, list,
+ // Docker provides Docker container management operations (create, list,
// inspect, start, stop, remove, exec, pull).
- Container *ContainerService
+ Docker *DockerService
httpClient *gen.ClientWithResponses
baseURL string
@@ -139,7 +139,7 @@ func New(
baseURL: baseURL,
}
c.File = &FileService{client: httpClient}
- c.Container = &ContainerService{client: httpClient}
+ c.Docker = &DockerService{client: httpClient}
return c
}
diff --git a/pkg/sdk/orchestrator/container_provider.go b/pkg/sdk/orchestrator/container_provider.go
deleted file mode 100644
index 62a6580c..00000000
--- a/pkg/sdk/orchestrator/container_provider.go
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "time"
-)
-
-// ContainerProvider provides typed access to provider operations inside
-// a container via the RuntimeTarget's ExecProvider method. This runs
-// `osapi provider run ` inside the container,
-// so the osapi binary must be present at /osapi in the container.
-//
-// The SDK owns the input/output type contracts. The CLI's `provider run`
-// command and this typed layer use the same serialization format.
-type ContainerProvider struct {
- target RuntimeTarget
-}
-
-// NewContainerProvider creates a provider bound to a RuntimeTarget.
-func NewContainerProvider(
- target RuntimeTarget,
-) *ContainerProvider {
- return &ContainerProvider{target: target}
-}
-
-// ── Result types ─────────────────────────────────────────────────────
-//
-// These mirror the internal provider result types and define the JSON
-// contract between the `osapi provider run` CLI and SDK consumers.
-
-// HostOSInfo contains operating system information.
-type HostOSInfo struct {
- Distribution string `json:"Distribution"`
- Version string `json:"Version"`
- Changed bool `json:"changed"`
-}
-
-// MemStats contains memory statistics in bytes.
-type MemStats struct {
- Total uint64 `json:"Total"`
- Available uint64 `json:"Available"`
- Free uint64 `json:"Free"`
- Cached uint64 `json:"Cached"`
- Changed bool `json:"changed"`
-}
-
-// LoadStats contains load average statistics.
-type LoadStats struct {
- Load1 float32 `json:"Load1"`
- Load5 float32 `json:"Load5"`
- Load15 float32 `json:"Load15"`
- Changed bool `json:"changed"`
-}
-
-// DiskUsage contains disk usage statistics for a single mount point.
-type DiskUsage struct {
- Name string `json:"Name"`
- Total uint64 `json:"Total"`
- Used uint64 `json:"Used"`
- Free uint64 `json:"Free"`
- Changed bool `json:"changed"`
-}
-
-// CommandResult contains the output of a command execution.
-type CommandResult struct {
- Stdout string `json:"stdout"`
- Stderr string `json:"stderr"`
- ExitCode int `json:"exit_code"`
- DurationMs int64 `json:"duration_ms"`
- Changed bool `json:"changed"`
-}
-
-// ── Input types ──────────────────────────────────────────────────────
-//
-// These mirror the internal provider param types.
-
-// ExecParams contains parameters for direct command execution.
-type ExecParams struct {
- Command string `json:"command"`
- Args []string `json:"args,omitempty"`
- Cwd string `json:"cwd,omitempty"`
- Timeout int `json:"timeout,omitempty"`
-}
-
-// ShellParams contains parameters for shell command execution.
-type ShellParams struct {
- Command string `json:"command"`
- Cwd string `json:"cwd,omitempty"`
- Timeout int `json:"timeout,omitempty"`
-}
-
-// PingParams contains parameters for the ping operation.
-type PingParams struct {
- Address string `json:"address"`
-}
-
-// PingResult contains the result of a ping operation.
-type PingResult struct {
- PacketsSent int `json:"PacketsSent"`
- PacketsReceived int `json:"PacketsReceived"`
- PacketLoss float64 `json:"PacketLoss"`
- MinRTT time.Duration `json:"MinRTT"`
- AvgRTT time.Duration `json:"AvgRTT"`
- MaxRTT time.Duration `json:"MaxRTT"`
- Changed bool `json:"changed"`
-}
-
-// DNSGetParams contains parameters for DNS configuration retrieval.
-type DNSGetParams struct {
- InterfaceName string `json:"interface_name"`
-}
-
-// DNSGetResult contains DNS configuration.
-type DNSGetResult struct {
- DNSServers []string `json:"DNSServers"`
- SearchDomains []string `json:"SearchDomains"`
-}
-
-// DNSUpdateParams contains parameters for DNS configuration update.
-type DNSUpdateParams struct {
- Servers []string `json:"servers"`
- SearchDomains []string `json:"search_domains"`
- InterfaceName string `json:"interface_name"`
-}
-
-// DNSUpdateResult contains the result of a DNS update operation.
-type DNSUpdateResult struct {
- Changed bool `json:"changed"`
-}
-
-// ── Helper ───────────────────────────────────────────────────────────
-
-// run executes a provider operation and unmarshals the JSON result.
-func run[T any](
- ctx context.Context,
- cp *ContainerProvider,
- provider string,
- operation string,
- params any,
-) (*T, error) {
- var data []byte
- if params != nil {
- var err error
- data, err = json.Marshal(params)
- if err != nil {
- return nil, fmt.Errorf("marshal %s/%s params: %w", provider, operation, err)
- }
- }
-
- out, err := cp.target.ExecProvider(ctx, provider, operation, data)
- if err != nil {
- return nil, err
- }
-
- var result T
- if err := json.Unmarshal(out, &result); err != nil {
- return nil, fmt.Errorf("unmarshal %s/%s result: %w", provider, operation, err)
- }
-
- return &result, nil
-}
-
-// runScalar executes a provider operation that returns a JSON scalar
-// (string, int, float).
-func runScalar[T any](
- ctx context.Context,
- cp *ContainerProvider,
- provider string,
- operation string,
-) (T, error) {
- var zero T
-
- out, err := cp.target.ExecProvider(ctx, provider, operation, nil)
- if err != nil {
- return zero, err
- }
-
- var result T
- if err := json.Unmarshal(out, &result); err != nil {
- return zero, fmt.Errorf("unmarshal %s/%s result: %w", provider, operation, err)
- }
-
- return result, nil
-}
-
-// ── Host operations ──────────────────────────────────────────────────
-
-// GetHostname returns the container's hostname.
-func (cp *ContainerProvider) GetHostname(
- ctx context.Context,
-) (string, error) {
- return runScalar[string](ctx, cp, "host", "get-hostname")
-}
-
-// GetOSInfo returns the container's OS distribution and version.
-func (cp *ContainerProvider) GetOSInfo(
- ctx context.Context,
-) (*HostOSInfo, error) {
- return run[HostOSInfo](ctx, cp, "host", "get-os-info", nil)
-}
-
-// GetArchitecture returns the CPU architecture (e.g., x86_64, aarch64).
-func (cp *ContainerProvider) GetArchitecture(
- ctx context.Context,
-) (string, error) {
- return runScalar[string](ctx, cp, "host", "get-architecture")
-}
-
-// GetKernelVersion returns the kernel version string.
-func (cp *ContainerProvider) GetKernelVersion(
- ctx context.Context,
-) (string, error) {
- return runScalar[string](ctx, cp, "host", "get-kernel-version")
-}
-
-// GetUptime returns the system uptime as a duration.
-func (cp *ContainerProvider) GetUptime(
- ctx context.Context,
-) (time.Duration, error) {
- return runScalar[time.Duration](ctx, cp, "host", "get-uptime")
-}
-
-// GetFQDN returns the fully qualified domain name.
-func (cp *ContainerProvider) GetFQDN(
- ctx context.Context,
-) (string, error) {
- return runScalar[string](ctx, cp, "host", "get-fqdn")
-}
-
-// GetCPUCount returns the number of logical CPUs.
-func (cp *ContainerProvider) GetCPUCount(
- ctx context.Context,
-) (int, error) {
- return runScalar[int](ctx, cp, "host", "get-cpu-count")
-}
-
-// GetServiceManager returns the system service manager (e.g., systemd).
-func (cp *ContainerProvider) GetServiceManager(
- ctx context.Context,
-) (string, error) {
- return runScalar[string](ctx, cp, "host", "get-service-manager")
-}
-
-// GetPackageManager returns the system package manager (e.g., apt, dnf).
-func (cp *ContainerProvider) GetPackageManager(
- ctx context.Context,
-) (string, error) {
- return runScalar[string](ctx, cp, "host", "get-package-manager")
-}
-
-// ── Memory operations ────────────────────────────────────────────────
-
-// GetMemStats returns memory statistics.
-func (cp *ContainerProvider) GetMemStats(
- ctx context.Context,
-) (*MemStats, error) {
- return run[MemStats](ctx, cp, "mem", "get-stats", nil)
-}
-
-// ── Load operations ──────────────────────────────────────────────────
-
-// GetLoadStats returns load average statistics.
-func (cp *ContainerProvider) GetLoadStats(
- ctx context.Context,
-) (*LoadStats, error) {
- return run[LoadStats](ctx, cp, "load", "get-average-stats", nil)
-}
-
-// ── Disk operations ──────────────────────────────────────────────────
-
-// GetDiskUsage returns disk usage statistics for all local mounts.
-func (cp *ContainerProvider) GetDiskUsage(
- ctx context.Context,
-) ([]DiskUsage, error) {
- out, err := cp.target.ExecProvider(ctx, "disk", "get-local-usage-stats", nil)
- if err != nil {
- return nil, err
- }
-
- var result []DiskUsage
- if err := json.Unmarshal(out, &result); err != nil {
- return nil, fmt.Errorf("unmarshal disk/get-local-usage-stats result: %w", err)
- }
-
- return result, nil
-}
-
-// ── Command operations ───────────────────────────────────────────────
-
-// Exec runs a command inside the container via the command provider.
-func (cp *ContainerProvider) Exec(
- ctx context.Context,
- params ExecParams,
-) (*CommandResult, error) {
- return run[CommandResult](ctx, cp, "command", "exec", ¶ms)
-}
-
-// Shell runs a shell command inside the container via the command provider.
-func (cp *ContainerProvider) Shell(
- ctx context.Context,
- params ShellParams,
-) (*CommandResult, error) {
- return run[CommandResult](ctx, cp, "command", "shell", ¶ms)
-}
-
-// ── Ping operations ──────────────────────────────────────────────────
-
-// Ping pings an address from inside the container.
-func (cp *ContainerProvider) Ping(
- ctx context.Context,
- address string,
-) (*PingResult, error) {
- return run[PingResult](ctx, cp, "ping", "do", &PingParams{Address: address})
-}
-
-// ── DNS operations ───────────────────────────────────────────────────
-
-// GetDNS returns the DNS configuration for the given interface.
-func (cp *ContainerProvider) GetDNS(
- ctx context.Context,
- interfaceName string,
-) (*DNSGetResult, error) {
- return run[DNSGetResult](ctx, cp, "dns", "get-resolv-conf", &DNSGetParams{
- InterfaceName: interfaceName,
- })
-}
-
-// UpdateDNS updates the DNS configuration for the given interface.
-func (cp *ContainerProvider) UpdateDNS(
- ctx context.Context,
- params DNSUpdateParams,
-) (*DNSUpdateResult, error) {
- return run[DNSUpdateResult](ctx, cp, "dns", "update-resolv-conf", ¶ms)
-}
diff --git a/pkg/sdk/orchestrator/container_provider_public_test.go b/pkg/sdk/orchestrator/container_provider_public_test.go
deleted file mode 100644
index d695c3b9..00000000
--- a/pkg/sdk/orchestrator/container_provider_public_test.go
+++ /dev/null
@@ -1,828 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator_test
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/suite"
-
- "github.com/retr0h/osapi/pkg/sdk/orchestrator"
-)
-
-// mockTarget implements RuntimeTarget for testing.
-type mockTarget struct {
- responses map[string][]byte
- errors map[string]error
- lastData []byte
-}
-
-func (m *mockTarget) Name() string {
- return "test-container"
-}
-
-func (m *mockTarget) Runtime() string {
- return "docker"
-}
-
-func (m *mockTarget) ExecProvider(
- _ context.Context,
- provider string,
- operation string,
- data []byte,
-) ([]byte, error) {
- m.lastData = data
- key := provider + "/" + operation
-
- if err, ok := m.errors[key]; ok {
- return nil, err
- }
-
- if resp, ok := m.responses[key]; ok {
- return resp, nil
- }
-
- return nil, fmt.Errorf("unexpected call: %s", key)
-}
-
-type ContainerProviderPublicTestSuite struct {
- suite.Suite
-}
-
-func TestContainerProviderPublicTestSuite(t *testing.T) {
- suite.Run(t, new(ContainerProviderPublicTestSuite))
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetHostname() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result string, err error)
- }{
- {
- name: "returns hostname",
- response: []byte(`"my-container"`),
- validateFunc: func(result string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "my-container", result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "connection refused")
- },
- },
- {
- name: "unmarshal error",
- response: []byte(`not-json`),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "unmarshal")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-hostname": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-hostname"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetHostname(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetOSInfo() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result *orchestrator.HostOSInfo, err error)
- }{
- {
- name: "returns os info",
- response: []byte(`{"Distribution":"ubuntu","Version":"24.04"}`),
- validateFunc: func(result *orchestrator.HostOSInfo, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "ubuntu", result.Distribution)
- assert.Equal(suite.T(), "24.04", result.Version)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("timeout"),
- validateFunc: func(_ *orchestrator.HostOSInfo, err error) {
- assert.Error(suite.T(), err)
- },
- },
- {
- name: "unmarshal error",
- response: []byte(`{bad`),
- validateFunc: func(_ *orchestrator.HostOSInfo, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "unmarshal")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-os-info": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-os-info"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetOSInfo(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetMemStats() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result *orchestrator.MemStats, err error)
- }{
- {
- name: "parses memory stats",
- response: []byte(
- `{"Total":8192000000,"Available":4096000000,"Free":2048000000,"Cached":1024000000}`,
- ),
- validateFunc: func(result *orchestrator.MemStats, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), uint64(8192000000), result.Total)
- assert.Equal(suite.T(), uint64(4096000000), result.Available)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"mem/get-stats": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["mem/get-stats"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetMemStats(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetLoadStats() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result *orchestrator.LoadStats, err error)
- }{
- {
- name: "parses load stats",
- response: []byte(`{"Load1":0.5,"Load5":0.75,"Load15":1.0}`),
- validateFunc: func(result *orchestrator.LoadStats, err error) {
- assert.NoError(suite.T(), err)
- assert.InDelta(suite.T(), float32(0.5), result.Load1, 0.01)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"load/get-average-stats": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["load/get-average-stats"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetLoadStats(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestExec() {
- tests := []struct {
- name string
- params orchestrator.ExecParams
- response []byte
- err error
- validateFunc func(result *orchestrator.CommandResult, err error, lastData []byte)
- }{
- {
- name: "runs command with changed true",
- params: orchestrator.ExecParams{
- Command: "uname",
- Args: []string{"-a"},
- },
- response: []byte(
- `{"stdout":"Linux container 5.15.0\n","stderr":"","exit_code":0,"duration_ms":5,"changed":true}`,
- ),
- validateFunc: func(result *orchestrator.CommandResult, err error, lastData []byte) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "Linux container 5.15.0\n", result.Stdout)
- assert.True(suite.T(), result.Changed)
-
- var sent orchestrator.ExecParams
- _ = json.Unmarshal(lastData, &sent)
- assert.Equal(suite.T(), "uname", sent.Command)
- assert.Equal(suite.T(), []string{"-a"}, sent.Args)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"command/exec": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["command/exec"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.Exec(context.Background(), tc.params)
- tc.validateFunc(result, err, target.lastData)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestShell() {
- tests := []struct {
- name string
- command string
- response []byte
- err error
- validateFunc func(result *orchestrator.CommandResult, err error)
- }{
- {
- name: "runs shell command",
- command: "echo hello",
- response: []byte(`{"stdout":"hello\n","stderr":"","exit_code":0,"duration_ms":2}`),
- validateFunc: func(result *orchestrator.CommandResult, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "hello\n", result.Stdout)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"command/shell": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["command/shell"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.Shell(context.Background(), orchestrator.ShellParams{
- Command: tc.command,
- })
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestPing() {
- tests := []struct {
- name string
- address string
- response []byte
- err error
- validateFunc func(result *orchestrator.PingResult, err error, lastData []byte)
- }{
- {
- name: "pings address",
- address: "8.8.8.8",
- response: []byte(`{"PacketsSent":3,"PacketsReceived":3,"PacketLoss":0}`),
- validateFunc: func(result *orchestrator.PingResult, err error, lastData []byte) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), 3, result.PacketsSent)
-
- var sent orchestrator.PingParams
- _ = json.Unmarshal(lastData, &sent)
- assert.Equal(suite.T(), "8.8.8.8", sent.Address)
- },
- },
- {
- name: "exec error",
- address: "8.8.8.8",
- err: fmt.Errorf("timeout"),
- validateFunc: func(_ *orchestrator.PingResult, err error, _ []byte) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"ping/do": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["ping/do"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.Ping(context.Background(), tc.address)
- tc.validateFunc(result, err, target.lastData)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetArchitecture() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result string, err error)
- }{
- {
- name: "returns architecture",
- response: []byte(`"x86_64"`),
- validateFunc: func(result string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "x86_64", result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-architecture": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-architecture"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetArchitecture(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetKernelVersion() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result string, err error)
- }{
- {
- name: "returns kernel version",
- response: []byte(`"5.15.0-91-generic"`),
- validateFunc: func(result string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "5.15.0-91-generic", result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-kernel-version": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-kernel-version"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetKernelVersion(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetUptime() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result time.Duration, err error)
- }{
- {
- name: "returns uptime duration",
- response: []byte(`3600000000000`),
- validateFunc: func(result time.Duration, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), time.Hour, result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ time.Duration, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-uptime": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-uptime"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetUptime(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetFQDN() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result string, err error)
- }{
- {
- name: "returns fqdn",
- response: []byte(`"web-01.example.com"`),
- validateFunc: func(result string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "web-01.example.com", result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-fqdn": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-fqdn"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetFQDN(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetCPUCount() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result int, err error)
- }{
- {
- name: "returns cpu count",
- response: []byte(`4`),
- validateFunc: func(result int, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), 4, result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ int, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-cpu-count": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-cpu-count"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetCPUCount(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetServiceManager() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result string, err error)
- }{
- {
- name: "returns service manager",
- response: []byte(`"systemd"`),
- validateFunc: func(result string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "systemd", result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-service-manager": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-service-manager"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetServiceManager(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetPackageManager() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result string, err error)
- }{
- {
- name: "returns package manager",
- response: []byte(`"apt"`),
- validateFunc: func(result string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "apt", result)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"host/get-package-manager": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["host/get-package-manager"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetPackageManager(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetDiskUsage() {
- tests := []struct {
- name string
- response []byte
- err error
- validateFunc func(result []orchestrator.DiskUsage, err error)
- }{
- {
- name: "returns disk usage",
- response: []byte(
- `[{"Name":"/","Total":50000000000,"Used":25000000000,"Free":25000000000}]`,
- ),
- validateFunc: func(result []orchestrator.DiskUsage, err error) {
- assert.NoError(suite.T(), err)
- assert.Len(suite.T(), result, 1)
- assert.Equal(suite.T(), "/", result[0].Name)
- assert.Equal(suite.T(), uint64(50000000000), result[0].Total)
- },
- },
- {
- name: "exec error",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ []orchestrator.DiskUsage, err error) {
- assert.Error(suite.T(), err)
- },
- },
- {
- name: "unmarshal error",
- response: []byte(`not-json`),
- validateFunc: func(_ []orchestrator.DiskUsage, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "unmarshal")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"disk/get-local-usage-stats": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["disk/get-local-usage-stats"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetDiskUsage(context.Background())
- tc.validateFunc(result, err)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestGetDNS() {
- tests := []struct {
- name string
- iface string
- response []byte
- err error
- validateFunc func(result *orchestrator.DNSGetResult, err error, lastData []byte)
- }{
- {
- name: "returns dns config",
- iface: "eth0",
- response: []byte(
- `{"DNSServers":["8.8.8.8","8.8.4.4"],"SearchDomains":["example.com"]}`,
- ),
- validateFunc: func(result *orchestrator.DNSGetResult, err error, lastData []byte) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), []string{"8.8.8.8", "8.8.4.4"}, result.DNSServers)
- assert.Equal(suite.T(), []string{"example.com"}, result.SearchDomains)
-
- var sent orchestrator.DNSGetParams
- _ = json.Unmarshal(lastData, &sent)
- assert.Equal(suite.T(), "eth0", sent.InterfaceName)
- },
- },
- {
- name: "exec error",
- iface: "eth0",
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ *orchestrator.DNSGetResult, err error, _ []byte) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"dns/get-resolv-conf": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["dns/get-resolv-conf"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.GetDNS(context.Background(), tc.iface)
- tc.validateFunc(result, err, target.lastData)
- })
- }
-}
-
-func (suite *ContainerProviderPublicTestSuite) TestUpdateDNS() {
- tests := []struct {
- name string
- params orchestrator.DNSUpdateParams
- response []byte
- err error
- validateFunc func(result *orchestrator.DNSUpdateResult, err error, lastData []byte)
- }{
- {
- name: "updates dns config",
- params: orchestrator.DNSUpdateParams{
- Servers: []string{"8.8.8.8"},
- SearchDomains: []string{"example.com"},
- InterfaceName: "eth0",
- },
- response: []byte(`{"changed":true}`),
- validateFunc: func(result *orchestrator.DNSUpdateResult, err error, lastData []byte) {
- assert.NoError(suite.T(), err)
- assert.True(suite.T(), result.Changed)
-
- var sent orchestrator.DNSUpdateParams
- _ = json.Unmarshal(lastData, &sent)
- assert.Equal(suite.T(), []string{"8.8.8.8"}, sent.Servers)
- assert.Equal(suite.T(), "eth0", sent.InterfaceName)
- },
- },
- {
- name: "exec error",
- params: orchestrator.DNSUpdateParams{
- Servers: []string{"8.8.8.8"},
- InterfaceName: "eth0",
- },
- err: fmt.Errorf("connection refused"),
- validateFunc: func(_ *orchestrator.DNSUpdateResult, err error, _ []byte) {
- assert.Error(suite.T(), err)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &mockTarget{
- responses: map[string][]byte{"dns/update-resolv-conf": tc.response},
- errors: map[string]error{},
- }
- if tc.err != nil {
- target.errors["dns/update-resolv-conf"] = tc.err
- }
-
- cp := orchestrator.NewContainerProvider(target)
- result, err := cp.UpdateDNS(context.Background(), tc.params)
- tc.validateFunc(result, err, target.lastData)
- })
- }
-}
diff --git a/pkg/sdk/orchestrator/container_provider_test.go b/pkg/sdk/orchestrator/container_provider_test.go
deleted file mode 100644
index 49f20717..00000000
--- a/pkg/sdk/orchestrator/container_provider_test.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/suite"
-)
-
-type ContainerProviderTestSuite struct {
- suite.Suite
-}
-
-func TestContainerProviderTestSuite(t *testing.T) {
- suite.Run(t, new(ContainerProviderTestSuite))
-}
-
-func (suite *ContainerProviderTestSuite) TestRunMarshalError() {
- tests := []struct {
- name string
- params any
- validateFunc func(err error)
- }{
- {
- name: "returns error when params cannot be marshaled",
- params: make(chan int),
- validateFunc: func(err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "marshal")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- target := &DockerTarget{
- name: "test",
- execFn: func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return `{}`, "", 0, nil
- },
- }
-
- cp := NewContainerProvider(target)
- _, err := run[CommandResult](
- context.Background(),
- cp,
- "test",
- "op",
- tc.params,
- )
- tc.validateFunc(err)
- })
- }
-}
diff --git a/pkg/sdk/orchestrator/deploy.go b/pkg/sdk/orchestrator/deploy.go
deleted file mode 100644
index 72fc2226..00000000
--- a/pkg/sdk/orchestrator/deploy.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "net/http"
- "strings"
-)
-
-const (
- defaultGitHubOwner = "retr0h"
- defaultGitHubRepo = "osapi"
-)
-
-// releaseAsset represents a single asset in a GitHub release.
-type releaseAsset struct {
- Name string `json:"name"`
- BrowserDownloadURL string `json:"browser_download_url"`
-}
-
-// githubRelease represents the GitHub API response for a release.
-type githubRelease struct {
- TagName string `json:"tag_name"`
- Assets []releaseAsset `json:"assets"`
-}
-
-// httpClient allows injection of a custom HTTP client for testing.
-var httpClient = http.DefaultClient
-
-// resolveLatestBinaryURL queries the GitHub API for the latest release
-// of the osapi repository and returns the download URL for the binary
-// matching the given OS and architecture.
-func resolveLatestBinaryURL(
- ctx context.Context,
- goos string,
- goarch string,
-) (string, error) {
- apiURL := fmt.Sprintf(
- "https://api.github.com/repos/%s/%s/releases/latest",
- defaultGitHubOwner,
- defaultGitHubRepo,
- )
-
- return resolveFromURL(ctx, apiURL, goos, goarch)
-}
-
-// resolveFromURL fetches a GitHub release JSON from the given URL and
-// returns the download URL for the binary matching goos/goarch.
-func resolveFromURL(
- ctx context.Context,
- apiURL string,
- goos string,
- goarch string,
-) (string, error) {
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil)
- if err != nil {
- return "", fmt.Errorf("create request: %w", err)
- }
-
- req.Header.Set("Accept", "application/vnd.github+json")
-
- resp, err := httpClient.Do(req)
- if err != nil {
- return "", fmt.Errorf("query GitHub releases: %w", err)
- }
- defer func() { _ = resp.Body.Close() }()
-
- if resp.StatusCode != http.StatusOK {
- return "", fmt.Errorf(
- "GitHub releases returned %d (no release published?)",
- resp.StatusCode,
- )
- }
-
- var release githubRelease
- if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
- return "", fmt.Errorf("decode release response: %w", err)
- }
-
- return matchAsset(release.Assets, goos, goarch)
-}
-
-// matchAsset finds the download URL for the binary matching the given
-// OS and architecture in the release assets.
-func matchAsset(
- assets []releaseAsset,
- goos string,
- goarch string,
-) (string, error) {
- suffix := fmt.Sprintf("_%s_%s", goos, goarch)
-
- for _, a := range assets {
- if strings.HasSuffix(a.Name, suffix) {
- return a.BrowserDownloadURL, nil
- }
- }
-
- return "", fmt.Errorf(
- "no osapi binary found for %s/%s in release assets",
- goos,
- goarch,
- )
-}
-
-// deployScript returns a shell script that ensures curl is available
-// and downloads the osapi binary to /osapi inside the container.
-func deployScript(
- binaryURL string,
-) string {
- return fmt.Sprintf(
- `command -v curl >/dev/null 2>&1 || `+
- `(apt-get update -qq && apt-get install -y -qq ca-certificates curl >/dev/null 2>&1) && `+
- `curl -fsSL '%s' -o /osapi && chmod +x /osapi`,
- binaryURL,
- )
-}
diff --git a/pkg/sdk/orchestrator/deploy_public_test.go b/pkg/sdk/orchestrator/deploy_public_test.go
deleted file mode 100644
index f5d61a2b..00000000
--- a/pkg/sdk/orchestrator/deploy_public_test.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator_test
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/suite"
-
- "github.com/retr0h/osapi/pkg/sdk/orchestrator"
-)
-
-type DeployPublicTestSuite struct {
- suite.Suite
-}
-
-func TestDeployPublicTestSuite(t *testing.T) {
- suite.Run(t, new(DeployPublicTestSuite))
-}
-
-func (suite *DeployPublicTestSuite) TestPrepare() {
- tests := []struct {
- name string
- binaryURL string
- skipPrepare bool
- callTwice bool
- execStdout string
- execStderr string
- execCode int
- execErr error
- validateFunc func(err error, capturedCmds [][]string)
- }{
- {
- name: "downloads binary from custom URL",
- binaryURL: "https://example.com/osapi-linux",
- validateFunc: func(err error, capturedCmds [][]string) {
- assert.NoError(suite.T(), err)
- assert.Len(suite.T(), capturedCmds, 1)
- assert.Equal(suite.T(), "sh", capturedCmds[0][0])
- assert.Equal(suite.T(), "-c", capturedCmds[0][1])
- assert.Contains(suite.T(), capturedCmds[0][2], "https://example.com/osapi-linux")
- assert.Contains(suite.T(), capturedCmds[0][2], "curl")
- assert.Contains(suite.T(), capturedCmds[0][2], "chmod +x /osapi")
- },
- },
- {
- name: "returns error on non-zero exit",
- binaryURL: "https://example.com/osapi-linux",
- execStderr: "curl: (22) 404 Not Found",
- execCode: 22,
- validateFunc: func(err error, _ [][]string) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "deploy osapi binary (exit 22)")
- assert.Contains(suite.T(), err.Error(), "404 Not Found")
- },
- },
- {
- name: "returns error on exec failure",
- binaryURL: "https://example.com/osapi-linux",
- execErr: assert.AnError,
- validateFunc: func(err error, _ [][]string) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "deploy osapi binary")
- },
- },
- {
- name: "skips preparation when configured",
- skipPrepare: true,
- validateFunc: func(err error, capturedCmds [][]string) {
- assert.NoError(suite.T(), err)
- assert.Empty(suite.T(), capturedCmds)
- },
- },
- {
- name: "executes preparation only once across multiple calls",
- binaryURL: "https://example.com/osapi",
- callTwice: true,
- validateFunc: func(err error, capturedCmds [][]string) {
- assert.NoError(suite.T(), err)
- assert.Len(suite.T(), capturedCmds, 1)
- },
- },
- {
- name: "returns error when GitHub release resolution fails",
- validateFunc: func(err error, _ [][]string) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "resolve osapi binary")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- var capturedCmds [][]string
-
- execFn := func(
- _ context.Context,
- _ string,
- cmd []string,
- ) (string, string, int, error) {
- capturedCmds = append(capturedCmds, cmd)
- if tc.execErr != nil {
- return "", "", -1, tc.execErr
- }
-
- return tc.execStdout, tc.execStderr, tc.execCode, nil
- }
-
- target := orchestrator.NewDockerTarget("web", "ubuntu:24.04", execFn)
- if tc.binaryURL != "" {
- target.SetBinaryURL(tc.binaryURL)
- }
- if tc.skipPrepare {
- target.SetSkipPrepare(true)
- }
-
- if tc.callTwice {
- _ = target.Prepare(context.Background())
- }
-
- err := target.Prepare(context.Background())
- tc.validateFunc(err, capturedCmds)
- })
- }
-}
-
-func (suite *DeployPublicTestSuite) TestExecProvider() {
- tests := []struct {
- name string
- binaryURL string
- validateFunc func(result []byte, err error, cmds [][]string)
- }{
- {
- name: "returns prepare error",
- validateFunc: func(result []byte, err error, _ [][]string) {
- assert.Error(suite.T(), err)
- assert.Nil(suite.T(), result)
- assert.Contains(suite.T(), err.Error(), "resolve osapi binary")
- },
- },
- {
- name: "triggers automatic preparation",
- binaryURL: "https://example.com/osapi",
- validateFunc: func(_ []byte, err error, cmds [][]string) {
- assert.NoError(suite.T(), err)
- // First call is the deploy script, second is the provider command.
- assert.Len(suite.T(), cmds, 2)
- assert.Equal(suite.T(), "sh", cmds[0][0])
- assert.Contains(suite.T(), cmds[0][2], "curl")
- assert.Equal(suite.T(), "/osapi", cmds[1][0])
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- var cmds [][]string
-
- execFn := func(
- _ context.Context,
- _ string,
- cmd []string,
- ) (string, string, int, error) {
- cmds = append(cmds, cmd)
-
- return `"ok"`, "", 0, nil
- }
-
- target := orchestrator.NewDockerTarget("web", "ubuntu:24.04", execFn)
- if tc.binaryURL != "" {
- target.SetBinaryURL(tc.binaryURL)
- }
-
- result, err := target.ExecProvider(
- context.Background(),
- "host",
- "get-hostname",
- nil,
- )
- tc.validateFunc(result, err, cmds)
- })
- }
-}
diff --git a/pkg/sdk/orchestrator/deploy_test.go b/pkg/sdk/orchestrator/deploy_test.go
deleted file mode 100644
index 2d89c2cf..00000000
--- a/pkg/sdk/orchestrator/deploy_test.go
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-import (
- "context"
- "encoding/json"
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/suite"
-)
-
-type DeployTestSuite struct {
- suite.Suite
-}
-
-func TestDeployTestSuite(t *testing.T) {
- suite.Run(t, new(DeployTestSuite))
-}
-
-func (suite *DeployTestSuite) TestMatchAsset() {
- tests := []struct {
- name string
- assets []releaseAsset
- goos string
- goarch string
- validateFunc func(url string, err error)
- }{
- {
- name: "matches linux amd64 asset",
- assets: []releaseAsset{
- {Name: "osapi_1.0.0_darwin_all", BrowserDownloadURL: "https://example.com/darwin"},
- {
- Name: "osapi_1.0.0_linux_amd64",
- BrowserDownloadURL: "https://example.com/linux_amd64",
- },
- {
- Name: "osapi_1.0.0_linux_arm64",
- BrowserDownloadURL: "https://example.com/linux_arm64",
- },
- },
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(url string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "https://example.com/linux_amd64", url)
- },
- },
- {
- name: "matches linux arm64 asset",
- assets: []releaseAsset{
- {
- Name: "osapi_1.0.0_linux_amd64",
- BrowserDownloadURL: "https://example.com/linux_amd64",
- },
- {
- Name: "osapi_1.0.0_linux_arm64",
- BrowserDownloadURL: "https://example.com/linux_arm64",
- },
- },
- goos: "linux",
- goarch: "arm64",
- validateFunc: func(url string, err error) {
- assert.NoError(suite.T(), err)
- assert.Equal(suite.T(), "https://example.com/linux_arm64", url)
- },
- },
- {
- name: "returns error when no matching asset",
- assets: []releaseAsset{
- {Name: "osapi_1.0.0_darwin_all", BrowserDownloadURL: "https://example.com/darwin"},
- },
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "no osapi binary found for linux/amd64")
- },
- },
- {
- name: "returns error when no assets",
- assets: nil,
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "no osapi binary found")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- url, err := matchAsset(tc.assets, tc.goos, tc.goarch)
- tc.validateFunc(url, err)
- })
- }
-}
-
-func (suite *DeployTestSuite) TestResolveFromURL() {
- tests := []struct {
- name string
- handler http.HandlerFunc
- goos string
- goarch string
- validateFunc func(url string, err error)
- }{
- {
- name: "resolves URL from release response",
- handler: func(w http.ResponseWriter, _ *http.Request) {
- release := githubRelease{
- TagName: "v1.0.0",
- Assets: []releaseAsset{
- {
- Name: "osapi_1.0.0_linux_amd64",
- BrowserDownloadURL: "https://github.com/retr0h/osapi/releases/download/v1.0.0/osapi_1.0.0_linux_amd64",
- },
- },
- }
- w.Header().Set("Content-Type", "application/json")
- _ = json.NewEncoder(w).Encode(release)
- },
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(url string, err error) {
- assert.NoError(suite.T(), err)
- assert.Contains(suite.T(), url, "osapi_1.0.0_linux_amd64")
- },
- },
- {
- name: "returns error on 404",
- handler: func(w http.ResponseWriter, _ *http.Request) {
- w.WriteHeader(http.StatusNotFound)
- },
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "404")
- },
- },
- {
- name: "returns error on invalid JSON",
- handler: func(w http.ResponseWriter, _ *http.Request) {
- _, _ = w.Write([]byte(`{invalid`))
- },
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "decode")
- },
- },
- {
- name: "returns error when no matching asset in release",
- handler: func(w http.ResponseWriter, _ *http.Request) {
- release := githubRelease{
- TagName: "v1.0.0",
- Assets: []releaseAsset{
- {
- Name: "osapi_1.0.0_darwin_all",
- BrowserDownloadURL: "https://example.com/darwin",
- },
- },
- }
- w.Header().Set("Content-Type", "application/json")
- _ = json.NewEncoder(w).Encode(release)
- },
- goos: "linux",
- goarch: "amd64",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "no osapi binary found")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- server := httptest.NewServer(tc.handler)
- defer server.Close()
-
- url, err := resolveFromURL(
- context.Background(),
- server.URL,
- tc.goos,
- tc.goarch,
- )
- tc.validateFunc(url, err)
- })
- }
-}
-
-func (suite *DeployTestSuite) TestResolveLatestBinaryURL() {
- tests := []struct {
- name string
- handler http.HandlerFunc
- validateFunc func(url string, err error)
- }{
- {
- name: "resolves from GitHub API",
- handler: func(w http.ResponseWriter, _ *http.Request) {
- release := githubRelease{
- TagName: "v1.0.0",
- Assets: []releaseAsset{
- {
- Name: "osapi_1.0.0_linux_arm64",
- BrowserDownloadURL: "https://example.com/arm64",
- },
- {
- Name: "osapi_1.0.0_linux_amd64",
- BrowserDownloadURL: "https://example.com/amd64",
- },
- },
- }
- w.Header().Set("Content-Type", "application/json")
- _ = json.NewEncoder(w).Encode(release)
- },
- validateFunc: func(url string, err error) {
- assert.NoError(suite.T(), err)
- assert.NotEmpty(suite.T(), url)
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- server := httptest.NewServer(tc.handler)
- defer server.Close()
-
- original := httpClient
- // Create a client that redirects all requests to the test server.
- httpClient = &http.Client{
- Transport: &rewriteTransport{
- base: server.Client().Transport,
- url: server.URL,
- },
- }
- defer func() { httpClient = original }()
-
- url, err := resolveLatestBinaryURL(
- context.Background(),
- "linux",
- "amd64",
- )
- tc.validateFunc(url, err)
- })
- }
-}
-
-// rewriteTransport redirects all requests to a test server URL.
-type rewriteTransport struct {
- base http.RoundTripper
- url string
-}
-
-func (t *rewriteTransport) RoundTrip(
- req *http.Request,
-) (*http.Response, error) {
- req = req.Clone(req.Context())
- req.URL.Scheme = "http"
- req.URL.Host = t.url[len("http://"):]
-
- return t.base.RoundTrip(req)
-}
-
-func (suite *DeployTestSuite) TestResolveFromURLHTTPError() {
- tests := []struct {
- name string
- apiURL string
- validateFunc func(url string, err error)
- }{
- {
- name: "returns error on connection failure",
- apiURL: "http://127.0.0.1:0/invalid",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "query GitHub releases")
- },
- },
- {
- name: "returns error on invalid URL",
- apiURL: "http://invalid\x00url",
- validateFunc: func(_ string, err error) {
- assert.Error(suite.T(), err)
- assert.Contains(suite.T(), err.Error(), "create request")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- url, err := resolveFromURL(
- context.Background(),
- tc.apiURL,
- "linux",
- "amd64",
- )
- tc.validateFunc(url, err)
- })
- }
-}
-
-func (suite *DeployTestSuite) TestDeployScript() {
- tests := []struct {
- name string
- binaryURL string
- validateFunc func(script string)
- }{
- {
- name: "generates valid download script",
- binaryURL: "https://example.com/osapi",
- validateFunc: func(script string) {
- assert.Contains(suite.T(), script, "curl")
- assert.Contains(suite.T(), script, "https://example.com/osapi")
- assert.Contains(suite.T(), script, "-o /osapi")
- assert.Contains(suite.T(), script, "chmod +x /osapi")
- },
- },
- }
-
- for _, tc := range tests {
- suite.Run(tc.name, func() {
- script := deployScript(tc.binaryURL)
- tc.validateFunc(script)
- })
- }
-}
diff --git a/pkg/sdk/orchestrator/docker.go b/pkg/sdk/orchestrator/docker.go
new file mode 100644
index 00000000..7c1af2a3
--- /dev/null
+++ b/pkg/sdk/orchestrator/docker.go
@@ -0,0 +1,249 @@
+package orchestrator
+
+import (
+ "context"
+
+ osapiclient "github.com/retr0h/osapi/pkg/sdk/client"
+ "github.com/retr0h/osapi/pkg/sdk/client/gen"
+)
+
+// DockerPull creates a task that pulls a Docker image on the target host.
+func (p *Plan) DockerPull(
+ name string,
+ target string,
+ image string,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Pull(ctx, target, gen.DockerPullRequest{
+ Image: image,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: r.Changed,
+ Data: map[string]any{
+ "image_id": r.ImageID,
+ "tag": r.Tag,
+ "size": r.Size,
+ },
+ }, nil
+ })
+}
+
+// DockerCreate creates a task that creates a Docker container on the
+// target host.
+func (p *Plan) DockerCreate(
+ name string,
+ target string,
+ body gen.DockerCreateRequest,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Create(ctx, target, body)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: r.Changed,
+ Data: map[string]any{
+ "id": r.ID,
+ "name": r.Name,
+ "image": r.Image,
+ "state": r.State,
+ },
+ }, nil
+ })
+}
+
+// DockerStart creates a task that starts a Docker container on the
+// target host.
+func (p *Plan) DockerStart(
+ name string,
+ target string,
+ id string,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Start(ctx, target, id)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: r.Changed,
+ Data: map[string]any{
+ "id": r.ID,
+ "message": r.Message,
+ },
+ }, nil
+ })
+}
+
+// DockerStop creates a task that stops a Docker container on the
+// target host.
+func (p *Plan) DockerStop(
+ name string,
+ target string,
+ id string,
+ body gen.DockerStopRequest,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Stop(ctx, target, id, body)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: r.Changed,
+ Data: map[string]any{
+ "id": r.ID,
+ "message": r.Message,
+ },
+ }, nil
+ })
+}
+
+// DockerRemove creates a task that removes a Docker container from the
+// target host.
+func (p *Plan) DockerRemove(
+ name string,
+ target string,
+ id string,
+ params *gen.DeleteNodeContainerDockerByIDParams,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Remove(ctx, target, id, params)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: r.Changed,
+ Data: map[string]any{
+ "id": r.ID,
+ "message": r.Message,
+ },
+ }, nil
+ })
+}
+
+// DockerExec creates a task that executes a command in a Docker
+// container.
+func (p *Plan) DockerExec(
+ name string,
+ target string,
+ id string,
+ body gen.DockerExecRequest,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Exec(ctx, target, id, body)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: r.Changed,
+ Data: map[string]any{
+ "stdout": r.Stdout,
+ "stderr": r.Stderr,
+ "exit_code": r.ExitCode,
+ },
+ }, nil
+ })
+}
+
+// DockerInspect creates a task that inspects a Docker container on the
+// target host.
+func (p *Plan) DockerInspect(
+ name string,
+ target string,
+ id string,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.Inspect(ctx, target, id)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: false,
+ Data: map[string]any{
+ "id": r.ID,
+ "name": r.Name,
+ "image": r.Image,
+ "state": r.State,
+ },
+ }, nil
+ })
+}
+
+// DockerList creates a task that lists Docker containers on the target
+// host.
+func (p *Plan) DockerList(
+ name string,
+ target string,
+ params *gen.GetNodeContainerDockerParams,
+) *Task {
+ return p.TaskFunc(name, func(
+ ctx context.Context,
+ c *osapiclient.Client,
+ ) (*Result, error) {
+ resp, err := c.Docker.List(ctx, target, params)
+ if err != nil {
+ return nil, err
+ }
+
+ r := resp.Data.Results[0]
+
+ return &Result{
+ JobID: resp.Data.JobID,
+ Changed: false,
+ Data: map[string]any{
+ "containers": r.Containers,
+ },
+ }, nil
+ })
+}
diff --git a/pkg/sdk/orchestrator/docker_public_test.go b/pkg/sdk/orchestrator/docker_public_test.go
new file mode 100644
index 00000000..0bbda3e2
--- /dev/null
+++ b/pkg/sdk/orchestrator/docker_public_test.go
@@ -0,0 +1,711 @@
+package orchestrator_test
+
+import (
+ "context"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/suite"
+
+ osapiclient "github.com/retr0h/osapi/pkg/sdk/client"
+ "github.com/retr0h/osapi/pkg/sdk/client/gen"
+ "github.com/retr0h/osapi/pkg/sdk/orchestrator"
+)
+
+type DockerPublicTestSuite struct {
+ suite.Suite
+}
+
+func (s *DockerPublicTestSuite) TestDockerPull() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ image string
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "pull-image",
+ target: "_any",
+ image: "ubuntu:24.04",
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("pull-image", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "pull-image",
+ target: "_any",
+ image: "alpine:latest",
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000001","results":[{"hostname":"h1","image_id":"sha256:abc","tag":"latest","size":1024,"changed":true}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000001", result.JobID)
+ s.True(result.Changed)
+ s.Equal("sha256:abc", result.Data["image_id"])
+ s.Equal("latest", result.Data["tag"])
+ s.Equal(int64(1024), result.Data["size"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "pull-image",
+ target: "_any",
+ image: "alpine:latest",
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerPull(tt.taskName, tt.target, tt.image)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerCreate() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ body gen.DockerCreateRequest
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "create-container",
+ target: "_any",
+ body: gen.DockerCreateRequest{Image: "nginx:latest"},
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("create-container", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "create-container",
+ target: "_any",
+ body: gen.DockerCreateRequest{Image: "nginx:latest"},
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000002","results":[{"hostname":"h1","id":"c1","name":"web","image":"nginx:latest","state":"created","changed":true}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000002", result.JobID)
+ s.True(result.Changed)
+ s.Equal("c1", result.Data["id"])
+ s.Equal("web", result.Data["name"])
+ s.Equal("nginx:latest", result.Data["image"])
+ s.Equal("created", result.Data["state"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "create-container",
+ target: "_any",
+ body: gen.DockerCreateRequest{Image: "nginx:latest"},
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerCreate(tt.taskName, tt.target, tt.body)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerStart() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ id string
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "start-container",
+ target: "_any",
+ id: "abc123",
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("start-container", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "start-container",
+ target: "_any",
+ id: "abc123",
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000003","results":[{"hostname":"h1","id":"abc123","message":"started","changed":true}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000003", result.JobID)
+ s.True(result.Changed)
+ s.Equal("abc123", result.Data["id"])
+ s.Equal("started", result.Data["message"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "start-container",
+ target: "_any",
+ id: "abc123",
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerStart(tt.taskName, tt.target, tt.id)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerStop() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ id string
+ body gen.DockerStopRequest
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "stop-container",
+ target: "_any",
+ id: "abc123",
+ body: gen.DockerStopRequest{},
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("stop-container", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "stop-container",
+ target: "_any",
+ id: "abc123",
+ body: gen.DockerStopRequest{},
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000004","results":[{"hostname":"h1","id":"abc123","message":"stopped","changed":true}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000004", result.JobID)
+ s.True(result.Changed)
+ s.Equal("abc123", result.Data["id"])
+ s.Equal("stopped", result.Data["message"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "stop-container",
+ target: "_any",
+ id: "abc123",
+ body: gen.DockerStopRequest{},
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerStop(tt.taskName, tt.target, tt.id, tt.body)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerRemove() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ id string
+ params *gen.DeleteNodeContainerDockerByIDParams
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "remove-container",
+ target: "_any",
+ id: "abc123",
+ params: nil,
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("remove-container", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "remove-container",
+ target: "_any",
+ id: "abc123",
+ params: nil,
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000005","results":[{"hostname":"h1","id":"abc123","message":"removed","changed":true}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000005", result.JobID)
+ s.True(result.Changed)
+ s.Equal("abc123", result.Data["id"])
+ s.Equal("removed", result.Data["message"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "remove-container",
+ target: "_any",
+ id: "abc123",
+ params: nil,
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerRemove(tt.taskName, tt.target, tt.id, tt.params)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerExec() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ id string
+ body gen.DockerExecRequest
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "exec-cmd",
+ target: "_any",
+ id: "abc123",
+ body: gen.DockerExecRequest{Command: []string{"hostname"}},
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("exec-cmd", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "exec-cmd",
+ target: "_any",
+ id: "abc123",
+ body: gen.DockerExecRequest{Command: []string{"hostname"}},
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusAccepted)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000006","results":[{"hostname":"h1","stdout":"web-01\n","stderr":"","exit_code":0,"changed":true}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000006", result.JobID)
+ s.True(result.Changed)
+ s.Equal("web-01\n", result.Data["stdout"])
+ s.Equal("", result.Data["stderr"])
+ s.Equal(0, result.Data["exit_code"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "exec-cmd",
+ target: "_any",
+ id: "abc123",
+ body: gen.DockerExecRequest{Command: []string{"hostname"}},
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerExec(tt.taskName, tt.target, tt.id, tt.body)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerInspect() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ id string
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "inspect-container",
+ target: "_any",
+ id: "abc123",
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("inspect-container", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "inspect-container",
+ target: "_any",
+ id: "abc123",
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000007","results":[{"hostname":"h1","id":"abc123","name":"web","image":"nginx:latest","state":"running"}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000007", result.JobID)
+ s.False(result.Changed)
+ s.Equal("abc123", result.Data["id"])
+ s.Equal("web", result.Data["name"])
+ s.Equal("nginx:latest", result.Data["image"])
+ s.Equal("running", result.Data["state"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "inspect-container",
+ target: "_any",
+ id: "abc123",
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerInspect(tt.taskName, tt.target, tt.id)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func (s *DockerPublicTestSuite) TestDockerList() {
+ tests := []struct {
+ name string
+ taskName string
+ target string
+ params *gen.GetNodeContainerDockerParams
+ handler http.HandlerFunc
+ validateFunc func(*orchestrator.Task, *osapiclient.Client)
+ }{
+ {
+ name: "creates task with correct name",
+ taskName: "list-containers",
+ target: "_any",
+ params: nil,
+ validateFunc: func(
+ task *orchestrator.Task,
+ _ *osapiclient.Client,
+ ) {
+ s.NotNil(task)
+ s.Equal("list-containers", task.Name())
+ },
+ },
+ {
+ name: "executes closure and returns result",
+ taskName: "list-containers",
+ target: "_any",
+ params: nil,
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write([]byte(
+ `{"job_id":"00000000-0000-0000-0000-000000000008","results":[{"hostname":"h1","containers":[{"id":"c1","name":"web","image":"nginx","state":"running"}]}]}`,
+ ))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.NoError(err)
+ s.Equal("00000000-0000-0000-0000-000000000008", result.JobID)
+ s.False(result.Changed)
+ s.NotNil(result.Data["containers"])
+ },
+ },
+ {
+ name: "returns error when SDK call fails",
+ taskName: "list-containers",
+ target: "_any",
+ params: nil,
+ handler: func(w http.ResponseWriter, _ *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusForbidden)
+ _, _ = w.Write([]byte(`{"error":"forbidden"}`))
+ },
+ validateFunc: func(
+ task *orchestrator.Task,
+ c *osapiclient.Client,
+ ) {
+ result, err := task.Fn()(context.Background(), c)
+ s.Error(err)
+ s.Nil(result)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ s.Run(tt.name, func() {
+ var c *osapiclient.Client
+ if tt.handler != nil {
+ srv := httptest.NewServer(tt.handler)
+ defer srv.Close()
+ c = osapiclient.New(srv.URL, "token")
+ }
+
+ plan := orchestrator.NewPlan(c)
+ task := plan.DockerList(tt.taskName, tt.target, tt.params)
+ tt.validateFunc(task, c)
+ s.Len(plan.Tasks(), 1)
+ })
+ }
+}
+
+func TestDockerPublicTestSuite(t *testing.T) {
+ suite.Run(t, new(DockerPublicTestSuite))
+}
diff --git a/pkg/sdk/orchestrator/docker_target.go b/pkg/sdk/orchestrator/docker_target.go
deleted file mode 100644
index ffd3c8d5..00000000
--- a/pkg/sdk/orchestrator/docker_target.go
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-import (
- "context"
- "fmt"
- "runtime"
- "sync"
-)
-
-// ExecFn executes a command inside a container and returns stdout/stderr/exit code.
-type ExecFn func(
- ctx context.Context,
- containerID string,
- command []string,
-) (stdout, stderr string, exitCode int, err error)
-
-// DockerTarget implements RuntimeTarget for Docker containers.
-// It automatically deploys the osapi binary into the container
-// on first use via Prepare.
-type DockerTarget struct {
- name string
- image string
- execFn ExecFn
- binaryURL string
- skipPrepare bool
-
- prepareOnce sync.Once
- prepareErr error
-}
-
-// NewDockerTarget creates a new Docker runtime target.
-func NewDockerTarget(
- name string,
- image string,
- execFn ExecFn,
-) *DockerTarget {
- return &DockerTarget{
- name: name,
- image: image,
- execFn: execFn,
- }
-}
-
-// Name returns the container name.
-func (t *DockerTarget) Name() string {
- return t.name
-}
-
-// Runtime returns "docker".
-func (t *DockerTarget) Runtime() string {
- return "docker"
-}
-
-// Image returns the container image.
-func (t *DockerTarget) Image() string {
- return t.image
-}
-
-// SetBinaryURL overrides the GitHub release URL for the osapi binary.
-func (t *DockerTarget) SetBinaryURL(
- url string,
-) {
- t.binaryURL = url
-}
-
-// SetSkipPrepare disables automatic binary deployment.
-func (t *DockerTarget) SetSkipPrepare(
- skip bool,
-) {
- t.skipPrepare = skip
-}
-
-// Prepare ensures the osapi binary is deployed inside the container.
-// It resolves the binary URL (from GitHub releases or a custom URL),
-// downloads it inside the container, and makes it executable.
-// Subsequent calls are no-ops.
-func (t *DockerTarget) Prepare(
- ctx context.Context,
-) error {
- if t.skipPrepare {
- return nil
- }
-
- t.prepareOnce.Do(func() {
- t.prepareErr = t.doPrepare(ctx)
- })
-
- return t.prepareErr
-}
-
-// doPrepare performs the actual binary deployment.
-func (t *DockerTarget) doPrepare(
- ctx context.Context,
-) error {
- url := t.binaryURL
- if url == "" {
- var err error
-
- url, err = resolveLatestBinaryURL(ctx, "linux", runtime.GOARCH)
- if err != nil {
- return fmt.Errorf("resolve osapi binary: %w", err)
- }
- }
-
- script := deployScript(url)
-
- _, stderr, exitCode, err := t.execFn(
- ctx,
- t.name,
- []string{"sh", "-c", script},
- )
- if err != nil {
- return fmt.Errorf("deploy osapi binary: %w", err)
- }
-
- if exitCode != 0 {
- return fmt.Errorf("deploy osapi binary (exit %d): %s", exitCode, stderr)
- }
-
- return nil
-}
-
-// ExecProvider runs a provider operation inside this container via
-// docker exec. On first call it automatically deploys the osapi binary
-// unless WithOSAPIBinarySkip was set.
-func (t *DockerTarget) ExecProvider(
- ctx context.Context,
- provider string,
- operation string,
- data []byte,
-) ([]byte, error) {
- if err := t.Prepare(ctx); err != nil {
- return nil, err
- }
-
- cmd := []string{"/osapi", "provider", "run", provider, operation}
- if len(data) > 0 {
- cmd = append(cmd, "--data", string(data))
- }
-
- stdout, stderr, exitCode, err := t.execFn(ctx, t.name, cmd)
- if err != nil {
- return nil, fmt.Errorf("exec provider in container %s: %w", t.name, err)
- }
-
- if exitCode != 0 {
- return nil, fmt.Errorf(
- "provider %s/%s failed (exit %d): %s",
- provider,
- operation,
- exitCode,
- stderr,
- )
- }
-
- return []byte(stdout), nil
-}
diff --git a/pkg/sdk/orchestrator/docker_target_public_test.go b/pkg/sdk/orchestrator/docker_target_public_test.go
deleted file mode 100644
index c211d14f..00000000
--- a/pkg/sdk/orchestrator/docker_target_public_test.go
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator_test
-
-import (
- "context"
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/suite"
-
- "github.com/retr0h/osapi/pkg/sdk/orchestrator"
-)
-
-// Compile-time interface check.
-var _ orchestrator.RuntimeTarget = (*orchestrator.DockerTarget)(nil)
-
-type DockerTargetPublicTestSuite struct {
- suite.Suite
-}
-
-func TestDockerTargetPublicTestSuite(t *testing.T) {
- suite.Run(t, new(DockerTargetPublicTestSuite))
-}
-
-func (s *DockerTargetPublicTestSuite) TestNewDockerTarget() {
- tests := []struct {
- name string
- targetName string
- image string
- validateFunc func(target *orchestrator.DockerTarget)
- }{
- {
- name: "returns correct name and runtime",
- targetName: "web",
- image: "ubuntu:24.04",
- validateFunc: func(target *orchestrator.DockerTarget) {
- s.Equal("web", target.Name())
- s.Equal("docker", target.Runtime())
- s.Equal("ubuntu:24.04", target.Image())
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- target := orchestrator.NewDockerTarget(
- tt.targetName,
- tt.image,
- func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "", 0, nil
- },
- )
- tt.validateFunc(target)
- })
- }
-}
-
-func (s *DockerTargetPublicTestSuite) TestExecProvider() {
- tests := []struct {
- name string
- provider string
- operation string
- data []byte
- execFn orchestrator.ExecFn
- validateFunc func(result []byte, err error, capturedCmd []string)
- }{
- {
- name: "constructs correct command without data",
- provider: "node.host",
- operation: "get",
- data: nil,
- execFn: func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return `{"hostname":"web-01"}`, "", 0, nil
- },
- validateFunc: func(result []byte, err error, _ []string) {
- s.NoError(err)
- s.Equal(`{"hostname":"web-01"}`, string(result))
- },
- },
- {
- name: "constructs correct command with data",
- provider: "network.dns",
- operation: "set",
- data: []byte(`{"servers":["8.8.8.8"]}`),
- execFn: nil, // set below to capture command
- validateFunc: func(_ []byte, _ error, capturedCmd []string) {
- s.Equal([]string{
- "/osapi", "provider", "run", "network.dns", "set",
- "--data", `{"servers":["8.8.8.8"]}`,
- }, capturedCmd)
- },
- },
- {
- name: "returns error on non-zero exit",
- provider: "node.host",
- operation: "get",
- data: nil,
- execFn: func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "command not found", 1, nil
- },
- validateFunc: func(result []byte, err error, _ []string) {
- s.Error(err)
- s.Nil(result)
- s.Contains(err.Error(), "failed (exit 1)")
- s.Contains(err.Error(), "command not found")
- },
- },
- {
- name: "returns error on exec failure",
- provider: "node.host",
- operation: "get",
- data: nil,
- execFn: func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "", 0, fmt.Errorf("connection refused")
- },
- validateFunc: func(result []byte, err error, _ []string) {
- s.Error(err)
- s.Nil(result)
- s.Contains(err.Error(), "exec provider in container")
- s.Contains(err.Error(), "connection refused")
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- var capturedCmd []string
-
- execFn := tt.execFn
- if execFn == nil {
- execFn = func(
- _ context.Context,
- _ string,
- cmd []string,
- ) (string, string, int, error) {
- capturedCmd = cmd
-
- return `{}`, "", 0, nil
- }
- }
-
- target := orchestrator.NewDockerTarget("web", "ubuntu:24.04", execFn)
- target.SetSkipPrepare(true)
-
- result, err := target.ExecProvider(
- context.Background(),
- tt.provider,
- tt.operation,
- tt.data,
- )
- tt.validateFunc(result, err, capturedCmd)
- })
- }
-}
diff --git a/pkg/sdk/orchestrator/options.go b/pkg/sdk/orchestrator/options.go
index 652d6190..694d9adf 100644
--- a/pkg/sdk/orchestrator/options.go
+++ b/pkg/sdk/orchestrator/options.go
@@ -95,11 +95,8 @@ type Hooks struct {
// PlanConfig holds plan-level configuration.
type PlanConfig struct {
- OnErrorStrategy ErrorStrategy
- Hooks *Hooks
- DockerExecFn ExecFn
- DockerBinaryURL string
- DockerSkipDeploy bool
+ OnErrorStrategy ErrorStrategy
+ Hooks *Hooks
}
// PlanOption is a functional option for NewPlan.
@@ -122,33 +119,3 @@ func WithHooks(
cfg.Hooks = &hooks
}
}
-
-// WithDockerExecFn sets the exec function used by Plan.Docker() to
-// execute commands inside Docker containers.
-func WithDockerExecFn(
- fn ExecFn,
-) PlanOption {
- return func(cfg *PlanConfig) {
- cfg.DockerExecFn = fn
- }
-}
-
-// WithOSAPIBinaryURL overrides the default GitHub release URL for the
-// osapi binary that gets deployed into Docker containers. Use this for
-// custom builds, mirrors, or pre-release binaries.
-func WithOSAPIBinaryURL(
- url string,
-) PlanOption {
- return func(cfg *PlanConfig) {
- cfg.DockerBinaryURL = url
- }
-}
-
-// WithOSAPIBinarySkip disables automatic binary deployment into Docker
-// containers. Use this when the osapi binary is already baked into the
-// container image.
-func WithOSAPIBinarySkip() PlanOption {
- return func(cfg *PlanConfig) {
- cfg.DockerSkipDeploy = true
- }
-}
diff --git a/pkg/sdk/orchestrator/options_public_test.go b/pkg/sdk/orchestrator/options_public_test.go
index e6b01dd0..803428d8 100644
--- a/pkg/sdk/orchestrator/options_public_test.go
+++ b/pkg/sdk/orchestrator/options_public_test.go
@@ -142,43 +142,3 @@ func (s *OptionsPublicTestSuite) TestPlanOption() {
})
}
}
-
-func (s *OptionsPublicTestSuite) TestWithOSAPIBinaryURL() {
- tests := []struct {
- name string
- url string
- }{
- {
- name: "sets binary URL",
- url: "https://example.com/osapi",
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- cfg := &orchestrator.PlanConfig{}
- opt := orchestrator.WithOSAPIBinaryURL(tt.url)
- opt(cfg)
- s.Equal(tt.url, cfg.DockerBinaryURL)
- })
- }
-}
-
-func (s *OptionsPublicTestSuite) TestWithOSAPIBinarySkip() {
- tests := []struct {
- name string
- }{
- {
- name: "sets skip deploy flag",
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- cfg := &orchestrator.PlanConfig{}
- opt := orchestrator.WithOSAPIBinarySkip()
- opt(cfg)
- s.True(cfg.DockerSkipDeploy)
- })
- }
-}
diff --git a/pkg/sdk/orchestrator/plan.go b/pkg/sdk/orchestrator/plan.go
index 3a6d4215..aabcf21d 100644
--- a/pkg/sdk/orchestrator/plan.go
+++ b/pkg/sdk/orchestrator/plan.go
@@ -10,12 +10,9 @@ import (
// Plan is a DAG of tasks with dependency edges.
type Plan struct {
- client *osapiclient.Client
- tasks []*Task
- config PlanConfig
- dockerExecFn ExecFn
- dockerBinaryURL string
- dockerSkipDeploy bool
+ client *osapiclient.Client
+ tasks []*Task
+ config PlanConfig
}
// NewPlan creates a new plan bound to an OSAPI client.
@@ -32,11 +29,8 @@ func NewPlan(
}
return &Plan{
- client: client,
- config: cfg,
- dockerExecFn: cfg.DockerExecFn,
- dockerBinaryURL: cfg.DockerBinaryURL,
- dockerSkipDeploy: cfg.DockerSkipDeploy,
+ client: client,
+ config: cfg,
}
}
diff --git a/pkg/sdk/orchestrator/plan_in.go b/pkg/sdk/orchestrator/plan_in.go
deleted file mode 100644
index d31845c7..00000000
--- a/pkg/sdk/orchestrator/plan_in.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-// ScopedPlan routes provider operations through a RuntimeTarget.
-type ScopedPlan struct {
- plan *Plan
- target RuntimeTarget
-}
-
-// In creates a scoped plan context for the given runtime target.
-func (p *Plan) In(
- target RuntimeTarget,
-) *ScopedPlan {
- return &ScopedPlan{
- plan: p,
- target: target,
- }
-}
-
-// Docker creates a DockerTarget bound to this plan. The target
-// automatically deploys the osapi binary into the container on first
-// provider call. Use WithOSAPIBinaryURL to override the download
-// source, or WithOSAPIBinarySkip if the binary is pre-installed.
-// Panics if no ExecFn was provided via WithDockerExecFn option.
-func (p *Plan) Docker(
- name string,
- image string,
-) *DockerTarget {
- if p.dockerExecFn == nil {
- panic("orchestrator: Plan.Docker() called without WithDockerExecFn option")
- }
-
- t := NewDockerTarget(name, image, p.dockerExecFn)
- t.binaryURL = p.dockerBinaryURL
- t.skipPrepare = p.dockerSkipDeploy
-
- return t
-}
-
-// Target returns the runtime target for this scoped plan.
-func (sp *ScopedPlan) Target() RuntimeTarget {
- return sp.target
-}
-
-// TaskFunc creates a task on the parent plan within the target context.
-func (sp *ScopedPlan) TaskFunc(
- name string,
- fn TaskFn,
-) *Task {
- return sp.plan.TaskFunc(name, fn)
-}
-
-// TaskFuncWithResults creates a task with results within the target context.
-func (sp *ScopedPlan) TaskFuncWithResults(
- name string,
- fn TaskFnWithResults,
-) *Task {
- return sp.plan.TaskFuncWithResults(name, fn)
-}
diff --git a/pkg/sdk/orchestrator/plan_in_public_test.go b/pkg/sdk/orchestrator/plan_in_public_test.go
deleted file mode 100644
index ee943ae0..00000000
--- a/pkg/sdk/orchestrator/plan_in_public_test.go
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator_test
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/suite"
-
- osapiclient "github.com/retr0h/osapi/pkg/sdk/client"
- "github.com/retr0h/osapi/pkg/sdk/orchestrator"
-)
-
-type PlanInPublicTestSuite struct {
- suite.Suite
-}
-
-func TestPlanInPublicTestSuite(t *testing.T) {
- suite.Run(t, new(PlanInPublicTestSuite))
-}
-
-func (s *PlanInPublicTestSuite) TestDocker() {
- tests := []struct {
- name string
- execFn orchestrator.ExecFn
- targetName string
- image string
- validateFunc func(target *orchestrator.DockerTarget)
- }{
- {
- name: "returns target with correct name and image",
- execFn: func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "", 0, nil
- },
- targetName: "web-01",
- image: "ubuntu:24.04",
- validateFunc: func(target *orchestrator.DockerTarget) {
- s.Equal("web-01", target.Name())
- s.Equal("ubuntu:24.04", target.Image())
- s.Equal("docker", target.Runtime())
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- plan := orchestrator.NewPlan(
- nil,
- orchestrator.WithDockerExecFn(tt.execFn),
- )
-
- target := plan.Docker(tt.targetName, tt.image)
- tt.validateFunc(target)
- })
- }
-}
-
-func (s *PlanInPublicTestSuite) TestDockerPanicsWithoutExecFn() {
- plan := orchestrator.NewPlan(nil)
-
- s.Panics(func() {
- plan.Docker("web", "ubuntu:24.04")
- })
-}
-
-func (s *PlanInPublicTestSuite) TestIn() {
- tests := []struct {
- name string
- validateFunc func(sp *orchestrator.ScopedPlan)
- }{
- {
- name: "returns scoped plan with target",
- validateFunc: func(sp *orchestrator.ScopedPlan) {
- s.NotNil(sp)
- s.Equal("web", sp.Target().Name())
- s.Equal("docker", sp.Target().Runtime())
- },
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- execFn := func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "", 0, nil
- }
-
- plan := orchestrator.NewPlan(
- nil,
- orchestrator.WithDockerExecFn(execFn),
- )
- target := plan.Docker("web", "ubuntu:24.04")
- sp := plan.In(target)
-
- tt.validateFunc(sp)
- })
- }
-}
-
-func (s *PlanInPublicTestSuite) TestScopedPlanTaskFunc() {
- execFn := func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "", 0, nil
- }
-
- plan := orchestrator.NewPlan(
- nil,
- orchestrator.WithDockerExecFn(execFn),
- )
- target := plan.Docker("web", "ubuntu:24.04")
- sp := plan.In(target)
-
- task := sp.TaskFunc("install-pkg", func(
- _ context.Context,
- _ *osapiclient.Client,
- ) (*orchestrator.Result, error) {
- return &orchestrator.Result{Changed: true}, nil
- })
-
- s.Equal("install-pkg", task.Name())
- s.Len(plan.Tasks(), 1)
- s.Equal(task, plan.Tasks()[0])
-}
-
-func (s *PlanInPublicTestSuite) TestScopedPlanTaskFuncWithResults() {
- execFn := func(
- _ context.Context,
- _ string,
- _ []string,
- ) (string, string, int, error) {
- return "", "", 0, nil
- }
-
- plan := orchestrator.NewPlan(
- nil,
- orchestrator.WithDockerExecFn(execFn),
- )
- target := plan.Docker("web", "ubuntu:24.04")
- sp := plan.In(target)
-
- task := sp.TaskFuncWithResults("check-status", func(
- _ context.Context,
- _ *osapiclient.Client,
- _ orchestrator.Results,
- ) (*orchestrator.Result, error) {
- return &orchestrator.Result{Changed: false}, nil
- })
-
- s.Equal("check-status", task.Name())
- s.Len(plan.Tasks(), 1)
- s.Equal(task, plan.Tasks()[0])
-}
diff --git a/pkg/sdk/orchestrator/runtime_target.go b/pkg/sdk/orchestrator/runtime_target.go
deleted file mode 100644
index 7a679006..00000000
--- a/pkg/sdk/orchestrator/runtime_target.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2026 John Dewey
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-package orchestrator
-
-import "context"
-
-// RuntimeTarget represents a container runtime target that can execute
-// provider operations. Implementations exist for Docker (now) and
-// LXD/Podman (later).
-type RuntimeTarget interface {
- // Name returns the target name (container name).
- Name() string
- // Runtime returns the runtime type ("docker", "lxd", "podman").
- Runtime() string
- // ExecProvider executes a provider operation inside the target.
- ExecProvider(ctx context.Context, provider, operation string, data []byte) ([]byte, error)
-}
diff --git a/pkg/sdk/platform/platform.go b/pkg/sdk/platform/platform.go
index 84e35689..fdd2f08f 100644
--- a/pkg/sdk/platform/platform.go
+++ b/pkg/sdk/platform/platform.go
@@ -19,8 +19,8 @@
// DEALINGS IN THE SOFTWARE.
// Package platform provides cross-platform detection for OSAPI providers.
-// Both the CLI (provider run) and the agent use this package to select
-// the correct provider variant (ubuntu, darwin, or generic linux).
+// The agent uses this package to select the correct provider variant
+// (ubuntu, darwin, or generic linux).
package platform
import (
diff --git a/test/integration/container_test.go b/test/integration/docker_test.go
similarity index 89%
rename from test/integration/container_test.go
rename to test/integration/docker_test.go
index 67c600be..22ac203e 100644
--- a/test/integration/container_test.go
+++ b/test/integration/docker_test.go
@@ -28,12 +28,12 @@ import (
"github.com/stretchr/testify/suite"
)
-type ContainerSmokeSuite struct {
+type DockerSmokeSuite struct {
suite.Suite
}
-func (s *ContainerSmokeSuite) TestContainerPull() {
- skipWriteOp(s.T(), "CONTAINER_PULL")
+func (s *DockerSmokeSuite) TestDockerPull() {
+ skipWriteOp(s.T(), "DOCKER_PULL")
tests := []struct {
name string
@@ -43,7 +43,7 @@ func (s *ContainerSmokeSuite) TestContainerPull() {
{
name: "pulls alpine image and returns image id",
args: []string{
- "client", "container", "pull",
+ "client", "container", "docker", "pull",
"--image", "alpine:latest",
"--json",
},
@@ -79,12 +79,12 @@ func (s *ContainerSmokeSuite) TestContainerPull() {
}
}
-func (s *ContainerSmokeSuite) TestContainerCreateListInspectStopRemove() {
- skipWriteOp(s.T(), "CONTAINER_LIFECYCLE")
+func (s *DockerSmokeSuite) TestDockerCreateListInspectStopRemove() {
+ skipWriteOp(s.T(), "DOCKER_LIFECYCLE")
// Pull the image first so create does not fail.
pullOut, _, pullCode := runCLI(
- "client", "container", "pull",
+ "client", "container", "docker", "pull",
"--image", "alpine:latest",
"--json",
)
@@ -96,7 +96,7 @@ func (s *ContainerSmokeSuite) TestContainerCreateListInspectStopRemove() {
// Create
createOut, _, createCode := runCLI(
- "client", "container", "create",
+ "client", "container", "docker", "create",
"--image", "alpine:latest",
"--name", "integration-test-container",
"--auto-start=false",
@@ -119,7 +119,7 @@ func (s *ContainerSmokeSuite) TestContainerCreateListInspectStopRemove() {
// List
listOut, _, listCode := runCLI(
- "client", "container", "list",
+ "client", "container", "docker", "list",
"--state", "all",
"--json",
)
@@ -139,7 +139,7 @@ func (s *ContainerSmokeSuite) TestContainerCreateListInspectStopRemove() {
// Inspect
inspectOut, _, inspectCode := runCLI(
- "client", "container", "inspect",
+ "client", "container", "docker", "inspect",
"--id", "integration-test-container",
"--json",
)
@@ -161,7 +161,7 @@ func (s *ContainerSmokeSuite) TestContainerCreateListInspectStopRemove() {
// Remove (force, in case the container is running)
removeOut, _, removeCode := runCLI(
- "client", "container", "remove",
+ "client", "container", "docker", "remove",
"--id", "integration-test-container",
"--force",
"--json",
@@ -182,7 +182,7 @@ func (s *ContainerSmokeSuite) TestContainerCreateListInspectStopRemove() {
s.Contains(firstRemove, "changed")
}
-func (s *ContainerSmokeSuite) TestContainerList() {
+func (s *DockerSmokeSuite) TestDockerList() {
tests := []struct {
name string
args []string
@@ -191,7 +191,7 @@ func (s *ContainerSmokeSuite) TestContainerList() {
{
name: "returns container list with results",
args: []string{
- "client", "container", "list",
+ "client", "container", "docker", "list",
"--state", "all",
"--json",
},
@@ -217,8 +217,8 @@ func (s *ContainerSmokeSuite) TestContainerList() {
}
}
-func TestContainerSmokeSuite(
+func TestDockerSmokeSuite(
t *testing.T,
) {
- suite.Run(t, new(ContainerSmokeSuite))
+ suite.Run(t, new(DockerSmokeSuite))
}