aac139368f
Moves all packages from internal/ to pkg/ so they can be imported by external modules (needed for claude-pm integration). - internal/app/ → pkg/app/ - internal/docker/ → pkg/docker/ - internal/config/ → pkg/config/ - internal/utils/ → pkg/utils/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
113 lines
2.9 KiB
Go
113 lines
2.9 KiB
Go
package docker
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/client"
|
|
)
|
|
|
|
type Client struct {
|
|
cli *client.Client
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
func New(host ...string) (*Client, error) {
|
|
opts := []client.Opt{client.FromEnv, client.WithAPIVersionNegotiation()}
|
|
if len(host) > 0 && host[0] != "" {
|
|
opts = append(opts, client.WithHost(host[0]))
|
|
}
|
|
cli, err := client.NewClientWithOpts(opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
return &Client{cli: cli, ctx: ctx, cancel: cancel}, nil
|
|
}
|
|
|
|
// Cancel cancels all in-flight Docker API calls.
|
|
func (c *Client) Cancel() {
|
|
c.cancel()
|
|
}
|
|
|
|
func (c *Client) Ping() error {
|
|
_, err := c.cli.Ping(c.ctx)
|
|
return err
|
|
}
|
|
|
|
func (c *Client) ListContainers(all bool) ([]types.Container, error) {
|
|
opts := container.ListOptions{All: all}
|
|
return c.cli.ContainerList(c.ctx, opts)
|
|
}
|
|
|
|
func (c *Client) InspectContainer(id string) (types.ContainerJSON, error) {
|
|
return c.cli.ContainerInspect(c.ctx, id)
|
|
}
|
|
|
|
func (c *Client) StartContainer(id string) error {
|
|
return c.cli.ContainerStart(c.ctx, id, container.StartOptions{})
|
|
}
|
|
|
|
func (c *Client) StopContainer(id string) error {
|
|
return c.cli.ContainerStop(c.ctx, id, container.StopOptions{})
|
|
}
|
|
|
|
func (c *Client) RestartContainer(id string) error {
|
|
return c.cli.ContainerRestart(c.ctx, id, container.StopOptions{})
|
|
}
|
|
|
|
func (c *Client) DeleteContainer(id string, force bool) error {
|
|
return c.cli.ContainerRemove(c.ctx, id, container.RemoveOptions{Force: force})
|
|
}
|
|
|
|
func (c *Client) PauseContainer(id string) error {
|
|
return c.cli.ContainerPause(c.ctx, id)
|
|
}
|
|
|
|
func (c *Client) UnpauseContainer(id string) error {
|
|
return c.cli.ContainerUnpause(c.ctx, id)
|
|
}
|
|
|
|
func (c *Client) Logs(id string, options container.LogsOptions) (io.ReadCloser, error) {
|
|
return c.cli.ContainerLogs(c.ctx, id, options)
|
|
}
|
|
|
|
// ContainerStats gets a single stats snapshot for a container.
|
|
// Uses stream=false (NOT one-shot) so Docker fills in precpu_stats for accurate CPU delta.
|
|
func (c *Client) ContainerStats(id string) (*container.StatsResponse, error) {
|
|
resp, err := c.cli.ContainerStats(c.ctx, id, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var stats container.StatsResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
|
|
return nil, err
|
|
}
|
|
return &stats, nil
|
|
}
|
|
|
|
func (c *Client) ContainerExec(id string, cmd []string, tty bool) (types.HijackedResponse, error) {
|
|
execConfig := container.ExecOptions{
|
|
Cmd: cmd,
|
|
Tty: tty,
|
|
AttachStdin: true,
|
|
AttachStdout: true,
|
|
AttachStderr: true,
|
|
}
|
|
exec, err := c.cli.ContainerExecCreate(c.ctx, id, execConfig)
|
|
if err != nil {
|
|
return types.HijackedResponse{}, err
|
|
}
|
|
return c.cli.ContainerExecAttach(c.ctx, exec.ID, container.ExecStartOptions{})
|
|
}
|
|
|
|
func (c *Client) Close() error {
|
|
return c.cli.Close()
|
|
}
|