mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-11 22:30:47 +01:00
Moved non-agent-specific logic from agent/pkg/agent/ to internal/agentpool/: - pool.go: Agent pool management (Get, Add, Remove, List, Iter, etc.) - http_requests.go: HTTP utilities (health checks, forwarding, websockets, reverse proxy) - agent.go: Agent struct with HTTP client management This separates general-purpose pool management from agent-specific configuration, improving code organization and making the agent package focused on agent config only.
109 lines
3.3 KiB
Go
109 lines
3.3 KiB
Go
package agentapi
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
_ "embed"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
|
"github.com/yusing/godoxy/internal/agentpool"
|
|
apitypes "github.com/yusing/goutils/apitypes"
|
|
)
|
|
|
|
type NewAgentRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Host string `json:"host" binding:"required"`
|
|
Port int `json:"port" binding:"required,min=1,max=65535"`
|
|
Type string `json:"type" binding:"required,oneof=docker system"`
|
|
Nightly bool `json:"nightly" binding:"omitempty"`
|
|
ContainerRuntime agent.ContainerRuntime `json:"container_runtime" binding:"omitempty,oneof=docker podman" default:"docker"`
|
|
} // @name NewAgentRequest
|
|
|
|
type NewAgentResponse struct {
|
|
Compose string `json:"compose"`
|
|
CA PEMPairResponse `json:"ca"`
|
|
Client PEMPairResponse `json:"client"`
|
|
} // @name NewAgentResponse
|
|
|
|
// @x-id "create"
|
|
// @BasePath /api/v1
|
|
// @Summary Create a new agent
|
|
// @Description Create a new agent and return the docker compose file, encrypted CA and client PEMs
|
|
// @Description The returned PEMs are encrypted with a random key and will be used for verification when adding a new agent
|
|
// @Tags agent
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body NewAgentRequest true "Request"
|
|
// @Success 200 {object} NewAgentResponse
|
|
// @Failure 400 {object} apitypes.ErrorResponse
|
|
// @Failure 403 {object} apitypes.ErrorResponse
|
|
// @Failure 409 {object} apitypes.ErrorResponse
|
|
// @Failure 500 {object} apitypes.ErrorResponse
|
|
// @Router /agent/create [post]
|
|
func Create(c *gin.Context) {
|
|
var request NewAgentRequest
|
|
if err := c.ShouldBindJSON(&request); err != nil {
|
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid request", err))
|
|
return
|
|
}
|
|
|
|
hostport := net.JoinHostPort(request.Host, strconv.Itoa(request.Port))
|
|
if _, ok := agentpool.Get(hostport); ok {
|
|
c.JSON(http.StatusConflict, apitypes.Error("agent already exists"))
|
|
return
|
|
}
|
|
|
|
var image string
|
|
if request.Nightly {
|
|
image = agent.DockerImageNightly
|
|
} else {
|
|
image = agent.DockerImageProduction
|
|
}
|
|
|
|
ca, srv, client, err := agent.NewAgent()
|
|
if err != nil {
|
|
c.Error(apitypes.InternalServerError(err, "failed to create agent"))
|
|
return
|
|
}
|
|
|
|
var cfg agent.Generator = &agent.AgentEnvConfig{
|
|
Name: request.Name,
|
|
Port: request.Port,
|
|
CACert: ca.String(),
|
|
SSLCert: srv.String(),
|
|
ContainerRuntime: request.ContainerRuntime,
|
|
}
|
|
if request.Type == "docker" {
|
|
cfg = &agent.AgentComposeConfig{
|
|
Image: image,
|
|
AgentEnvConfig: cfg.(*agent.AgentEnvConfig),
|
|
}
|
|
}
|
|
template, err := cfg.Generate()
|
|
if err != nil {
|
|
c.Error(apitypes.InternalServerError(err, "failed to generate agent config"))
|
|
return
|
|
}
|
|
|
|
key := getEncryptionKey()
|
|
encCA, err := ca.Encrypt(key)
|
|
if err != nil {
|
|
c.Error(apitypes.InternalServerError(err, "failed to encrypt CA PEMs"))
|
|
return
|
|
}
|
|
encClient, err := client.Encrypt(key)
|
|
if err != nil {
|
|
c.Error(apitypes.InternalServerError(err, "failed to encrypt client PEMs"))
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, NewAgentResponse{
|
|
Compose: template,
|
|
CA: toPEMPairResponse(encCA),
|
|
Client: toPEMPairResponse(encClient),
|
|
})
|
|
}
|