Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
Signed-off-by: Suleiman Dibirov <idsulik@gmail.com>
  • Loading branch information
idsulik committed Dec 15, 2024
1 parent bdf16af commit 21f172e
Showing 5 changed files with 90 additions and 45 deletions.
4 changes: 2 additions & 2 deletions pkg/api/labels.go
Original file line number Diff line number Diff line change
@@ -32,9 +32,9 @@ const (
// ConfigHashLabel stores configuration hash for a compose service
ConfigHashLabel = "com.docker.compose.config-hash"
// ServiceConfigsHash stores configuration hash for a compose service configs
ServiceConfigsHash = "com.docker.compose.service.configs-hash"
ServiceConfigsHash = "com.docker.compose.service.%s.configs.hash"
// ServiceSecretsHash stores configuration hash for a compose service secrets
ServiceSecretsHash = "com.docker.compose.service.secrets-hash"
ServiceSecretsHash = "com.docker.compose.service.%s.secrets.hash"
// ContainerNumberLabel stores the container index of a replicated service
ContainerNumberLabel = "com.docker.compose.container-number"
// VolumeLabel allow to track resource related to a compose volume
17 changes: 12 additions & 5 deletions pkg/compose/convergence.go
Original file line number Diff line number Diff line change
@@ -326,6 +326,7 @@ func (c *convergence) resolveSharedNamespaces(service *types.ServiceConfig) erro
return nil
}

//nolint:gocyclo
func (c *convergence) mustRecreate(project *types.Project, expected types.ServiceConfig, actual moby.Container, policy string) (bool, error) {
if policy == api.RecreateNever {
return false, nil
@@ -346,20 +347,26 @@ func (c *convergence) mustRecreate(project *types.Project, expected types.Servic
return true, nil
}

serviceConfigsHash, err := ServiceConfigsHash(project, expected)
serviceNameToConfigHash, err := ServiceConfigsHash(project, expected)
if err != nil {
return false, err
}

Check warning on line 353 in pkg/compose/convergence.go

Codecov / codecov/patch

pkg/compose/convergence.go#L352-L353

Added lines #L352 - L353 were not covered by tests

for serviceName, hash := range serviceNameToConfigHash {
if actual.Labels[fmt.Sprintf(api.ServiceConfigsHash, serviceName)] != hash {
return true, nil
}

Check warning on line 358 in pkg/compose/convergence.go

Codecov / codecov/patch

pkg/compose/convergence.go#L356-L358

Added lines #L356 - L358 were not covered by tests
}

serviceSecretsHash, err := ServiceSecretsHash(project, expected)
if err != nil {
return false, err
}

Check warning on line 364 in pkg/compose/convergence.go

Codecov / codecov/patch

pkg/compose/convergence.go#L363-L364

Added lines #L363 - L364 were not covered by tests
serviceConfigsChanged := actual.Labels[api.ServiceConfigsHash] != serviceConfigsHash
serviceSecretsChanged := actual.Labels[api.ServiceSecretsHash] != serviceSecretsHash

if serviceConfigsChanged || serviceSecretsChanged {
return true, nil
for serviceName, hash := range serviceSecretsHash {
if actual.Labels[fmt.Sprintf(api.ServiceSecretsHash, serviceName)] != hash {
return true, nil
}

Check warning on line 369 in pkg/compose/convergence.go

Codecov / codecov/patch

pkg/compose/convergence.go#L367-L369

Added lines #L367 - L369 were not covered by tests
}

if c.networks != nil && actual.State == "running" {
14 changes: 10 additions & 4 deletions pkg/compose/create.go
Original file line number Diff line number Diff line change
@@ -511,23 +511,29 @@ func (s *composeService) prepareLabels(labels types.Labels, project *types.Proje
return nil, err
}

serviceConfigsHash, err := ServiceConfigsHash(project, service)
serviceNameToConfigHash, err := ServiceConfigsHash(project, service)
if err != nil {
return nil, err
}

Check warning on line 517 in pkg/compose/create.go

Codecov / codecov/patch

pkg/compose/create.go#L516-L517

Added lines #L516 - L517 were not covered by tests

serviceSecretsHash, err := ServiceSecretsHash(project, service)
for serviceName, hash := range serviceNameToConfigHash {
labels[fmt.Sprintf(api.ServiceConfigsHash, serviceName)] = hash
}

serviceNameToSecretHash, err := ServiceSecretsHash(project, service)
if err != nil {
return nil, err
}

Check warning on line 526 in pkg/compose/create.go

Codecov / codecov/patch

pkg/compose/create.go#L525-L526

Added lines #L525 - L526 were not covered by tests

for serviceName, hash := range serviceNameToSecretHash {
labels[fmt.Sprintf(api.ServiceSecretsHash, serviceName)] = hash
}

if number > 0 {
// One-off containers are not indexed
labels[api.ContainerNumberLabel] = strconv.Itoa(number)
}
labels[api.ConfigHashLabel] = serviceHash
labels[api.ServiceConfigsHash] = serviceConfigsHash
labels[api.ServiceSecretsHash] = serviceSecretsHash
labels[api.ContainerNumberLabel] = strconv.Itoa(number)

var dependencies []string
20 changes: 10 additions & 10 deletions pkg/compose/hash.go
Original file line number Diff line number Diff line change
@@ -47,37 +47,37 @@ func ServiceHash(o types.ServiceConfig) (string, error) {
}

// ServiceConfigsHash computes the configuration hash for service configs.
func ServiceConfigsHash(project *types.Project, serviceConfig types.ServiceConfig) (string, error) {
data := make([]byte, 0)
func ServiceConfigsHash(project *types.Project, serviceConfig types.ServiceConfig) (map[string]string, error) {
serviceNameToHash := make(map[string]string)
for _, config := range serviceConfig.Configs {
file := project.Configs[config.Source]
b, err := createTarForConfig(project, types.FileReferenceConfig(config), types.FileObjectConfig(file))

if err != nil {
return "", err
return nil, err
}

Check warning on line 58 in pkg/compose/hash.go

Codecov / codecov/patch

pkg/compose/hash.go#L57-L58

Added lines #L57 - L58 were not covered by tests

data = append(data, b.Bytes()...)
serviceNameToHash[config.Target] = digest.SHA256.FromBytes(b.Bytes()).Encoded()
}

return digest.SHA256.FromBytes(data).Encoded(), nil
return serviceNameToHash, nil
}

// ServiceSecretsHash computes the configuration hash for service secrets.
func ServiceSecretsHash(project *types.Project, serviceConfig types.ServiceConfig) (string, error) {
data := make([]byte, 0)
func ServiceSecretsHash(project *types.Project, serviceConfig types.ServiceConfig) (map[string]string, error) {
serviceNameToHash := make(map[string]string)
for _, secret := range serviceConfig.Secrets {
file := project.Secrets[secret.Source]
b, err := createTarForConfig(project, types.FileReferenceConfig(secret), types.FileObjectConfig(file))

if err != nil {
return "", err
return nil, err
}

Check warning on line 75 in pkg/compose/hash.go

Codecov / codecov/patch

pkg/compose/hash.go#L74-L75

Added lines #L74 - L75 were not covered by tests

data = append(data, b.Bytes()...)
serviceNameToHash[secret.Target] = digest.SHA256.FromBytes(b.Bytes()).Encoded()
}

return digest.SHA256.FromBytes(data).Encoded(), nil
return serviceNameToHash, nil
}

func createTarForConfig(
80 changes: 56 additions & 24 deletions pkg/compose/hash_test.go
Original file line number Diff line number Diff line change
@@ -40,79 +40,111 @@ func TestServiceHashWithIgnorableValues(t *testing.T) {
}

func TestServiceConfigsHashWithoutChangesContent(t *testing.T) {
hash1, err := ServiceConfigsHash(projectWithConfigs("a", "", ""), serviceConfig("myContext1", "always", 1))
serviceNameToConfigHash1, err := ServiceConfigsHash(projectWithConfigs("a", "", ""), serviceConfig("myContext1", "always", 1))
assert.NilError(t, err)
hash2, err := ServiceConfigsHash(projectWithConfigs("a", "", ""), serviceConfig("myContext2", "never", 2))
serviceNameToConfigHas2, err := ServiceConfigsHash(projectWithConfigs("a", "", ""), serviceConfig("myContext2", "never", 2))
assert.NilError(t, err)
assert.Assert(t, hash1 == hash2)
assert.Equal(t, len(serviceNameToConfigHash1), len(serviceNameToConfigHas2))

for serviceName, hash := range serviceNameToConfigHash1 {
assert.Equal(t, hash, serviceNameToConfigHas2[serviceName])
}
}

func TestServiceConfigsHashWithChangedConfigContent(t *testing.T) {
hash1, err := ServiceConfigsHash(projectWithConfigs("a", "", ""), serviceConfig("myContext1", "always", 1))
serviceNameToConfigHash1, err := ServiceConfigsHash(projectWithConfigs("a", "", ""), serviceConfig("myContext1", "always", 1))
assert.NilError(t, err)
hash2, err := ServiceConfigsHash(projectWithConfigs("b", "", ""), serviceConfig("myContext2", "never", 2))
serviceNameToConfigHash2, err := ServiceConfigsHash(projectWithConfigs("b", "", ""), serviceConfig("myContext2", "never", 2))
assert.NilError(t, err)
assert.Assert(t, hash1 != hash2)
assert.Equal(t, len(serviceNameToConfigHash1), len(serviceNameToConfigHash2))

for serviceName, hash := range serviceNameToConfigHash1 {
assert.Assert(t, hash != serviceNameToConfigHash2[serviceName])
}
}

func TestServiceConfigsHashWithChangedConfigEnvironment(t *testing.T) {
hash1, err := ServiceConfigsHash(projectWithConfigs("", "a", ""), serviceConfig("myContext1", "always", 1))
serviceNameToConfigHash1, err := ServiceConfigsHash(projectWithConfigs("", "a", ""), serviceConfig("myContext1", "always", 1))
assert.NilError(t, err)
hash2, err := ServiceConfigsHash(projectWithConfigs("", "b", ""), serviceConfig("myContext2", "never", 2))
serviceNameToConfigHash2, err := ServiceConfigsHash(projectWithConfigs("", "b", ""), serviceConfig("myContext2", "never", 2))
assert.NilError(t, err)
assert.Assert(t, hash1 != hash2)
assert.Equal(t, len(serviceNameToConfigHash1), len(serviceNameToConfigHash2))

for serviceName, hash := range serviceNameToConfigHash1 {
assert.Assert(t, hash != serviceNameToConfigHash2[serviceName])
}
}

func TestServiceConfigsHashWithChangedConfigFile(t *testing.T) {
hash1, err := ServiceConfigsHash(
serviceNameToConfigHash1, err := ServiceConfigsHash(
projectWithConfigs("", "", "./testdata/config1.txt"),
serviceConfig("myContext1", "always", 1),
)
assert.NilError(t, err)
hash2, err := ServiceConfigsHash(
serviceNameToConfigHash2, err := ServiceConfigsHash(
projectWithConfigs("", "", "./testdata/config2.txt"),
serviceConfig("myContext2", "never", 2),
)
assert.NilError(t, err)
assert.Assert(t, hash1 != hash2)
assert.Equal(t, len(serviceNameToConfigHash1), len(serviceNameToConfigHash2))

for serviceName, hash := range serviceNameToConfigHash1 {
assert.Assert(t, hash != serviceNameToConfigHash2[serviceName])
}
}

func TestServiceSecretsHashWithoutChangesContent(t *testing.T) {
hash1, err := ServiceSecretsHash(projectWithSecrets("a", "", ""), serviceConfig("myContext1", "always", 1))
serviceNameToSecretHash1, err := ServiceSecretsHash(projectWithSecrets("a", "", ""), serviceConfig("myContext1", "always", 1))
assert.NilError(t, err)
hash2, err := ServiceSecretsHash(projectWithSecrets("a", "", ""), serviceConfig("myContext2", "never", 2))
serviceNameToSecretHash2, err := ServiceSecretsHash(projectWithSecrets("a", "", ""), serviceConfig("myContext2", "never", 2))
assert.NilError(t, err)
assert.Assert(t, hash1 == hash2)
assert.Equal(t, len(serviceNameToSecretHash1), len(serviceNameToSecretHash2))

for serviceName, hash := range serviceNameToSecretHash1 {
assert.Equal(t, hash, serviceNameToSecretHash2[serviceName])
}
}

func TestServiceSecretsHashWithChangedSecretContent(t *testing.T) {
hash1, err := ServiceSecretsHash(projectWithSecrets("a", "", ""), serviceConfig("myContext1", "always", 1))
serviceNameToSecretHash1, err := ServiceSecretsHash(projectWithSecrets("a", "", ""), serviceConfig("myContext1", "always", 1))
assert.NilError(t, err)
hash2, err := ServiceSecretsHash(projectWithSecrets("b", "", ""), serviceConfig("myContext2", "never", 2))
serviceNameToSecretHash2, err := ServiceSecretsHash(projectWithSecrets("b", "", ""), serviceConfig("myContext2", "never", 2))
assert.NilError(t, err)
assert.Assert(t, hash1 != hash2)
assert.Equal(t, len(serviceNameToSecretHash1), len(serviceNameToSecretHash2))

for serviceName, hash := range serviceNameToSecretHash1 {
assert.Assert(t, hash != serviceNameToSecretHash2[serviceName])
}
}

func TestServiceSecretsHashWithChangedSecretEnvironment(t *testing.T) {
hash1, err := ServiceSecretsHash(projectWithSecrets("", "a", ""), serviceConfig("myContext1", "always", 1))
serviceNameToSecretHash1, err := ServiceSecretsHash(projectWithSecrets("", "a", ""), serviceConfig("myContext1", "always", 1))
assert.NilError(t, err)
hash2, err := ServiceSecretsHash(projectWithSecrets("", "b", ""), serviceConfig("myContext2", "never", 2))
serviceNameToSecretHash2, err := ServiceSecretsHash(projectWithSecrets("", "b", ""), serviceConfig("myContext2", "never", 2))
assert.NilError(t, err)
assert.Assert(t, hash1 != hash2)
assert.Equal(t, len(serviceNameToSecretHash1), len(serviceNameToSecretHash2))

for serviceName, hash := range serviceNameToSecretHash1 {
assert.Assert(t, hash != serviceNameToSecretHash2[serviceName])
}
}

func TestServiceSecretsHashWithChangedSecretFile(t *testing.T) {
hash1, err := ServiceSecretsHash(
serviceNameToSecretHash1, err := ServiceSecretsHash(
projectWithSecrets("", "", "./testdata/config1.txt"),
serviceConfig("myContext1", "always", 1),
)
assert.NilError(t, err)
hash2, err := ServiceSecretsHash(
serviceNameToSecretHash2, err := ServiceSecretsHash(
projectWithSecrets("", "", "./testdata/config2.txt"),
serviceConfig("myContext2", "never", 2),
)
assert.NilError(t, err)
assert.Assert(t, hash1 != hash2)
assert.Equal(t, len(serviceNameToSecretHash1), len(serviceNameToSecretHash2))

for serviceName, hash := range serviceNameToSecretHash1 {
assert.Assert(t, hash != serviceNameToSecretHash2[serviceName])
}
}

func projectWithConfigs(configContent, configEnvironmentValue, configFile string) *types.Project {

0 comments on commit 21f172e

Please sign in to comment.