diff --git a/internal/room/containers.go b/internal/room/containers.go index abe627a..9ff0da5 100644 --- a/internal/room/containers.go +++ b/internal/room/containers.go @@ -13,34 +13,17 @@ import ( ) func (manager *RoomManagerCtx) containerToEntry(container dockerTypes.Container) (*types.RoomEntry, error) { - roomName, ok := container.Labels["m1k1o.neko_rooms.name"] - if !ok { - return nil, fmt.Errorf("damaged container labels: name not found") - } - - nekoImage, ok := container.Labels["m1k1o.neko_rooms.neko_image"] - if !ok { - // Backward compatibility. - nekoImage = container.Image - //return nil, fmt.Errorf("Damaged container labels: neko_image not found.") - } - - URL, ok := container.Labels["m1k1o.neko_rooms.url"] - if !ok { - return nil, fmt.Errorf("damaged container labels: url not found") - } - - epr, err := manager.getEprFromLabels(container.Labels) + labels, err := manager.extractLabels(container.Labels) if err != nil { return nil, err } return &types.RoomEntry{ ID: container.ID, - URL: URL, - Name: roomName, - NekoImage: nekoImage, - MaxConnections: epr.Max - epr.Min + 1, + URL: labels.URL, + Name: labels.Name, + NekoImage: labels.NekoImage, + MaxConnections: labels.Epr.Max - labels.Epr.Min + 1, Running: container.State == "running", Status: container.Status, Created: time.Unix(container.Created, 0), diff --git a/internal/room/labels.go b/internal/room/labels.go new file mode 100644 index 0000000..7065413 --- /dev/null +++ b/internal/room/labels.go @@ -0,0 +1,71 @@ +package room + +import ( + "fmt" + "strconv" +) + +type RoomLabels struct { + Name string + URL string + Epr EprPorts + NekoImage string +} + +func (manager *RoomManagerCtx) extractLabels(labels map[string]string) (*RoomLabels, error) { + name, ok := labels["m1k1o.neko_rooms.name"] + if !ok { + return nil, fmt.Errorf("damaged container labels: name not found") + } + + url, ok := labels["m1k1o.neko_rooms.url"] + if !ok { + return nil, fmt.Errorf("damaged container labels: url not found") + } + + nekoImage, ok := labels["m1k1o.neko_rooms.neko_image"] + if !ok { + return nil, fmt.Errorf("damaged container labels: neko_image not found") + } + + eprMinStr, ok := labels["m1k1o.neko_rooms.epr.min"] + if !ok { + return nil, fmt.Errorf("damaged container labels: epr.min not found") + } + + eprMin, err := strconv.ParseUint(eprMinStr, 10, 16) + if err != nil { + return nil, err + } + + eprMaxStr, ok := labels["m1k1o.neko_rooms.epr.max"] + if !ok { + return nil, fmt.Errorf("damaged container labels: epr.max not found") + } + + eprMax, err := strconv.ParseUint(eprMaxStr, 10, 16) + if err != nil { + return nil, err + } + + return &RoomLabels{ + Name: name, + URL: url, + NekoImage: nekoImage, + Epr: EprPorts{ + Min: uint16(eprMin), + Max: uint16(eprMax), + }, + }, nil +} + +func (manager *RoomManagerCtx) serializeLabels(labels RoomLabels) map[string]string { + return map[string]string{ + "m1k1o.neko_rooms.name": labels.Name, + "m1k1o.neko_rooms.url": labels.URL, + "m1k1o.neko_rooms.instance": manager.config.InstanceName, + "m1k1o.neko_rooms.epr.min": fmt.Sprintf("%d", labels.Epr.Min), + "m1k1o.neko_rooms.epr.max": fmt.Sprintf("%d", labels.Epr.Max), + "m1k1o.neko_rooms.neko_image": labels.NekoImage, + } +} diff --git a/internal/room/manager.go b/internal/room/manager.go index 930c418..c013a0f 100644 --- a/internal/room/manager.go +++ b/internal/room/manager.go @@ -115,6 +115,10 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro } } + // + // Allocate ports + // + epr, err := manager.allocatePorts(settings.MaxConnections) if err != nil { return "", err @@ -138,8 +142,33 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro exposedPorts[portKey] = struct{}{} } + // + // Set traefik labels + // + containerName := manager.config.InstanceName + "-" + roomName + traefikLabels := map[string]string{ + "traefik.enable": "true", + "traefik.http.services." + containerName + "-frontend.loadbalancer.server.port": fmt.Sprintf("%d", frontendPort), + "traefik.http.routers." + containerName + ".entrypoints": manager.config.TraefikEntrypoint, + "traefik.http.routers." + containerName + ".rule": "Host(`" + manager.config.TraefikDomain + "`) && PathPrefix(`/" + roomName + "`)", + "traefik.http.middlewares." + containerName + "-rdr.redirectregex.regex": "/" + roomName + "$$", + "traefik.http.middlewares." + containerName + "-rdr.redirectregex.replacement": "/" + roomName + "/", + "traefik.http.middlewares." + containerName + "-prf.stripprefix.prefixes": "/" + roomName + "/", + "traefik.http.routers." + containerName + ".middlewares": containerName + "-rdr," + containerName + "-prf", + } + + // optional HTTPS + if manager.config.TraefikCertresolver != "" { + traefikLabels["traefik.http.routers."+containerName+".tls"] = "true" + traefikLabels["traefik.http.routers."+containerName+".tls.certresolver"] = manager.config.TraefikCertresolver + } + + // + // Set internal labels + // + instanceUrl := manager.config.InstanceUrl if instanceUrl == "" { urlProto := "http" @@ -158,31 +187,20 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro instanceUrl = instanceUrl + "/" } - labels := map[string]string{ - // Set internal labels - "m1k1o.neko_rooms.name": roomName, - "m1k1o.neko_rooms.url": instanceUrl + roomName + "/", - "m1k1o.neko_rooms.instance": manager.config.InstanceName, - "m1k1o.neko_rooms.epr.min": fmt.Sprintf("%d", epr.Min), - "m1k1o.neko_rooms.epr.max": fmt.Sprintf("%d", epr.Max), - "m1k1o.neko_rooms.neko_image": settings.NekoImage, + labels := manager.serializeLabels(RoomLabels{ + Name: roomName, + URL: instanceUrl + roomName + "/", + Epr: epr, + NekoImage: settings.NekoImage, + }) - // Set traefik labels - "traefik.enable": "true", - "traefik.http.services." + containerName + "-frontend.loadbalancer.server.port": fmt.Sprintf("%d", frontendPort), - "traefik.http.routers." + containerName + ".entrypoints": manager.config.TraefikEntrypoint, - "traefik.http.routers." + containerName + ".rule": "Host(`" + manager.config.TraefikDomain + "`) && PathPrefix(`/" + roomName + "`)", - "traefik.http.middlewares." + containerName + "-rdr.redirectregex.regex": "/" + roomName + "$$", - "traefik.http.middlewares." + containerName + "-rdr.redirectregex.replacement": "/" + roomName + "/", - "traefik.http.middlewares." + containerName + "-prf.stripprefix.prefixes": "/" + roomName + "/", - "traefik.http.routers." + containerName + ".middlewares": containerName + "-rdr," + containerName + "-prf", + for k, v := range traefikLabels { + labels[k] = v } - // optional HTTPS - if manager.config.TraefikCertresolver != "" { - labels["traefik.http.routers."+containerName+".tls"] = "true" - labels["traefik.http.routers."+containerName+".tls.certresolver"] = manager.config.TraefikCertresolver - } + // + // Set environment variables + // env := []string{ fmt.Sprintf("NEKO_BIND=:%d", frontendPort), @@ -245,6 +263,10 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro } } + // + // Set container mounts + // + paths := map[string]bool{} mounts := []dockerMount.Mount{} for _, mount := range settings.Mounts { @@ -319,6 +341,10 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro paths[mount.ContainerPath] = true } + // + // Set container configs + // + config := &container.Config{ // Hostname Hostname: containerName, @@ -417,22 +443,12 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro return nil, err } - roomName, ok := container.Config.Labels["m1k1o.neko_rooms.name"] - if !ok { - return nil, fmt.Errorf("damaged container labels: name not found") - } - - nekoImage, ok := container.Config.Labels["m1k1o.neko_rooms.neko_image"] - if !ok { - return nil, fmt.Errorf("damaged container labels: neko_image not found") - } - - epr, err := manager.getEprFromLabels(container.Config.Labels) + labels, err := manager.extractLabels(container.Config.Labels) if err != nil { return nil, err } - privateStorageRoot := path.Join(manager.config.StorageExternal, privateStoragePath, roomName) + privateStorageRoot := path.Join(manager.config.StorageExternal, privateStoragePath, labels.Name) templateStorageRoot := path.Join(manager.config.StorageExternal, templateStoragePath) mounts := []types.RoomMount{} @@ -456,7 +472,7 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro } var policiesData *types.Policies - policyConfig := policies.GetConfig(nekoImage) + policyConfig := policies.GetConfig(labels.NekoImage) if policyConfig != nil { var policyMount *types.RoomMount for _, mount := range mounts { @@ -480,9 +496,9 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro } settings := types.RoomSettings{ - Name: roomName, - NekoImage: nekoImage, - MaxConnections: epr.Max - epr.Min + 1, + Name: labels.Name, + NekoImage: labels.NekoImage, + MaxConnections: labels.Epr.Max - labels.Epr.Min + 1, Mounts: mounts, Policies: policiesData, } diff --git a/internal/room/ports.go b/internal/room/ports.go index c3cec07..dd3e5b4 100644 --- a/internal/room/ports.go +++ b/internal/room/ports.go @@ -3,7 +3,6 @@ package room import ( "fmt" "sort" - "strconv" ) type EprPorts struct { @@ -51,12 +50,12 @@ func (manager *RoomManagerCtx) getUsedPorts() ([]EprPorts, error) { result := []EprPorts{} for _, container := range containers { - epr, err := manager.getEprFromLabels(container.Labels) + labels, err := manager.extractLabels(container.Labels) if err != nil { return nil, err } - result = append(result, epr) + result = append(result, labels.Epr) } sort.SliceStable(result, func(i, j int) bool { @@ -65,32 +64,3 @@ func (manager *RoomManagerCtx) getUsedPorts() ([]EprPorts, error) { return result, nil } - -func (manager *RoomManagerCtx) getEprFromLabels(labels map[string]string) (EprPorts, error) { - var err error - epr := EprPorts{} - - eprMinStr, ok := labels["m1k1o.neko_rooms.epr.min"] - if !ok { - return epr, fmt.Errorf("damaged container labels: epr.min not found") - } - - eprMin, err := strconv.ParseUint(eprMinStr, 10, 16) - if err != nil { - return epr, err - } - - eprMaxStr, ok := labels["m1k1o.neko_rooms.epr.max"] - if !ok { - return epr, fmt.Errorf("damaged container labels: epr.max not found") - } - - eprMax, err := strconv.ParseUint(eprMaxStr, 10, 16) - if err != nil { - return epr, err - } - - epr.Min = uint16(eprMin) - epr.Max = uint16(eprMax) - return epr, nil -}