added commands

This commit is contained in:
ACoolName 2024-05-15 00:07:10 +03:00
parent 16b6850635
commit 343e16a4db
3 changed files with 98 additions and 10 deletions

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.22.0
require github.com/gin-gonic/gin v1.9.1
require (
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/docker/docker v26.1.2+incompatible // indirect

2
go.sum
View File

@ -1,3 +1,5 @@
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10 h1:XwHQ5xDtYPdtBbVPyRO6UZoWZe8/mbKUb076f8x7RvI=
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10/go.mod h1:gv0DYOzHEsKgo31lTCDGauIg4DTTGn41Bzp+t3wSOlk=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=

View File

@ -4,12 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"strings"
"time"
"acooldomain.co/backend/auth"
"acooldomain.co/backend/models"
"github.com/buildkite/shellwords"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
@ -181,16 +183,27 @@ func (con Connection) CreateServer(ctx *gin.Context) {
ctx.JSON(200, volumeResponse.Name)
}
type PortMappingRequest struct {
Source models.Port
Destination models.Port
}
type StartServerRequest struct {
Command string `json:"command"`
Ports []PortMappingRequest `json:"ports"`
}
func (con Connection) StartServer(ctx *gin.Context) {
serverId := ctx.Param("server_id")
claims, exists := ctx.Get("claims")
var request StartServerRequest
json.NewDecoder(ctx.Request.Body).Decode(&request)
if !exists {
ctx.AbortWithStatus(403)
return
}
// command := ctx.Param("command")
serverInfo, err := con.getServerInfoFromId(serverId)
if err != nil {
@ -227,14 +240,29 @@ func (con Connection) StartServer(ctx *gin.Context) {
}
var portMapping nat.PortMap = make(nat.PortMap)
for _, port := range serverInfo.Image.Ports {
dockerPort, err := nat.NewPort(port.Protocol, fmt.Sprint(port.Number))
if err != nil {
ctx.AbortWithError(500, err)
return
if len(request.Ports) == 0 {
for _, port := range serverInfo.Image.Ports {
dockerPort, err := nat.NewPort(port.Protocol, fmt.Sprint(port.Number))
if err != nil {
ctx.AbortWithError(500, err)
return
}
portMapping[dockerPort] = []nat.PortBinding{{HostIP: "0.0.0.0"}}
}
portMapping[dockerPort] = []nat.PortBinding{{HostIP: "0.0.0.0"}}
} else {
for _, portCouple := range request.Ports {
portMapping[nat.Port(fmt.Sprintf("%d/%s", portCouple.Source.Number, portCouple.Source.Protocol))] = []nat.PortBinding{{HostPort: fmt.Sprint(portCouple.Destination.Number)}}
}
}
words, err := shellwords.Split(request.Command)
if err != nil {
ctx.AbortWithError(500, err)
return
}
if len(words) == 0 {
words = nil
}
response, err := con.apiClient.ContainerCreate(
@ -244,11 +272,12 @@ func (con Connection) StartServer(ctx *gin.Context) {
AttachStdout: true,
AttachStderr: true,
Tty: true,
OpenStdin: false,
OpenStdin: true,
StdinOnce: false,
Image: imageId,
Volumes: volumes,
Labels: jsonLabels,
Cmd: words,
},
&container.HostConfig{
AutoRemove: true,
@ -345,6 +374,60 @@ func (con Connection) StopServer(ctx *gin.Context) {
ctx.Status(200)
}
func (con Connection) DeleteServer(ctx *gin.Context) {
serverId := ctx.Param("server_id")
containers, err := con.apiClient.ContainerList(context.Background(), container.ListOptions{All: true, Filters: filters.NewArgs(filters.Arg("label", "volume_id="+serverId))})
if err != nil {
ctx.AbortWithError(500, err)
return
}
for _, containerInstance := range containers {
con.apiClient.ContainerStop(context.Background(), containerInstance.ID, container.StopOptions{})
err := con.apiClient.ContainerRemove(context.Background(), containerInstance.ID, container.RemoveOptions{Force: true, RemoveLinks: true})
if err != nil {
ctx.AbortWithError(500, err)
return
}
}
con.apiClient.VolumeRemove(context.Background(), serverId, false)
ctx.JSON(200, "ok")
}
type RunCommandRequest struct {
Command string `json:"command"`
}
func (con Connection) RunCommand(ctx *gin.Context) {
var request RunCommandRequest
err := json.NewDecoder(ctx.Request.Body).Decode(&request)
serverId := ctx.Param("server_id")
log.Print("Writing command \"", request.Command, "\"")
containers, err := con.apiClient.ContainerList(context.Background(), container.ListOptions{Filters: filters.NewArgs(filters.Arg("label", "volume_id="+serverId))})
if err != nil {
ctx.AbortWithError(500, err)
return
}
for _, containerData := range containers {
hijacked, err := con.apiClient.ContainerAttach(context.Background(), containerData.ID, container.AttachOptions{Stream: true, Stdin: true})
defer func() { hijacked.Close(); hijacked.CloseWrite() }()
if err != nil {
ctx.AbortWithError(500, err)
return
}
number, err := hijacked.Conn.Write([]byte(request.Command + "\n"))
log.Print("Wrote ", number, " bytes")
if err != nil {
ctx.AbortWithError(500, err)
return
}
}
ctx.JSON(200, "OK")
}
func (con Connection) serverAuthorized(permissions models.Permission) func(*gin.Context) bool {
return func(ctx *gin.Context) bool {
claims, exists := ctx.Get("claims")
@ -387,4 +470,6 @@ func LoadGroup(group *gin.RouterGroup, mongo_client *mongo.Client) {
group.POST("/", auth.AuthorizedTo(models.Create), connection.CreateServer)
group.GET("/", auth.AuthorizedTo(0), connection.GetServers)
group.POST("/:server_id/stop", auth.AuthorizedTo(models.Stop, connection.serverAuthorized(models.Stop)), connection.StopServer)
group.POST("/:server_id/delete", auth.AuthorizedTo(models.Delete, connection.serverAuthorized(models.Delete)), connection.DeleteServer)
group.POST("/:server_id/run_command", auth.AuthorizedTo(models.RunCommand, connection.serverAuthorized(models.RunCommand)), connection.RunCommand)
}