116 lines
2.9 KiB
Go
116 lines
2.9 KiB
Go
package console_new
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/network"
|
|
"github.com/docker/docker/client"
|
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
)
|
|
|
|
type Container struct {
|
|
client *client.Client
|
|
id string
|
|
}
|
|
|
|
func (c Container) Start(ctx context.Context) error {
|
|
return c.client.ContainerStart(ctx, c.id, container.StartOptions{})
|
|
}
|
|
|
|
func (c Container) Close(ctx context.Context) error {
|
|
timeout := 10
|
|
if err := c.client.ContainerStop(ctx, c.id, container.StopOptions{
|
|
Timeout: &timeout,
|
|
}); err != nil {
|
|
// If stop fails, force kill
|
|
if err := c.client.ContainerKill(ctx, c.id, "SIGKILL"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Remove container and volumes
|
|
removeOptions := container.RemoveOptions{
|
|
RemoveVolumes: true,
|
|
Force: true,
|
|
}
|
|
|
|
return c.client.ContainerRemove(ctx, c.id, removeOptions)
|
|
}
|
|
|
|
func (c Container) execUserCmd(ctx context.Context, user string, cmd string) (string, error) {
|
|
slog.Info("executing command", "user", user, "cmd", cmd)
|
|
var cmdStr = []string{"/bin/bash", "-c"}
|
|
|
|
cmdStr = append(cmdStr, cmd)
|
|
|
|
slog.Info("executing command", "user", user, "cmd", fmt.Sprintf("%#v", cmdStr))
|
|
exec, err := c.client.ContainerExecCreate(ctx, c.id, container.ExecOptions{
|
|
Cmd: cmdStr,
|
|
User: user,
|
|
AttachStdout: true,
|
|
AttachStderr: true,
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
resp, err := c.client.ContainerExecAttach(ctx, exec.ID, container.ExecAttachOptions{})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Close()
|
|
|
|
output, err := io.ReadAll(resp.Reader)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Wait for command to finish and get exit code
|
|
inspectResp, err := c.client.ContainerExecInspect(ctx, exec.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
slog.Info("command finished", "output", string(output), "err", err, "resp", inspectResp)
|
|
|
|
if inspectResp.ExitCode != 0 {
|
|
return string(output), fmt.Errorf("command exited with code %d", inspectResp.ExitCode)
|
|
}
|
|
|
|
return string(output), nil
|
|
}
|
|
func (c Container) Execute(ctx context.Context, cmd string) (string, error) {
|
|
return c.execUserCmd(ctx, "", cmd)
|
|
}
|
|
|
|
func (c Container) ExecuteAs(ctx context.Context, user string, cmd string) (string, error) {
|
|
return c.execUserCmd(ctx, user, cmd)
|
|
}
|
|
|
|
func (c Container) Sudo(ctx context.Context, cmd string) (string, error) {
|
|
return c.execUserCmd(ctx, "root", cmd)
|
|
}
|
|
|
|
type ContainerConfig struct {
|
|
Config *container.Config
|
|
HostConfig *container.HostConfig
|
|
NetConfig *network.NetworkingConfig
|
|
Platform *v1.Platform
|
|
Name string
|
|
}
|
|
|
|
func CreateContainer(ctx context.Context, cl *client.Client, cfg ContainerConfig) (*Container, error) {
|
|
resp, err := cl.ContainerCreate(ctx, cfg.Config, cfg.HostConfig, cfg.NetConfig, cfg.Platform, cfg.Name)
|
|
|
|
slog.Info("creating container", "resp", resp, "err", err)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Container{client: cl, id: resp.ID}, nil
|
|
}
|