99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"github.com/moby/moby/api/types/container"
|
|
"github.com/moby/moby/client"
|
|
)
|
|
|
|
// ContainerLister is the subset of the Docker client used by the API.
|
|
type ContainerLister interface {
|
|
ContainerList(ctx context.Context, options client.ContainerListOptions) (client.ContainerListResult, error)
|
|
}
|
|
|
|
type API struct {
|
|
localEngine ContainerLister
|
|
logger *slog.Logger
|
|
}
|
|
|
|
func NewHandler(localEngine ContainerLister, logger *slog.Logger) http.Handler {
|
|
api := &API{localEngine: localEngine, logger: logger}
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("GET /api/v1/engines/{engineID}/containers", api.listContainers)
|
|
return mux
|
|
}
|
|
|
|
func (a *API) listContainers(w http.ResponseWriter, r *http.Request) {
|
|
if r.PathValue("engineID") != "1" {
|
|
writeError(w, http.StatusNotFound, "engine_not_found", "engine not found")
|
|
return
|
|
}
|
|
|
|
result, err := a.localEngine.ContainerList(r.Context(), client.ContainerListOptions{All: true})
|
|
if err != nil {
|
|
a.logger.Error("list Docker containers", "engine_id", 1, "error", err)
|
|
writeError(w, http.StatusBadGateway, "docker_unavailable", "could not list containers from the Docker Engine")
|
|
return
|
|
}
|
|
|
|
items := make([]containerResponse, 0, len(result.Items))
|
|
for _, item := range result.Items {
|
|
items = append(items, newContainerResponse(item))
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, listContainersResponse{Containers: items})
|
|
}
|
|
|
|
type listContainersResponse struct {
|
|
Containers []containerResponse `json:"containers"`
|
|
}
|
|
|
|
type containerResponse struct {
|
|
ID string `json:"id"`
|
|
Names []string `json:"names"`
|
|
Image string `json:"image"`
|
|
ImageID string `json:"imageId"`
|
|
Command string `json:"command"`
|
|
Created int64 `json:"created"`
|
|
State string `json:"state"`
|
|
Status string `json:"status"`
|
|
Labels map[string]string `json:"labels"`
|
|
}
|
|
|
|
func newContainerResponse(item container.Summary) containerResponse {
|
|
return containerResponse{
|
|
ID: item.ID,
|
|
Names: item.Names,
|
|
Image: item.Image,
|
|
ImageID: item.ImageID,
|
|
Command: item.Command,
|
|
Created: item.Created,
|
|
State: string(item.State),
|
|
Status: item.Status,
|
|
Labels: item.Labels,
|
|
}
|
|
}
|
|
|
|
type errorResponse struct {
|
|
Error apiError `json:"error"`
|
|
}
|
|
|
|
type apiError struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
func writeError(w http.ResponseWriter, status int, code, message string) {
|
|
writeJSON(w, status, errorResponse{Error: apiError{Code: code, Message: message}})
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, status int, value any) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
_ = json.NewEncoder(w).Encode(value)
|
|
}
|