chore: git cache cleanup
This commit is contained in:
92
backend/internal/api/handlers/docker_handler.go
Normal file
92
backend/internal/api/handlers/docker_handler.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Wikid82/charon/backend/internal/api/middleware"
|
||||
"github.com/Wikid82/charon/backend/internal/models"
|
||||
"github.com/Wikid82/charon/backend/internal/services"
|
||||
"github.com/Wikid82/charon/backend/internal/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type dockerContainerLister interface {
|
||||
ListContainers(ctx context.Context, host string) ([]services.DockerContainer, error)
|
||||
}
|
||||
|
||||
type remoteServerGetter interface {
|
||||
GetByUUID(uuidStr string) (*models.RemoteServer, error)
|
||||
}
|
||||
|
||||
type DockerHandler struct {
|
||||
dockerService dockerContainerLister
|
||||
remoteServerService remoteServerGetter
|
||||
}
|
||||
|
||||
func NewDockerHandler(dockerService dockerContainerLister, remoteServerService remoteServerGetter) *DockerHandler {
|
||||
return &DockerHandler{
|
||||
dockerService: dockerService,
|
||||
remoteServerService: remoteServerService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DockerHandler) RegisterRoutes(r *gin.RouterGroup) {
|
||||
r.GET("/docker/containers", h.ListContainers)
|
||||
}
|
||||
|
||||
func (h *DockerHandler) ListContainers(c *gin.Context) {
|
||||
log := middleware.GetRequestLogger(c)
|
||||
|
||||
host := strings.TrimSpace(c.Query("host"))
|
||||
serverID := strings.TrimSpace(c.Query("server_id"))
|
||||
|
||||
// SSRF hardening: do not accept arbitrary host values from the client.
|
||||
// Only allow explicit local selection ("local") or empty (default local).
|
||||
if host != "" && host != "local" {
|
||||
log.WithFields(map[string]any{"host": util.SanitizeForLog(host)}).Warn("rejected docker host query param")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid docker host selector"})
|
||||
return
|
||||
}
|
||||
|
||||
// If server_id is provided, look up the remote server
|
||||
if serverID != "" {
|
||||
server, err := h.remoteServerService.GetByUUID(serverID)
|
||||
if err != nil {
|
||||
log.WithFields(map[string]any{"server_id": util.SanitizeForLog(serverID)}).Warn("remote server not found")
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Remote server not found"})
|
||||
return
|
||||
}
|
||||
|
||||
// Construct Docker host string
|
||||
// Assuming TCP for now as that's what RemoteServer supports (Host/Port)
|
||||
// TODO: Support SSH if/when RemoteServer supports it
|
||||
host = fmt.Sprintf("tcp://%s:%d", server.Host, server.Port)
|
||||
}
|
||||
|
||||
containers, err := h.dockerService.ListContainers(c.Request.Context(), host)
|
||||
if err != nil {
|
||||
var unavailableErr *services.DockerUnavailableError
|
||||
if errors.As(err, &unavailableErr) {
|
||||
details := unavailableErr.Details()
|
||||
if details == "" {
|
||||
details = "Cannot connect to Docker. Please ensure Docker is running and the socket is accessible (e.g., /var/run/docker.sock is mounted)."
|
||||
}
|
||||
log.WithFields(map[string]any{"server_id": util.SanitizeForLog(serverID), "host": util.SanitizeForLog(host), "error": util.SanitizeForLog(err.Error())}).Warn("docker unavailable")
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{
|
||||
"error": "Docker daemon unavailable",
|
||||
"details": details,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(map[string]any{"server_id": util.SanitizeForLog(serverID), "host": util.SanitizeForLog(host), "error": util.SanitizeForLog(err.Error())}).Error("failed to list containers")
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list containers"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, containers)
|
||||
}
|
||||
Reference in New Issue
Block a user