Skip to content

Commit

Permalink
fix(digest): fix hash computation for the new Traits schema
Browse files Browse the repository at this point in the history
  • Loading branch information
tadayosi committed Jul 3, 2022
1 parent c6f4b22 commit 3ec0ce9
Showing 1 changed file with 79 additions and 3 deletions.
82 changes: 79 additions & 3 deletions pkg/util/digest/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"hash"
"io"
"path"
"sort"
Expand Down Expand Up @@ -98,12 +99,29 @@ func ComputeForIntegration(integration *v1.Integration) (string, error) {
}

// Integration traits
traits, err := json.Marshal(integration.Spec.Traits)
// Calculation logic prior to 1.10.0 (the new Traits API schema) is maintained
// in order to keep consistency in the digest calculated from the same set of
// Trait configurations for backward compatibility.
traitsMap, err := toMap(integration.Spec.Traits)
if err != nil {
return "", err
}
if _, err := hash.Write(traits); err != nil {
return "", err
for _, name := range sortedTraitsMapKeys(traitsMap) {
if name != "addons" {
if err := computeForTrait(hash, name, traitsMap[name]); err != nil {
return "", err
}
} else {
// Addons
addons := traitsMap["addons"]
for _, name := range util.SortedMapKeys(addons) {
if addon, ok := addons[name].(map[string]interface{}); ok {
if err := computeForTrait(hash, name, addon); err != nil {
return "", err
}
}
}
}
}
// Integration traits as annotations
for _, k := range sortedTraitAnnotationsKeys(integration) {
Expand All @@ -118,6 +136,53 @@ func ComputeForIntegration(integration *v1.Integration) (string, error) {
return digest, nil
}

func computeForTrait(hash hash.Hash, name string, trait map[string]interface{}) error {
if _, err := hash.Write([]byte(name + "[")); err != nil {
return err
}
// hash legacy configuration first
if trait["configuration"] != nil {
if config, ok := trait["configuration"].(map[string]interface{}); ok {
if err := computeForTraitProps(hash, config); err != nil {
return err
}
}
delete(trait, "configuration")
}
if err := computeForTraitProps(hash, trait); err != nil {
return err
}
if _, err := hash.Write([]byte("]")); err != nil {
return err
}

return nil
}

func computeForTraitProps(hash hash.Hash, props map[string]interface{}) error {
for _, prop := range util.SortedMapKeys(props) {
val := props[prop]
if _, err := hash.Write([]byte(fmt.Sprintf("%s=%v,", prop, val))); err != nil {
return err
}
}

return nil
}

func toMap(traits v1.Traits) (map[string]map[string]interface{}, error) {
data, err := json.Marshal(traits)
if err != nil {
return nil, err
}
traitsMap := make(map[string]map[string]interface{})
if err = json.Unmarshal(data, &traitsMap); err != nil {
return nil, err
}

return traitsMap, nil
}

// ComputeForIntegrationKit a digest of the fields that are relevant for the deployment
// Produces a digest that can be used as docker image tag.
func ComputeForIntegrationKit(kit *v1.IntegrationKit) (string, error) {
Expand Down Expand Up @@ -216,6 +281,17 @@ func ComputeForSource(s v1.SourceSpec) (string, error) {
return digest, nil
}

func sortedTraitsMapKeys(m map[string]map[string]interface{}) []string {
res := make([]string, len(m))
i := 0
for k := range m {
res[i] = k
i++
}
sort.Strings(res)
return res
}

func sortedTraitAnnotationsKeys(it *v1.Integration) []string {
res := make([]string, 0, len(it.Annotations))
for k := range it.Annotations {
Expand Down

0 comments on commit 3ec0ce9

Please sign in to comment.