feat: set UNCLOUD_MACHINE_ID in service container ENV (#135)

* Set machine id in service container ENV

* Add machine id to clone of the container's env map to avoid exposing serialization format

* fix: panic on setting UNCLOUD_MACHINE_ID env var when Env is nil in the spec

---------

Co-authored-by: Pasha Sviderski <me@psviderski.name>
This commit is contained in:
Justin Bradford
2025-10-07 14:12:00 +10:00
committed by GitHub
co-authored by Pasha Sviderski
parent 784d86d8e8
commit 3e804d9ecc
2 changed files with 24 additions and 3 deletions
+19 -2
View File
@@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
"maps"
"net/netip" "net/netip"
"os" "os"
"path/filepath" "path/filepath"
@@ -57,6 +58,9 @@ type Server struct {
// internalDNSIP is a function that returns the IP address of the internal DNS server. It may return an empty // internalDNSIP is a function that returns the IP address of the internal DNS server. It may return an empty
// address if the address is unknown (e.g. when the machine is not initialised yet). // address if the address is unknown (e.g. when the machine is not initialised yet).
internalDNSIP func() netip.Addr internalDNSIP func() netip.Addr
// machineID is a function that returns the machine ID. It may return an empty string if the machine
// is not initialised yet.
machineID func() string
// networkReady is a function that returns true if the Docker network is ready for containers. // networkReady is a function that returns true if the Docker network is ready for containers.
networkReady func() bool networkReady func() bool
// waitForNetworkReady is a function that waits for the Docker network to be ready for containers. // waitForNetworkReady is a function that waits for the Docker network to be ready for containers.
@@ -72,12 +76,13 @@ type ServerOptions struct {
} }
// NewServer creates a new Docker gRPC server with the provided Docker service. // NewServer creates a new Docker gRPC server with the provided Docker service.
func NewServer(service *Service, db *sqlx.DB, internalDNSIP func() netip.Addr, opts ServerOptions) *Server { func NewServer(service *Service, db *sqlx.DB, internalDNSIP func() netip.Addr, machineID func() string, opts ServerOptions) *Server {
s := &Server{ s := &Server{
client: service.Client, client: service.Client,
service: service, service: service,
db: db, db: db,
internalDNSIP: internalDNSIP, internalDNSIP: internalDNSIP,
machineID: machineID,
} }
s.networkReady = opts.NetworkReady s.networkReady = opts.NetworkReady
@@ -529,9 +534,21 @@ func (s *Server) CreateServiceContainer(
containerName = fmt.Sprintf("%s-%s", spec.Name, suffix) containerName = fmt.Sprintf("%s-%s", spec.Name, suffix)
} }
envVars := maps.Clone(spec.Container.Env)
if envVars == nil {
envVars = make(api.EnvVars)
}
// Inject the machine ID if available
if s.machineID != nil {
if machineID := s.machineID(); machineID != "" {
envVars["UNCLOUD_MACHINE_ID"] = machineID
}
}
config := &container.Config{ config := &container.Config{
Cmd: spec.Container.Command, Cmd: spec.Container.Command,
Env: spec.Container.Env.ToSlice(), Env: envVars.ToSlice(),
Entrypoint: spec.Container.Entrypoint, Entrypoint: spec.Container.Entrypoint,
Hostname: containerName, Hostname: containerName,
Image: spec.Container.Image, Image: spec.Container.Image,
+5 -1
View File
@@ -282,7 +282,11 @@ func NewMachine(config *Config) (*Machine, error) {
internalDNSIP := func() netip.Addr { internalDNSIP := func() netip.Addr {
return m.IP() return m.IP()
} }
m.dockerServer = machinedocker.NewServer(dockerService, db, internalDNSIP, machinedocker.ServerOptions{ // Machine ID will only be available after the machine is initialised as a cluster member so wrap it in a function.
machineID := func() string {
return m.state.ID
}
m.dockerServer = machinedocker.NewServer(dockerService, db, internalDNSIP, machineID, machinedocker.ServerOptions{
NetworkReady: m.IsNetworkReady, NetworkReady: m.IsNetworkReady,
WaitForNetworkReady: m.WaitForNetworkReady, WaitForNetworkReady: m.WaitForNetworkReady,
}) })