Procházet zdrojové kódy

add urbit container startup

reid před 2 roky
rodič
revize
ea9623ac85
6 změnil soubory, kde provedl 163 přidání a 15 odebrání
  1. 9 9
      broadcast/broadcast.go
  2. 12 0
      config/config.go
  3. 126 0
      docker/docker.go
  4. 5 0
      docker/urbit.go
  5. 3 3
      structs/structs.go
  6. 8 3
      system/system.go

+ 9 - 9
broadcast/broadcast.go

@@ -187,20 +187,20 @@ func constructSystemInfo() map[string]interface{} {
 	var ramObj []uint64
 	var diskObj []uint64
 	usedRam, totalRam := system.GetMemory()
-	ramObj = append(ramObj,usedRam,totalRam)
+	ramObj = append(ramObj, usedRam, totalRam)
 	cpuUsage := system.GetCPU()
 	cpuTemp := system.GetTemp()
 	usedDisk, freeDisk := system.GetDisk()
-	diskObj = append(diskObj,usedDisk,freeDisk)
+	diskObj = append(diskObj, usedDisk, freeDisk)
 	swapVal := system.HasSwap()
 	res = map[string]interface{}{
-		"System":map[string]interface{}{
-			"Usage":map[string]interface{}{
-				"RAM":ramObj,
-				"CPU":cpuUsage,
-				"CPUTemp":cpuTemp,
-				"Disk":diskObj,
-				"SwapFile":swapVal,
+		"System": map[string]interface{}{
+			"Usage": map[string]interface{}{
+				"RAM":      ramObj,
+				"CPU":      cpuUsage,
+				"CPUTemp":  cpuTemp,
+				"Disk":     diskObj,
+				"SwapFile": swapVal,
 			},
 		},
 	}

+ 12 - 0
config/config.go

@@ -19,6 +19,7 @@ var (
 	logger             = slog.New(slog.NewJSONHandler(os.Stdout, nil))
 	BasePath           = "/opt/nativeplanet/groundseg"
 	Version            = "v2.0.0"
+	Architecture       string
 	Ready              = false
 	VersionServerReady = false
 	VersionInfo        structs.Version
@@ -57,6 +58,7 @@ func init() {
 		errmsg := fmt.Sprintf("Error decoding JSON: %v", err)
 		logger.Error(errmsg)
 	}
+	Architecture = getArchitecture()
 }
 
 // return the global conf var
@@ -66,6 +68,16 @@ func Conf() structs.SysConfig {
 	return globalConfig
 }
 
+// tell if we're amd64 or arm64
+func getArchitecture() string {
+	switch runtime.GOARCH {
+	case "arm64", "aarch64":
+		return "arm64"
+	default:
+		return "amd64"
+	}
+}
+
 // update by passing in a map of key:values you want to modify
 func UpdateConf(values map[string]interface{}) error {
 	// mutex lock to avoid race conditions

+ 126 - 0
docker/docker.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
+	"goseg/config"
 	"goseg/structs"
 	"log/slog"
 	"os"
@@ -102,3 +103,128 @@ func GetContainerStats(containerName string) (structs.ContainerStats, error) {
 		DiskUsage:   diskUsage,
 	}, nil
 }
+
+// start a container by name + tag
+// not for booting new ships
+func StartContainer(containerName, containerType string) error {
+	ctx := context.Background()
+	cli, err := client.NewClientWithOpts(client.FromEnv)
+	if err != nil {
+		return err
+	}
+	// Placeholder: Get the desired tag and hash from your config
+	containerInfo, err := getCurrentContainerInfo()
+	if err != nil {
+		errMsg := fmt.Errorf("Couldn't get %s container info: %v", containerName, err)
+		logger.Error(errMsg)
+		return err
+	}
+	desiredTag := containerInfo["tag"]
+	desiredHash := containerInfo["hash"]
+	desiredRepo := containerInfo["repo"]
+	if desiredTag == "" || desiredHash == "" {
+		err = fmt.Errorf("Version info has not been retrieved!")
+		logger.Error(err)
+		return err
+	}
+	// Check if the desired image is available locally
+	images, err := cli.ImageList(ctx, types.ImageListOptions{})
+	if err != nil {
+		return err
+	}
+	imageExistsLocally := false
+	for _, img := range images {
+		for _, tag := range img.RepoTags {
+			if tag == containerType+":"+desiredTag && img.ID == desiredHash {
+				imageExistsLocally = true
+				break
+			}
+		}
+		if imageExistsLocally {
+			break
+		}
+	}
+	if !imageExistsLocally {
+		// pull the image if it doesn't exist locally
+		_, err = cli.ImagePull(ctx, desiredRepo+":"+desiredTag, types.ImagePullOptions{})
+		if err != nil {
+			return err
+		}
+	}
+	switch {
+	case existingContainer == nil:
+		// if the container does not exist, create and start it
+		_, err := cli.ContainerCreate(ctx, &container.Config{
+			Image: containerType + ":" + containerTag,
+		}, nil, nil, nil, containerName)
+		if err != nil {
+			return err
+		}
+		err = cli.ContainerStart(ctx, containerName, types.ContainerStartOptions{})
+		if err != nil {
+			return err
+		}
+		msg := fmt.Sprintf("%s started with image %s:%s", containerName, containerType, containerTag)
+		logger.Info(msg)
+	case existingContainer.State == "exited":
+		// if the container exists but is stopped, start it
+		err := cli.ContainerStart(ctx, containerName, types.ContainerStartOptions{})
+		if err != nil {
+			return err
+		}
+		msg := fmt.Sprintf("Started stopped container %s", containerName)
+		logger.Info(msg)
+	default:
+		// if container is running, check the image tag
+		currentImage := existingContainer.Image
+		currentTag := strings.Split(currentImage, ":")[1]
+		if currentTag != containerTag {
+			// 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
+			}
+			_, err = cli.ContainerCreate(ctx, &container.Config{
+				Image: containerType + ":" + containerTag,
+			}, nil, nil, nil, containerName)
+			if err != nil {
+				return err
+			}
+			err = cli.ContainerStart(ctx, containerName, types.ContainerStartOptions{})
+			if err != nil {
+				return err
+			}
+			msg := fmt.Sprintf("Restarted %s with image %s:%s", containerName, containerType, containerTag)
+			logger.Info(msg)
+		} else {
+			msg := fmt.Sprintf("%s is already running with the correct tag: %s", containerName, containerTag)
+			logger.Info(msg)
+		}
+	}
+	return nil
+}
+
+// convert the version info back into json then a map lol
+// so we can easily get the correct repo/release channel/tag/hash
+func getCurrentContainerInfo(containerType string) (map[string]string, error) {
+	var res map[string]string
+	conf := config.Conf()
+	releaseChannel := conf.UpdateBranch
+	arch := config.Architecture
+	hashLabel := arch + "_sha256"
+	versionInfo := config.VersionInfo
+	jsonData, err := json.Marshal(VersionInfo)
+	if err != nil {
+		return res, err
+	}
+	// Convert JSON to map
+	var m map[string]interface{}
+	err = json.Unmarshal(jsonData, &m)
+	if err != nil {
+		return res, err
+	}
+	res["tag"] = m["groundseg"][releaseChannel][containerType]["tag"]
+	res["hash"] = m["groundseg"][releaseChannel][containerType][hashLabel]
+	res["repo"] = m["groundseg"][releaseChannel][containerType]["repo"]
+	return res, nil
+}

+ 5 - 0
docker/urbit.go

@@ -25,6 +25,11 @@ func LoadUrbits() error {
 		if err := LoadConfig(pier); err != nil {
 			logger.Error(fmt.Sprintf("%v", err))
 			continue
+			err := StartContainer(pier, "urbit")
+			if err != nil {
+				logger.Error(fmt.Sprintf("%v", err))
+				continue
+			}
 		}
 	}
 	// apply latest version info (if automated updates)

+ 3 - 3
structs/structs.go

@@ -101,10 +101,10 @@ type VersionDetails struct {
 
 type SystemUsage struct {
 	RAM      []uint64 `json:"ram"`
-	CPU      int     `json:"cpu"`
-	CPUTemp  float64     `json:"cpu_temp"`
+	CPU      int      `json:"cpu"`
+	CPUTemp  float64  `json:"cpu_temp"`
 	Disk     []uint64 `json:"disk"`
-	SwapFile int     `json:"swap"`
+	SwapFile int      `json:"swap"`
 }
 
 type SystemUpdates struct {

+ 8 - 3
system/system.go

@@ -14,24 +14,28 @@ import (
 )
 
 var (
-	logger  = slog.New(slog.NewJSONHandler(os.Stdout, nil))
+	logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
 )
 
-func GetMemory() (uint64, uint64)  {
+// get memory used/avail in bytes
+func GetMemory() (uint64, uint64) {
 	v, _ := mem.VirtualMemory()
 	return v.Used, v.Total
 }
 
+// get cpu usage as %
 func GetCPU() int {
 	percent, _ := cpu.Percent(time.Second, false)
 	return int(percent[0])
 }
 
+// get used/avail disk in bytes
 func GetDisk() (uint64, uint64) {
 	d, _ := disk.Usage("/")
 	return d.Used, d.Free
 }
 
+// get cpu temp (may not work on some devices)
 func GetTemp() float64 {
 	data, err := ioutil.ReadFile("/sys/class/thermal/thermal_zone0/temp")
 	if err != nil {
@@ -49,6 +53,7 @@ func GetTemp() float64 {
 	return float64(temp) / 1000.0
 }
 
+// return 0 for no 1 for yes(?)
 func HasSwap() int {
 	data, err := ioutil.ReadFile("/proc/swaps")
 	if err != nil {
@@ -62,4 +67,4 @@ func HasSwap() int {
 	} else {
 		return 0
 	}
-}
+}