Browse Source

add urbit to docker state map on start

reid 2 years ago
parent
commit
ca49af92b0
7 changed files with 94 additions and 67 deletions
  1. 16 1
      config/config.go
  2. 31 20
      docker/docker.go
  3. 6 5
      docker/urbit.go
  4. 1 1
      main.go
  5. 34 35
      rectify/rectify.go
  6. 5 5
      structs/structs.go
  7. 1 0
      system/system.go

+ 16 - 1
config/config.go

@@ -24,9 +24,10 @@ var (
 	Ready              = false
 	VersionServerReady = false
 	VersionInfo        structs.Version
-	GSContainers = make(map[string]structs.ContainerState)
+	GSContainers       = make(map[string]structs.ContainerState)
 	checkInterval      = 5 * time.Minute
 	confMutex          sync.Mutex
+	contMutex          sync.Mutex
 	versMutex          sync.Mutex
 )
 
@@ -115,6 +116,20 @@ func UpdateConf(values map[string]interface{}) error {
 	return nil
 }
 
+// modify the desired/actual state of containers
+func UpdateContainerState(name string, containerState structs.ContainerState) {
+	contMutex.Lock()
+	defer contMutex.Unlock()
+	GSContainers[name] = state
+}
+
+// get the current container state
+func GetContainerState() structs.SysConfig {
+	contMutex.Lock()
+	defer contMutex.Unlock()
+	return GSContainers
+}
+
 // write a default conf to disk
 func createDefaultConf() error {
 	defaultConfig := structs.SysConfig{

+ 31 - 20
docker/docker.go

@@ -12,13 +12,12 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/client"
 	"github.com/docker/docker/api/types/container"
-
+	"github.com/docker/docker/client"
 )
 
 var (
-	logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
+	logger   = slog.New(slog.NewJSONHandler(os.Stdout, nil))
 	EventBus = make(chan structs.Event, 100)
 )
 
@@ -111,21 +110,22 @@ func GetContainerStats(containerName string) (structs.ContainerStats, error) {
 
 // start a container by name + tag
 // not for booting new ships
-func StartContainer(containerName string, containerType string) error {
+func StartContainer(containerName string, containerType string) (structs.ContainerState, error) {
+	var containerState ContainerState
 	ctx := context.Background()
 	cli, err := client.NewClientWithOpts(client.FromEnv)
 	if err != nil {
-		return err
+		return containerState, err
 	}
 	// get the desired tag and hash from config
-	containerInfo, err := getLatestContainerInfo(containerType)
+	containerInfo, err := GetLatestContainerInfo(containerType)
 	if err != nil {
-		return err
+		return containerState, err
 	}
 	// check if container exists
 	containers, err := cli.ContainerList(ctx, types.ContainerListOptions{All: true})
 	if err != nil {
-		return err
+		return containerState, err
 	}
 	var existingContainer *types.Container = nil
 	for _, container := range containers {
@@ -144,12 +144,12 @@ func StartContainer(containerName string, containerType string) error {
 	desiredRepo := containerInfo["repo"]
 	if desiredTag == "" || desiredHash == "" {
 		err = fmt.Errorf("Version info has not been retrieved!")
-		return err
+		return containerState, err
 	}
 	// check if the desired image is available locally
 	images, err := cli.ImageList(ctx, types.ImageListOptions{})
 	if err != nil {
-		return err
+		return containerState, err
 	}
 	imageExistsLocally := false
 	for _, img := range images {
@@ -167,7 +167,7 @@ func StartContainer(containerName string, containerType string) error {
 		// pull the image if it doesn't exist locally
 		_, err = cli.ImagePull(ctx, desiredRepo+":"+desiredTag, types.ImagePullOptions{})
 		if err != nil {
-			return err
+			return containerState, err
 		}
 	}
 	switch {
@@ -177,11 +177,11 @@ func StartContainer(containerName string, containerType string) error {
 			Image: containerType + ":" + desiredTag,
 		}, nil, nil, nil, containerName)
 		if err != nil {
-			return err
+			return containerState, err
 		}
 		err = cli.ContainerStart(ctx, containerName, types.ContainerStartOptions{})
 		if err != nil {
-			return err
+			return containerState, err
 		}
 		msg := fmt.Sprintf("%s started with image %s:%s", containerName, containerType, desiredTag)
 		logger.Info(msg)
@@ -189,7 +189,7 @@ func StartContainer(containerName string, containerType string) error {
 		// if the container exists but is stopped, start it
 		err := cli.ContainerStart(ctx, containerName, types.ContainerStartOptions{})
 		if err != nil {
-			return err
+			return containerState, err
 		}
 		msg := fmt.Sprintf("Started stopped container %s", containerName)
 		logger.Info(msg)
@@ -201,17 +201,17 @@ func StartContainer(containerName string, containerType string) error {
 			// if the tags don't match, recreate the container with the new tag
 			err := cli.ContainerRemove(ctx, containerName, types.ContainerRemoveOptions{Force: true})
 			if err != nil {
-				return err
+				return containerState, err
 			}
 			_, err = cli.ContainerCreate(ctx, &container.Config{
 				Image: containerType + ":" + desiredTag,
 			}, nil, nil, nil, containerName)
 			if err != nil {
-				return err
+				return containerState, err
 			}
 			err = cli.ContainerStart(ctx, containerName, types.ContainerStartOptions{})
 			if err != nil {
-				return err
+				return containerState, err
 			}
 			msg := fmt.Sprintf("Restarted %s with image %s:%s", containerName, containerType, desiredTag)
 			logger.Info(msg)
@@ -220,12 +220,23 @@ func StartContainer(containerName string, containerType string) error {
 			logger.Info(msg)
 		}
 	}
-	return nil
+	containerDetails, err := cli.ContainerInspect(ctx, containerName)
+	if err != nil {
+		return containerState, fmt.Errorf("failed to inspect container %s: %v", containerName, err)
+	}
+	containerState = ContainerState{
+		ID:        containerDetails.ID,
+		Name:      containerName,
+		Image:     fmt.Sprintf("%s:%s@sha256:%s", containerDetails.Config.Image, desiredTag, desiredHash),
+		Status:    containerDetails.State.Status,
+		CreatedAt: containerDetails.Created,
+	}
+	return containerState, err
 }
 
 // convert the version info back into json then a map lol
 // so we can easily get the correct repo/release channel/tag/hash
-func getLatestContainerInfo(containerType string) (map[string]string, error) {
+func GetLatestContainerInfo(containerType string) (map[string]string, error) {
 	var res map[string]string
 	conf := config.Conf()
 	releaseChannel := conf.UpdateBranch
@@ -331,4 +342,4 @@ func DockerPoller() {
 			return
 		}
 	}
-}
+}

+ 6 - 5
docker/urbit.go

@@ -11,7 +11,7 @@ import (
 )
 
 var (
-	urbitsConfig = make(map[string]structs.UrbitDocker)
+	UrbitsConfig = make(map[string]structs.UrbitDocker)
 	urbitMutex   sync.RWMutex
 )
 
@@ -20,12 +20,13 @@ func LoadUrbits() error {
 	// Loop through pier list
 	conf := config.Conf()
 	for _, pier := range conf.Piers {
-		logger.Info(fmt.Sprintf("Loading pier %s",pier))
-		err := StartContainer(pier, "vere")
+		logger.Info(fmt.Sprintf("Loading pier %s", pier))
+		info, err := StartContainer(pier, "vere")
 		if err != nil {
 			logger.Error(fmt.Sprintf("%v", err))
 			continue
 		}
+		config.UpdateContainerState(pier, info)
 	}
 	return nil
 }
@@ -33,7 +34,7 @@ func LoadUrbits() error {
 func Conf(pier string) structs.UrbitDocker {
 	urbitMutex.Lock()
 	defer urbitMutex.Unlock()
-	return urbitsConfig[pier]
+	return UrbitsConfig[pier]
 }
 
 func LoadConfig(pier string) error {
@@ -53,6 +54,6 @@ func LoadConfig(pier string) error {
 		return fmt.Errorf(errmsg)
 	}
 	// Store in var
-	urbitsConfig[pier] = targetStruct
+	UrbitsConfig[pier] = targetStruct
 	return nil
 }

+ 1 - 1
main.go

@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"goseg/config"
 	"goseg/docker"
-	"goseg/ws"
 	"goseg/rectify"
+	"goseg/ws"
 	"log/slog"
 	"net/http"
 	"os"

+ 34 - 35
rectify/rectify.go

@@ -1,4 +1,5 @@
 package rectify
+
 // this package is for watching the event bus and rectifying mismatches
 // between the desired and actual state
 
@@ -6,7 +7,6 @@ import (
 	"fmt"
 	"goseg/broadcast"
 	"goseg/config"
-	"goseg/docker"
 	"log/slog"
 	"os"
 
@@ -18,37 +18,36 @@ var (
 )
 
 func DockerSubscriptionHandler() {
-    for {
-        event := <-docker.EventBus
-        dockerEvent, ok := event.Data.(events.Message)  // assert the type
-        if !ok {
-            logger.Error("Failed to assert Docker event data type")
-            continue
-        }
-        switch dockerEvent.Action {
-        case "stop":
-            contID := dockerEvent.Actor.ID
-            contName := dockerEvent.Actor.Attributes["name"]
-            logger.Info(fmt.Sprintf("Docker: %s stopped", contName))
-            
-            if containerState, exists := config.GSContainers[contID]; exists {
-                containerState.Status = "stopped"
-                config.GSContainers[contID] = containerState
-            }
-
-        case "start":
-            contID := dockerEvent.Actor.ID
-            contName := dockerEvent.Actor.Attributes["name"]
-            logger.Info(fmt.Sprintf("Docker: %s started", contName))
-            
-            if containerState, exists := config.GSContainers[contID]; exists {
-                containerState.Status = "started"
-                config.GSContainers[contID] = containerState
-            }
-
-        default:
-            logger.Info(fmt.Sprintf("Docker event: %s", dockerEvent.Action))
-        }
-        broadcast.BroadcastToClients()
-    }
-}
+	for {
+		event := <-docker.EventBus
+		dockerEvent, ok := event.Data.(events.Message) // assert the type
+		if !ok {
+			logger.Error("Failed to assert Docker event data type")
+			continue
+		}
+		contID := dockerEvent.Actor.ID
+		contName := dockerEvent.Actor.Attributes["name"]
+		switch dockerEvent.Action {
+
+		case "stop":
+			logger.Info(fmt.Sprintf("Docker: %s stopped", contName))
+
+			if containerState, exists := config.GSContainers[contID]; exists {
+				containerState.Status = "stopped"
+				config.GSContainers[contID] = containerState
+			}
+
+		case "start":
+			logger.Info(fmt.Sprintf("Docker: %s started", contName))
+
+			if containerState, exists := config.GSContainers[contID]; exists {
+				containerState.Status = "started"
+				config.GSContainers[contID] = containerState
+			}
+
+		default:
+			logger.Info(fmt.Sprintf("Docker event: %s", dockerEvent.Action))
+		}
+		broadcast.BroadcastToClients()
+	}
+}

+ 5 - 5
structs/structs.go

@@ -18,11 +18,11 @@ type Event struct {
 
 // for keeping track of container desired/actual state
 type ContainerState struct {
-    ID        string
-    Name      string
-    Image     string
-    Status    string
-    CreatedAt time.Time
+	ID        string
+	Name      string
+	Image     string
+	Status    string
+	CreatedAt time.Time
 }
 
 // authenticated browser sessions

+ 1 - 0
system/system.go

@@ -1,4 +1,5 @@
 package system
+
 // for retrieving hw info and managing host
 
 import (