// Package docker define la abstracción HostConnector: la interfaz que el // resto del backend usa para hablar con "un host Docker", sin importarle si // es el socket local (LocalConnector, fase 1) o un agente remoto // (AgentConnector, cuando se añada un segundo host más adelante). package docker import ( "context" "fmt" "io" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" ) // Container es la representación simplificada que expone la API HTTP, // desacoplada del tipo interno del SDK de Docker. type Container struct { ID string `json:"id"` Names []string `json:"names"` Image string `json:"image"` State string `json:"state"` Status string `json:"status"` Created int64 `json:"created"` } // HostConnector es el contrato que debe cumplir cualquier forma de hablar con // un host Docker (local o remoto vía agente). type HostConnector interface { ListContainers(ctx context.Context) ([]Container, error) Close() error } // LocalConnector implementa HostConnector hablando directamente con el // socket Docker del host donde corre el backend. type LocalConnector struct { cli *client.Client } // NewLocalConnector crea un conector contra el Docker Engine local. // Si dockerHost está vacío, usa la configuración por defecto del SDK // (respeta la variable de entorno DOCKER_HOST si está definida). func NewLocalConnector(dockerHost string) (*LocalConnector, error) { opts := []client.Opt{client.FromEnv, client.WithAPIVersionNegotiation()} if dockerHost != "" { opts = append(opts, client.WithHost(dockerHost)) } cli, err := client.NewClientWithOpts(opts...) if err != nil { return nil, fmt.Errorf("creating docker client: %w", err) } return &LocalConnector{cli: cli}, nil } // ListContainers devuelve todos los contenedores del host, incluidos los // detenidos (equivalente a `docker ps -a`). func (l *LocalConnector) ListContainers(ctx context.Context) ([]Container, error) { list, err := l.cli.ContainerList(ctx, container.ListOptions{All: true}) if err != nil { return nil, fmt.Errorf("listing containers: %w", err) } out := make([]Container, 0, len(list)) for _, c := range list { out = append(out, Container{ ID: c.ID, Names: c.Names, Image: c.Image, State: c.State, Status: c.Status, Created: c.Created, }) } return out, nil } // Close libera los recursos del cliente Docker subyacente. func (l *LocalConnector) Close() error { return l.cli.Close() } var _ io.Closer = (*LocalConnector)(nil)