mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
fix: recreate containers only if spec changed by comparing spec hash
This commit is contained in:
@@ -9,11 +9,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LabelManaged = "uncloud.managed"
|
||||
LabelServiceID = "uncloud.service.id"
|
||||
LabelServiceName = "uncloud.service.name"
|
||||
LabelServiceMode = "uncloud.service.mode"
|
||||
LabelServicePorts = "uncloud.service.ports"
|
||||
LabelManaged = "uncloud.managed"
|
||||
LabelServiceID = "uncloud.service.id"
|
||||
LabelServiceName = "uncloud.service.name"
|
||||
LabelServiceMode = "uncloud.service.mode"
|
||||
LabelServicePorts = "uncloud.service.ports"
|
||||
LabelServiceSpecHash = "uncloud.service.spec-hash"
|
||||
)
|
||||
|
||||
type Container struct {
|
||||
|
||||
+60
-6
@@ -1,6 +1,8 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/distribution/reference"
|
||||
@@ -16,6 +18,12 @@ const (
|
||||
ServiceModeGlobal = "global"
|
||||
)
|
||||
|
||||
var serviceIDRegexp = regexp.MustCompile("^[0-9a-f]{32}$")
|
||||
|
||||
func ValidateServiceID(id string) bool {
|
||||
return serviceIDRegexp.MatchString(id)
|
||||
}
|
||||
|
||||
type ServiceSpec struct {
|
||||
Container ContainerSpec
|
||||
// Mode is the replication mode of the service. Default is ServiceModeReplicated if empty.
|
||||
@@ -50,6 +58,58 @@ func (s *ServiceSpec) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImmutableHash returns a hash of the immutable parts of the ServiceSpec that require container recreation if changed.
|
||||
func (s *ServiceSpec) ImmutableHash() (string, error) {
|
||||
var err error
|
||||
// Serialise and sort the ports to ensure the hash is consistent.
|
||||
ports := make([]string, len(s.Ports))
|
||||
for i, p := range s.Ports {
|
||||
ports[i], err = p.String()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("encode service port spec: %w", err)
|
||||
}
|
||||
}
|
||||
slices.Sort(ports)
|
||||
|
||||
volumes := make([]string, 0, len(s.Container.Volumes))
|
||||
volumes = append(volumes, s.Container.Volumes...)
|
||||
slices.Sort(volumes)
|
||||
|
||||
hashSpec := immutableHashSpec{
|
||||
Command: s.Container.Command,
|
||||
Entrypoint: s.Container.Entrypoint,
|
||||
Image: s.Container.Image,
|
||||
Init: s.Container.Init,
|
||||
Ports: ports,
|
||||
Volumes: volumes,
|
||||
}
|
||||
|
||||
data, err := json.Marshal(hashSpec)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal immutable hash spec: %w", err)
|
||||
}
|
||||
|
||||
hasher := sha256.New()
|
||||
if _, err = hasher.Write(data); err != nil {
|
||||
return "", fmt.Errorf("write to SHA256 hasher: %w", err)
|
||||
}
|
||||
|
||||
return hex.EncodeToString(hasher.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// immutableHashSpec contains only the immutable fields from ServiceSpec that require container recreation if changed.
|
||||
type immutableHashSpec struct {
|
||||
Command []string `json:",omitempty"`
|
||||
Entrypoint []string `json:",omitempty"`
|
||||
Image string
|
||||
Init *bool `json:",omitempty"`
|
||||
// Ports are set as labels on the container which are immutable.
|
||||
// TODO: store ingress ports in the cluster store instead of as labels which will allow changing them without
|
||||
// recreating the container.
|
||||
Ports []string `json:",omitempty"`
|
||||
Volumes []string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Equals returns true if the service spec is equal to the given spec ignoring the number of replicas.
|
||||
func (s *ServiceSpec) Equals(spec ServiceSpec) bool {
|
||||
// TODO: ignore order of ports.
|
||||
@@ -60,12 +120,6 @@ func (s *ServiceSpec) Equals(spec ServiceSpec) bool {
|
||||
return reflect.DeepEqual(*s, spec)
|
||||
}
|
||||
|
||||
var serviceIDRegexp = regexp.MustCompile("^[0-9a-f]{32}$")
|
||||
|
||||
func ValidateServiceID(id string) bool {
|
||||
return serviceIDRegexp.MatchString(id)
|
||||
}
|
||||
|
||||
type ContainerSpec struct {
|
||||
// Command overrides the default CMD of the image to be executed when running a container.
|
||||
Command []string
|
||||
|
||||
Reference in New Issue
Block a user