diff --git a/pkg/service/HelmAppService.go b/pkg/service/HelmAppService.go index aa46d06e7..0c7236e56 100644 --- a/pkg/service/HelmAppService.go +++ b/pkg/service/HelmAppService.go @@ -14,6 +14,8 @@ import ( "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/storage/driver" + appsV1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/runtime" "path" "github.com/aws/aws-sdk-go/aws" @@ -40,11 +42,9 @@ import ( "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/repo" "io/ioutil" - appsV1 "k8s.io/api/apps/v1" coreV1 "k8s.io/api/core/v1" errors2 "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/rest" @@ -1439,6 +1439,28 @@ func buildResourceRef(gvk schema.GroupVersionKind, manifest unstructured.Unstruc func buildPodMetadata(nodes []*bean.ResourceNode) ([]*bean.PodMetadata, error) { podsMetadata := make([]*bean.PodMetadata, 0, len(nodes)) + var dNodeHash string + + for _, node := range nodes { + if node.Kind == k8sCommonBean.DeploymentKind { + deploymentNode := node.ResourceRef.Manifest.Object + dNodeMap := deploymentNode["spec"].(map[string]interface{}) + dNodeTemplate := dNodeMap["template"] + + d, err := json.Marshal(dNodeTemplate) + if err != nil { + return nil, err + } + + dNodeSpec := &coreV1.PodTemplateSpec{} + err = json.Unmarshal(d, dNodeSpec) + if err != nil { + return nil, err + } + dNodeHash = util.ComputeHash(dNodeSpec) + } + } + for _, node := range nodes { if node.Kind != k8sCommonBean.PodKind { continue @@ -1481,10 +1503,31 @@ func buildPodMetadata(nodes []*bean.ResourceNode) ([]*bean.PodMetadata, error) { } replicaSetNode := getMatchingNode(nodes, parentKind, replicaSet.Name) - // if parent of replicaset is deployment, compare label pod-template-hash - if replicaSetNode != nil && len(replicaSetNode.ParentRefs) > 0 && replicaSetNode.ParentRefs[0].Kind == k8sCommonBean.DeploymentKind { - isNew = replicaSet.GetLabels()["pod-template-hash"] == pod.GetLabels()["pod-template-hash"] + replicaNode := replicaSetNode.ResourceRef.Manifest.Object + replicaNodeMap := replicaNode["spec"].(map[string]interface{}) + replicaNodeTemplate := replicaNodeMap["template"] + + replica, err := json.Marshal(replicaNodeTemplate) + if err != nil { + return nil, err + } + + replicaSetTemplate := &coreV1.PodTemplateSpec{} + err = json.Unmarshal(replica, replicaSetTemplate) + if err != nil { + return nil, err } + + rsCopy := replicaSetTemplate.DeepCopy() + labels := make(map[string]string) + for k, v := range rsCopy.Labels { + if k != "pod-template-hash" { + labels[k] = v + } + } + rsCopy.Labels = labels + replicaHash := util.ComputeHash(rsCopy) + isNew = replicaHash == dNodeHash } // if parent kind is DaemonSet then compare DaemonSet's Child ControllerRevision's label controller-revision-hash with pod label controller-revision-hash @@ -1550,9 +1593,7 @@ func buildPodMetadata(nodes []*bean.ResourceNode) ([]*bean.PodMetadata, error) { EphemeralContainers: ephemeralContainers, IsNew: isNew, } - podsMetadata = append(podsMetadata, podMetadata) - } return podsMetadata, nil } diff --git a/pkg/util/Helper.go b/pkg/util/Helper.go index 5c4dee397..a2ef93f93 100644 --- a/pkg/util/Helper.go +++ b/pkg/util/Helper.go @@ -1,6 +1,15 @@ package util -import "reflect" +import ( + "fmt" + "github.com/davecgh/go-spew/spew" + "hash" + "hash/fnv" + coreV1 "k8s.io/api/core/v1" + "reflect" +) + +const alphanums = "bcdfghjklmnpqrstvwxz2456789" func IsMapSubset(mapSet interface{}, mapSubset interface{}) bool { @@ -30,3 +39,31 @@ func IsMapSubset(mapSet interface{}, mapSubset interface{}) bool { return true } + +func ComputeHash(template *coreV1.PodTemplateSpec) string { + podTemplateSpecHasher := fnv.New32a() + DeepHashObject(podTemplateSpecHasher, *template) + return SafeEncodeString(fmt.Sprint(podTemplateSpecHasher.Sum32())) +} + +func SafeEncodeString(s string) string { + r := make([]byte, len(s)) + for i, b := range []rune(s) { + r[i] = alphanums[(int(b) % len(alphanums))] + } + return string(r) +} + +func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) { + hasher.Reset() + printer := spew.ConfigState{ + Indent: " ", + SortKeys: true, + DisableMethods: true, + SpewKeys: true, + } + _, err := printer.Fprintf(hasher, "%#v", objectToWrite) + if err != nil { + fmt.Println(err) + } +}