refactored
This commit is contained in:
3
instancemanager/docker/go.mod
Normal file
3
instancemanager/docker/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module git.acooldomain.co/server-manager/backend/instancemanager/docker
|
||||
|
||||
go 1.22.0
|
584
instancemanager/docker/instance_manager.go
Normal file
584
instancemanager/docker/instance_manager.go
Normal file
@@ -0,0 +1,584 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
instancemanager "git.acooldomain.co/server-manager/backend/instancemanager"
|
||||
"git.acooldomain.co/server-manager/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/image"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/volume"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
type InstanceManager struct {
|
||||
instancemanager.InstanceManager
|
||||
client client.Client
|
||||
config models.DockerInstanceManagerConfig
|
||||
}
|
||||
|
||||
func (self *InstanceManager) containerList(ctx context.Context, labels ContainerLabels, all bool) ([]types.Container, error) {
|
||||
filters, err := convertLabelsToFilter(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
containers, err := self.client.ContainerList(ctx, container.ListOptions{Filters: *filters, All: all})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) getVolume(ctx context.Context, serverId string) (*volume.Volume, error) {
|
||||
volume, err := self.client.VolumeInspect(ctx, serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels, err := convertVolumeLabelsToStruct(volume.Labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if labels.Type != Game {
|
||||
return nil, fmt.Errorf("Server not found")
|
||||
}
|
||||
|
||||
return &volume, err
|
||||
}
|
||||
|
||||
// General
|
||||
// Read Only
|
||||
func (self *InstanceManager) GetImage(ctx context.Context, imageId string) (*instancemanager.Image, error) {
|
||||
imageInspect, _, err := self.client.ImageInspectWithRaw(ctx, imageId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if imageInspect.Config.Labels["type"] != "game" {
|
||||
return nil, fmt.Errorf("Image not found")
|
||||
}
|
||||
|
||||
image := convertImageInspectToInstanceImage(imageInspect)
|
||||
|
||||
return &image, nil
|
||||
|
||||
}
|
||||
|
||||
func (self *InstanceManager) ListImages(ctx context.Context) ([]instancemanager.Image, error) {
|
||||
imageFilters, err := convertLabelsToFilter(ImageLabels{Type: Game})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawImages, err := self.client.ImageList(ctx, image.ListOptions{
|
||||
Filters: *imageFilters,
|
||||
})
|
||||
|
||||
images := make([]instancemanager.Image, len(rawImages))
|
||||
|
||||
for i, rawImage := range rawImages {
|
||||
imageInspect, _, err := self.client.ImageInspectWithRaw(ctx, rawImage.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
images[i] = convertImageInspectToInstanceImage(imageInspect)
|
||||
}
|
||||
|
||||
return images, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) GetServer(ctx context.Context, serverId string) (*instancemanager.Server, error) {
|
||||
volume, err := self.getVolume(ctx, serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serverContainers, err := self.containerList(
|
||||
ctx,
|
||||
ContainerLabels{
|
||||
VolumeId: serverId,
|
||||
},
|
||||
true,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(serverContainers) == 0 {
|
||||
return &instancemanager.Server{
|
||||
Id: volume.Name,
|
||||
Running: false,
|
||||
RunningCommand: "",
|
||||
RunningImage: nil,
|
||||
Ports: nil,
|
||||
Domain: self.config.GamesDomain,
|
||||
}, nil
|
||||
}
|
||||
|
||||
serverContainer := serverContainers[0]
|
||||
|
||||
running := serverContainer.State == "running"
|
||||
|
||||
runningCommand := serverContainer.Command
|
||||
image := convertImageStringToModelsImage(serverContainer.Image)
|
||||
|
||||
return &instancemanager.Server{
|
||||
Id: volume.Name,
|
||||
Running: running,
|
||||
RunningCommand: runningCommand,
|
||||
Ports: convertContainerPortsToPorts(serverContainer.Ports),
|
||||
RunningImage: &image,
|
||||
Domain: self.config.GamesDomain,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) ListServers(ctx context.Context) ([]instancemanager.Server, error) {
|
||||
volumeFilter, err := convertLabelsToFilter(VolumeLabels{Type: Game})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
volumes, err := self.client.VolumeList(ctx, volume.ListOptions{Filters: *volumeFilter})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverStatus := make(map[string]*instancemanager.Server)
|
||||
|
||||
for _, volume := range volumes.Volumes {
|
||||
serverStatus[volume.Name] = &instancemanager.Server{
|
||||
Id: volume.Name,
|
||||
Running: false,
|
||||
RunningCommand: "",
|
||||
Ports: nil,
|
||||
RunningImage: nil,
|
||||
Domain: self.config.GamesDomain,
|
||||
}
|
||||
}
|
||||
|
||||
containers, err := self.containerList(ctx, ContainerLabels{Type: Game}, false)
|
||||
|
||||
for _, container := range containers {
|
||||
rawLabels, err := json.Marshal(container.Labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var containerLabels ContainerLabels
|
||||
err = json.Unmarshal(rawLabels, &containerLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if container.State != "running" {
|
||||
continue
|
||||
}
|
||||
|
||||
image := convertImageStringToModelsImage(container.Image)
|
||||
|
||||
serverStatus[containerLabels.VolumeId].Ports = convertContainerPortsToPorts(container.Ports)
|
||||
serverStatus[containerLabels.VolumeId].Running = true
|
||||
serverStatus[containerLabels.VolumeId].RunningImage = &image
|
||||
serverStatus[containerLabels.VolumeId].RunningCommand = container.Command
|
||||
}
|
||||
|
||||
servers := make([]instancemanager.Server, len(serverStatus))
|
||||
|
||||
i := 0
|
||||
for _, value := range serverStatus {
|
||||
servers[i] = *value
|
||||
i++
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// State Changing
|
||||
func (self *InstanceManager) StartServer(ctx context.Context,
|
||||
serverId string,
|
||||
imageId string,
|
||||
command string,
|
||||
ports []models.Port,
|
||||
) error {
|
||||
server, err := self.GetServer(ctx, serverId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if server.Running {
|
||||
return fmt.Errorf("Server %s already running", serverId)
|
||||
}
|
||||
|
||||
containerLabels := ContainerLabels{
|
||||
VolumeId: server.Id,
|
||||
Type: "GAME",
|
||||
}
|
||||
|
||||
volumes := make(map[string]struct{})
|
||||
|
||||
var portMapping nat.PortMap = make(nat.PortMap)
|
||||
image, err := self.GetImage(ctx, imageId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(ports) == 0 {
|
||||
for _, port := range image.Ports {
|
||||
dockerPort, err := nat.NewPort(string(port.Protocol), fmt.Sprint(port.Number))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
portMapping[dockerPort] = []nat.PortBinding{{HostIP: "0.0.0.0"}}
|
||||
}
|
||||
} else {
|
||||
for _, portCouple := range ports {
|
||||
portMapping[nat.Port(fmt.Sprintf("%d/%s", portCouple.ContainerPort, portCouple.Protocol))] = []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: fmt.Sprint(portCouple.PublicPort)}}
|
||||
}
|
||||
}
|
||||
|
||||
if command == "" {
|
||||
command = image.Command
|
||||
}
|
||||
|
||||
words, err := shellwords.Split(command)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(words) == 0 {
|
||||
words = nil
|
||||
}
|
||||
|
||||
portSet := make(nat.PortSet)
|
||||
for port := range portMapping {
|
||||
portSet[port] = struct{}{}
|
||||
}
|
||||
|
||||
labels, err := convertLabelsToMap(containerLabels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createdContainer, err := self.client.ContainerCreate(
|
||||
context.TODO(),
|
||||
&container.Config{
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Tty: true,
|
||||
OpenStdin: true,
|
||||
StdinOnce: false,
|
||||
Image: imageId,
|
||||
Volumes: volumes,
|
||||
Labels: *labels,
|
||||
Cmd: words,
|
||||
ExposedPorts: portSet,
|
||||
},
|
||||
&container.HostConfig{
|
||||
AutoRemove: true,
|
||||
Mounts: []mount.Mount{{Source: server.Id, Target: image.WorkingDir, Type: "volume"}},
|
||||
PortBindings: portMapping,
|
||||
ConsoleSize: [2]uint{1000, 1000},
|
||||
},
|
||||
&network.NetworkingConfig{},
|
||||
&v1.Platform{},
|
||||
"",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = self.client.ContainerStart(ctx, createdContainer.ID, container.StartOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (self *InstanceManager) StopServer(ctx context.Context, serverId string) error {
|
||||
runningContainers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
|
||||
|
||||
for _, rawContainer := range runningContainers {
|
||||
err = self.client.ContainerStop(ctx, rawContainer.ID, container.StopOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) CreateServer(ctx context.Context) (*instancemanager.Server, error) {
|
||||
labels, err := convertLabelsToMap(VolumeLabels{
|
||||
Type: Game,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
volume, err := self.client.VolumeCreate(ctx, volume.CreateOptions{
|
||||
Labels: *labels,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &instancemanager.Server{
|
||||
Id: volume.Name,
|
||||
Running: false,
|
||||
RunningImage: nil,
|
||||
RunningCommand: "",
|
||||
Domain: self.config.GamesDomain,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) DeleteServer(ctx context.Context, serverId string) error {
|
||||
server, err := self.GetServer(ctx, serverId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if server.Running {
|
||||
err = self.StopServer(ctx, server.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = self.StopFileBrowser(ctx, server.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = self.client.VolumeRemove(ctx, server.Id, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Terminal
|
||||
// Status Changing
|
||||
func (self *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error) {
|
||||
server, err := self.GetServer(ctx, serverId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !server.Running {
|
||||
return nil, fmt.Errorf("Server %s not running", server.Id)
|
||||
}
|
||||
|
||||
rawContainers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rawContainers) == 0 {
|
||||
return nil, fmt.Errorf("Server %s not running and wasn't caught", server.Id)
|
||||
}
|
||||
|
||||
rawContainer := rawContainers[0]
|
||||
|
||||
attach, err := self.client.ContainerAttach(ctx,
|
||||
rawContainer.ID,
|
||||
container.AttachOptions{Stream: true,
|
||||
Stdin: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Logs: true,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &attach.Conn, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) ResizeTerminal(ctx context.Context, serverId string, width uint, height uint) error {
|
||||
containers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: Game}, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(containers) == 0 {
|
||||
return fmt.Errorf("Server %s not running", serverId)
|
||||
}
|
||||
|
||||
err = self.client.ContainerResize(context.TODO(), containers[0].ID, container.ResizeOptions{Height: height, Width: width})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// File Browser
|
||||
|
||||
// Read Only
|
||||
func (self *InstanceManager) GetFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
|
||||
containers, err := self.containerList(ctx, ContainerLabels{VolumeId: serverId, Type: FileBrowser}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(containers) == 0 {
|
||||
return nil, fmt.Errorf("File Browser for server %s is not running", serverId)
|
||||
}
|
||||
|
||||
rawContainer := containers[0]
|
||||
|
||||
containerLabels, err := convertContainerLabelsToStruct(rawContainer.Labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.FileBrowser{
|
||||
Url: containerLabels.VolumeId[:12] + "." + self.config.BrowsersDomain,
|
||||
Id: rawContainer.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.FileBrowser, error) {
|
||||
containers, err := self.containerList(ctx, ContainerLabels{Type: FileBrowser}, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileBrowsers := make([]models.FileBrowser, len(containers))
|
||||
|
||||
for i, rawContainer := range containers {
|
||||
containerLabels, err := convertContainerLabelsToStruct(rawContainer.Labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileBrowsers[i] = models.FileBrowser{
|
||||
Url: containerLabels.VolumeId[:12] + "." + self.config.BrowsersDomain,
|
||||
Id: rawContainer.ID,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return fileBrowsers, nil
|
||||
}
|
||||
|
||||
// Status Changing
|
||||
func (self *InstanceManager) StartFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
|
||||
server, err := self.GetServer(ctx, serverId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labelId := serverId[:12]
|
||||
|
||||
browserLabels := make(map[string]string)
|
||||
browserLabels["traefik.enable"] = "true"
|
||||
browserLabels[fmt.Sprintf("traefik.http.routers.%s.rule", labelId)] = fmt.Sprintf("Host(`%s.browsers.%s`)", labelId, self.config.BrowsersDomain)
|
||||
browserLabels[fmt.Sprintf("traefik.http.routers.%s.entrypoints", labelId)] = "websecure"
|
||||
browserLabels[fmt.Sprintf("traefik.http.routers.%s.middlewares", labelId)] = "games@docker"
|
||||
browserLabels[fmt.Sprintf("traefik.http.routers.%s.tls.domains[0].main", labelId)] = fmt.Sprintf("%s.%s", "browsers", self.config.BrowsersDomain)
|
||||
browserLabels[fmt.Sprintf("traefik.http.routers.%s.tls.domains[0].sans", labelId)] = fmt.Sprintf("*.%s.%s", "browsers", self.config.BrowsersDomain)
|
||||
browserLabels[fmt.Sprintf("traefik.http.routers.%s.tls.certresolver", labelId)] = "myresolver"
|
||||
|
||||
containerConfig, err := convertLabelsToMap(ContainerLabels{VolumeId: serverId, Type: FileBrowser})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for key, value := range *containerConfig {
|
||||
browserLabels[key] = value
|
||||
}
|
||||
|
||||
command := self.config.FileBrowser.Command
|
||||
|
||||
if command == "" {
|
||||
command = "--noauth -r /tmp/data"
|
||||
}
|
||||
|
||||
splitCommand, err := shellwords.Split(command)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ContainerResponse, err := self.client.ContainerCreate(
|
||||
context.TODO(),
|
||||
&container.Config{
|
||||
Cmd: splitCommand,
|
||||
Image: fmt.Sprintf("%s:%s", self.config.FileBrowser.Image.Registry, self.config.FileBrowser.Image.Tag),
|
||||
Labels: browserLabels,
|
||||
Tty: true,
|
||||
},
|
||||
&container.HostConfig{
|
||||
Mounts: []mount.Mount{{Source: server.Id, Target: "/tmp/data", Type: "volume"}},
|
||||
AutoRemove: true,
|
||||
ConsoleSize: [2]uint{1000, 1000},
|
||||
},
|
||||
&network.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*network.EndpointSettings{"browsers": {
|
||||
NetworkID: self.config.FileBrowser.Network,
|
||||
}},
|
||||
},
|
||||
&v1.Platform{},
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = self.client.ContainerStart(context.TODO(), ContainerResponse.ID, container.StartOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.FileBrowser{
|
||||
Url: serverId[:12] + "." + self.config.BrowsersDomain,
|
||||
Id: ContainerResponse.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *InstanceManager) StopFileBrowser(ctx context.Context, serverId string) error {
|
||||
containers, err := self.containerList(ctx, ContainerLabels{Type: FileBrowser}, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rawContainer := range containers {
|
||||
err := self.client.ContainerStop(ctx, rawContainer.ID, container.StopOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewInstanceManager(config models.DockerInstanceManagerConfig) (*InstanceManager, error) {
|
||||
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer apiClient.Close()
|
||||
|
||||
return &InstanceManager{
|
||||
config: config,
|
||||
client: *apiClient,
|
||||
}, nil
|
||||
}
|
27
instancemanager/docker/labels.go
Normal file
27
instancemanager/docker/labels.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package docker
|
||||
|
||||
type ContainerType string
|
||||
|
||||
const (
|
||||
Game ContainerType = "GAME"
|
||||
FileBrowser = "FILE_BROWSER"
|
||||
)
|
||||
|
||||
type ContainerLabels struct {
|
||||
VolumeId string `json:"volume_id,omitempty"`
|
||||
Type ContainerType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type BrowserLabels struct {
|
||||
ContainerLabels
|
||||
UrlRule string
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
type VolumeLabels struct {
|
||||
Type ContainerType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type ImageLabels struct {
|
||||
Type ContainerType `json:"type,omitempty"`
|
||||
}
|
179
instancemanager/docker/utils.go
Normal file
179
instancemanager/docker/utils.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
instancemanager "git.acooldomain.co/server-manager/backend/instancemanager"
|
||||
"git.acooldomain.co/server-manager/backend/models"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
func convertLabelsToFilter(labels any) (*filters.Args, error) {
|
||||
args := filters.NewArgs()
|
||||
|
||||
labelMap, err := convertLabelsToMap(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for key, value := range *labelMap {
|
||||
args.Add("label", fmt.Sprintf("%s=%s", key, value))
|
||||
}
|
||||
|
||||
return &args, nil
|
||||
}
|
||||
|
||||
func convertLabelsToMap(labels any) (*map[string]string, error) {
|
||||
raw, err := json.Marshal(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rawMap map[string]any
|
||||
|
||||
err = json.Unmarshal(raw, &rawMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stringifiedMap := stringifyMap(rawMap)
|
||||
|
||||
return &stringifiedMap, nil
|
||||
}
|
||||
|
||||
func stringifyMap(m map[string]any) map[string]string {
|
||||
stringifiedMap := make(map[string]string)
|
||||
for key, value := range m {
|
||||
stringifiedMap[key] = fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
return stringifiedMap
|
||||
}
|
||||
|
||||
func convertContainerPortsToPorts(ports []types.Port) []models.Port {
|
||||
containerPorts := make([]models.Port, len(ports))
|
||||
logger := log.Default()
|
||||
for i, port := range ports {
|
||||
var portProtocol models.PortProtocol
|
||||
switch port.Type {
|
||||
case "TCP":
|
||||
portProtocol = models.TCP
|
||||
case "UDP":
|
||||
portProtocol = models.UDP
|
||||
default:
|
||||
logger.Println(fmt.Sprintf("Unkown Port Protocol %s assuming TCP", port.Type))
|
||||
portProtocol = models.TCP
|
||||
}
|
||||
|
||||
containerPorts[i] = models.Port{
|
||||
PublicPort: port.PublicPort,
|
||||
ContainerPort: port.PrivatePort,
|
||||
Protocol: portProtocol,
|
||||
}
|
||||
}
|
||||
|
||||
return containerPorts
|
||||
}
|
||||
|
||||
func convertImageStringToModelsImage(image string) models.Image {
|
||||
imageSegments := strings.Split(image, ":")
|
||||
imageRegistry := imageSegments[0]
|
||||
imageTag := imageSegments[1]
|
||||
|
||||
return models.Image{
|
||||
Registry: imageRegistry,
|
||||
Tag: imageTag,
|
||||
}
|
||||
}
|
||||
|
||||
func convertImageInspectToInstanceImage(image types.ImageInspect) instancemanager.Image {
|
||||
modelsImage := convertImageStringToModelsImage(image.RepoTags[0])
|
||||
|
||||
ports := convertImagePortsToPorts(image.Config.ExposedPorts)
|
||||
|
||||
return instancemanager.Image{
|
||||
Registry: modelsImage.Registry,
|
||||
Tag: modelsImage.Tag,
|
||||
Command: strings.Join(image.Config.Cmd, " "),
|
||||
Ports: ports,
|
||||
WorkingDir: image.Config.WorkingDir,
|
||||
}
|
||||
}
|
||||
|
||||
func convertContainerLabelsToStruct(labels map[string]string) (*ContainerLabels, error) {
|
||||
var containerLabels ContainerLabels
|
||||
|
||||
rawLabels, err := json.Marshal(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawLabels, &labels)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &containerLabels, nil
|
||||
}
|
||||
|
||||
func convertVolumeLabelsToStruct(labels map[string]string) (*VolumeLabels, error) {
|
||||
var volumeLabels VolumeLabels
|
||||
|
||||
rawLabels, err := json.Marshal(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawLabels, &labels)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &volumeLabels, nil
|
||||
}
|
||||
|
||||
func convertImageLabelsToStruct(labels map[string]string) (*ImageLabels, error) {
|
||||
var imageLabels ImageLabels
|
||||
|
||||
rawLabels, err := json.Marshal(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawLabels, &labels)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &imageLabels, nil
|
||||
}
|
||||
|
||||
func convertImagePortsToPorts(rawPorts nat.PortSet) []instancemanager.Port {
|
||||
ports := make([]instancemanager.Port, len(rawPorts))
|
||||
i := 0
|
||||
for imagePort := range rawPorts {
|
||||
portNumber := imagePort.Int()
|
||||
var protocol models.PortProtocol
|
||||
switch imagePort.Proto() {
|
||||
case "TCP":
|
||||
protocol = models.TCP
|
||||
case "UDP":
|
||||
protocol = models.UDP
|
||||
default:
|
||||
log.Default().Println(fmt.Sprintf("Unknown port protocol %s using TCP", imagePort.Proto()))
|
||||
protocol = models.TCP
|
||||
}
|
||||
ports[i] = instancemanager.Port{
|
||||
Number: uint16(portNumber),
|
||||
Protocol: protocol,
|
||||
}
|
||||
i++
|
||||
}
|
||||
return ports
|
||||
}
|
Reference in New Issue
Block a user