From b5ef65478fbc8cf653a2cadd47de014d731b2b4b Mon Sep 17 00:00:00 2001 From: Oded Ben Ozer Date: Fri, 12 Apr 2024 08:29:39 +0200 Subject: [PATCH] Add diff from ArgoCD cli --- go.mod | 9 +- go.sum | 12 ++ internal/pkg/argocd/argocd.go | 272 ++++++++++++++++++++-------------- 3 files changed, 183 insertions(+), 110 deletions(-) diff --git a/go.mod b/go.mod index 93a320d8..d7b89205 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.22.1 require ( github.com/alexliesenfeld/health v0.8.0 github.com/argoproj/argo-cd/v2 v2.11.0-rc1 + github.com/argoproj/gitops-engine v0.7.1-0.20240411122334-1ade3a199867 github.com/bradleyfalzon/ghinstallation/v2 v2.10.0 github.com/go-test/deep v1.1.0 github.com/google/go-github/v52 v52.0.0 @@ -20,6 +21,7 @@ require ( golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 golang.org/x/oauth2 v0.19.0 gopkg.in/yaml.v2 v2.4.0 + k8s.io/apimachinery v0.26.11 ) require ( @@ -31,7 +33,6 @@ require ( github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect - github.com/argoproj/gitops-engine v0.7.1-0.20240411122334-1ade3a199867 // indirect github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect @@ -86,6 +87,8 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/itchyny/gojq v0.12.13 // indirect + github.com/itchyny/timefmt-go v0.1.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -127,6 +130,7 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xlab/treeprint v1.2.0 // indirect + github.com/yuin/gopher-lua v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect go.opentelemetry.io/otel v1.25.0 // indirect go.opentelemetry.io/otel/metric v1.25.0 // indirect @@ -151,7 +155,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.26.11 // indirect k8s.io/apiextensions-apiserver v0.26.10 // indirect - k8s.io/apimachinery v0.26.11 // indirect k8s.io/apiserver v0.26.11 // indirect k8s.io/cli-runtime v0.26.11 // indirect k8s.io/client-go v0.26.11 // indirect @@ -163,7 +166,9 @@ require ( k8s.io/kubectl v0.26.4 // indirect k8s.io/kubernetes v1.26.11 // indirect k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect + layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427 // indirect oras.land/oras-go/v2 v2.5.0 // indirect + sigs.k8s.io/controller-runtime v0.14.7 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.17.1 // indirect sigs.k8s.io/kustomize/kyaml v0.17.0 // indirect diff --git a/go.sum b/go.sum index 4342ad1e..2f5ef010 100644 --- a/go.sum +++ b/go.sum @@ -744,6 +744,8 @@ github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0+ github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= @@ -990,6 +992,10 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= +github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4= +github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= +github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -1667,6 +1673,8 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= @@ -2016,6 +2024,8 @@ k8s.io/kubernetes v1.26.11/go.mod h1:z1URAaBJ+XnOTr3Q/l4umxRUxn/OyD2fbkUgS0Bl7u4 k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427 h1:RZkKxMR3jbQxdCEcglq3j7wY3PRJIopAwBlx1RE71X0= +layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427/go.mod h1:ivKkcY8Zxw5ba0jldhZCYYQfGdb2K6u9tbYK1AwMIBc= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= @@ -2056,6 +2066,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.14.7 h1:Vrnm2vk9ZFlRkXATHz0W0wXcqNl7kPat8q2JyxVy0Q8= +sigs.k8s.io/controller-runtime v0.14.7/go.mod h1:ErTs3SJCOujNUnTz4AS+uh8hp6DHMo1gj6fFndJT1X8= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= diff --git a/internal/pkg/argocd/argocd.go b/internal/pkg/argocd/argocd.go index 7fb1c347..975fa1f7 100644 --- a/internal/pkg/argocd/argocd.go +++ b/internal/pkg/argocd/argocd.go @@ -2,124 +2,180 @@ package argocd import ( "context" + "encoding/json" "fmt" + cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" + "github.com/argoproj/argo-cd/v2/controller" "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + "github.com/argoproj/argo-cd/v2/util/argo" + argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff" + "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/errors" argoio "github.com/argoproj/argo-cd/v2/util/io" + "github.com/argoproj/gitops-engine/pkg/sync/hook" + "github.com/argoproj/gitops-engine/pkg/sync/ignore" + "github.com/argoproj/gitops-engine/pkg/utils/kube" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" ) -// type objKeyLiveTarget struct { -// key kube.ResourceKey -// live *unstructured.Unstructured -// target *unstructured.Unstructured -// } - -// func groupObjsByKey(localObs []*unstructured.Unstructured, liveObjs []*unstructured.Unstructured, appNamespace string) map[kube.ResourceKey]*unstructured.Unstructured { -// namespacedByGk := make(map[schema.GroupKind]bool) -// for i := range liveObjs { -// if liveObjs[i] != nil { -// key := kube.GetResourceKey(liveObjs[i]) -// namespacedByGk[schema.GroupKind{Group: key.Group, Kind: key.Kind}] = key.Namespace != "" -// } -// } -// localObs, _, err := controller.DeduplicateTargetObjects(appNamespace, localObs, &resourceInfoProvider{namespacedByGk: namespacedByGk}) -// errors.CheckError(err) -// objByKey := make(map[kube.ResourceKey]*unstructured.Unstructured) -// for i := range localObs { -// obj := localObs[i] -// if !(hook.IsHook(obj) || ignore.Ignore(obj)) { -// objByKey[kube.GetResourceKey(obj)] = obj -// } -// } -// return objByKey -// } -// -// func findandPrintDiff(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, resources *application.ManagedResourcesResponse, argoSettings *settings.Settings, diffOptions *DifferenceOption) bool { -// var foundDiffs bool -// liveObjs, err := cmdutil.LiveObjects(resources.Items) -// errors.CheckError(err) -// items := make([]objKeyLiveTarget, 0) -// if diffOptions.local != "" { -// localObjs := groupObjsByKey(getLocalObjects(ctx, app, proj, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace) -// items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) -// } else if diffOptions.revision != "" || (diffOptions.revisionSourceMappings != nil) { -// var unstructureds []*unstructured.Unstructured -// for _, mfst := range diffOptions.res.Manifests { -// obj, err := argoappv1.UnmarshalToUnstructured(mfst) -// errors.CheckError(err) -// unstructureds = append(unstructureds, obj) -// } -// groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) -// items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) -// } else if diffOptions.serversideRes != nil { -// var unstructureds []*unstructured.Unstructured -// for _, mfst := range diffOptions.serversideRes.Manifests { -// obj, err := argoappv1.UnmarshalToUnstructured(mfst) -// errors.CheckError(err) -// unstructureds = append(unstructureds, obj) -// } -// groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) -// items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) -// } else { -// for i := range resources.Items { -// res := resources.Items[i] -// var live = &unstructured.Unstructured{} -// err := json.Unmarshal([]byte(res.NormalizedLiveState), &live) -// errors.CheckError(err) -// -// var target = &unstructured.Unstructured{} -// err = json.Unmarshal([]byte(res.TargetState), &target) -// errors.CheckError(err) -// -// items = append(items, objKeyLiveTarget{kube.NewResourceKey(res.Group, res.Kind, res.Namespace, res.Name), live, target}) -// } -// } -// -// for _, item := range items { -// if item.target != nil && hook.IsHook(item.target) || item.live != nil && hook.IsHook(item.live) { -// continue -// } -// overrides := make(map[string]argoappv1.ResourceOverride) -// for k := range argoSettings.ResourceOverrides { -// val := argoSettings.ResourceOverrides[k] -// overrides[k] = *val -// } -// -// ignoreAggregatedRoles := false -// diffConfig, err := argodiff.NewDiffConfigBuilder(). -// WithDiffSettings(app.Spec.IgnoreDifferences, overrides, ignoreAggregatedRoles). -// WithTracking(argoSettings.AppLabelKey, argoSettings.TrackingMethod). -// WithNoCache(). -// Build() -// errors.CheckError(err) -// diffRes, err := argodiff.StateDiff(item.live, item.target, diffConfig) -// errors.CheckError(err) -// -// if diffRes.Modified || item.target == nil || item.live == nil { -// fmt.Printf("\n===== %s/%s %s/%s ======\n", item.key.Group, item.key.Kind, item.key.Namespace, item.key.Name) -// var live *unstructured.Unstructured -// var target *unstructured.Unstructured -// if item.target != nil && item.live != nil { -// target = &unstructured.Unstructured{} -// live = item.live -// err = json.Unmarshal(diffRes.PredictedLive, target) -// errors.CheckError(err) -// } else { -// live = item.live -// target = item.target -// } -// if !foundDiffs { -// foundDiffs = true -// } -// _ = cli.PrintDiff(item.key.Name, live, target) -// } -// } -// return foundDiffs -// } +type resourceInfoProvider struct { + namespacedByGk map[schema.GroupKind]bool +} + +// Infer if obj is namespaced or not from corresponding live objects list. If corresponding live object has namespace then target object is also namespaced. +// If live object is missing then it does not matter if target is namespaced or not. +func (p *resourceInfoProvider) IsNamespaced(gk schema.GroupKind) (bool, error) { + return p.namespacedByGk[gk], nil +} + +type objKeyLiveTarget struct { + key kube.ResourceKey + live *unstructured.Unstructured + target *unstructured.Unstructured +} + +func groupObjsByKey(localObs []*unstructured.Unstructured, liveObjs []*unstructured.Unstructured, appNamespace string) map[kube.ResourceKey]*unstructured.Unstructured { + namespacedByGk := make(map[schema.GroupKind]bool) + for i := range liveObjs { + if liveObjs[i] != nil { + key := kube.GetResourceKey(liveObjs[i]) + namespacedByGk[schema.GroupKind{Group: key.Group, Kind: key.Kind}] = key.Namespace != "" + } + } + localObs, _, err := controller.DeduplicateTargetObjects(appNamespace, localObs, &resourceInfoProvider{namespacedByGk: namespacedByGk}) + errors.CheckError(err) + objByKey := make(map[kube.ResourceKey]*unstructured.Unstructured) + for i := range localObs { + obj := localObs[i] + if !(hook.IsHook(obj) || ignore.Ignore(obj)) { + objByKey[kube.GetResourceKey(obj)] = obj + } + } + return objByKey +} + +func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[kube.ResourceKey]*unstructured.Unstructured, items []objKeyLiveTarget, argoSettings *settings.Settings, appName, namespace string) []objKeyLiveTarget { + resourceTracking := argo.NewResourceTracking() + for _, res := range resources.Items { + var live = &unstructured.Unstructured{} + err := json.Unmarshal([]byte(res.NormalizedLiveState), &live) + errors.CheckError(err) + + key := kube.ResourceKey{Name: res.Name, Namespace: res.Namespace, Group: res.Group, Kind: res.Kind} + if key.Kind == kube.SecretKind && key.Group == "" { + // Don't bother comparing secrets, argo-cd doesn't have access to k8s secret data + delete(objs, key) + continue + } + if local, ok := objs[key]; ok || live != nil { + if local != nil && !kube.IsCRD(local) { + err = resourceTracking.SetAppInstance(local, argoSettings.AppLabelKey, appName, namespace, argoappv1.TrackingMethod(argoSettings.GetTrackingMethod())) + errors.CheckError(err) + } + + items = append(items, objKeyLiveTarget{key, live, local}) + delete(objs, key) + } + } + for key, local := range objs { + if key.Kind == kube.SecretKind && key.Group == "" { + // Don't bother comparing secrets, argo-cd doesn't have access to k8s secret data + delete(objs, key) + continue + } + items = append(items, objKeyLiveTarget{key, nil, local}) + } + return items +} + +func findandPrintDiff(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, resources *application.ManagedResourcesResponse, argoSettings *settings.Settings, diffOptions *DifferenceOption) bool { + var foundDiffs bool + liveObjs, err := cmdutil.LiveObjects(resources.Items) + errors.CheckError(err) + items := make([]objKeyLiveTarget, 0) + if diffOptions.local != "" { + localObjs := groupObjsByKey(getLocalObjects(ctx, app, proj, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace) + items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) + } else if diffOptions.revision != "" || (diffOptions.revisionSourceMappings != nil) { + var unstructureds []*unstructured.Unstructured + for _, mfst := range diffOptions.res.Manifests { + obj, err := argoappv1.UnmarshalToUnstructured(mfst) + errors.CheckError(err) + unstructureds = append(unstructureds, obj) + } + groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) + items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) + } else if diffOptions.serversideRes != nil { + var unstructureds []*unstructured.Unstructured + for _, mfst := range diffOptions.serversideRes.Manifests { + obj, err := argoappv1.UnmarshalToUnstructured(mfst) + errors.CheckError(err) + unstructureds = append(unstructureds, obj) + } + groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) + items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) + } else { + for i := range resources.Items { + res := resources.Items[i] + var live = &unstructured.Unstructured{} + err := json.Unmarshal([]byte(res.NormalizedLiveState), &live) + errors.CheckError(err) + + var target = &unstructured.Unstructured{} + err = json.Unmarshal([]byte(res.TargetState), &target) + errors.CheckError(err) + + items = append(items, objKeyLiveTarget{kube.NewResourceKey(res.Group, res.Kind, res.Namespace, res.Name), live, target}) + } + } + + for _, item := range items { + if item.target != nil && hook.IsHook(item.target) || item.live != nil && hook.IsHook(item.live) { + continue + } + overrides := make(map[string]argoappv1.ResourceOverride) + for k := range argoSettings.ResourceOverrides { + val := argoSettings.ResourceOverrides[k] + overrides[k] = *val + } + + ignoreAggregatedRoles := false + diffConfig, err := argodiff.NewDiffConfigBuilder(). + WithDiffSettings(app.Spec.IgnoreDifferences, overrides, ignoreAggregatedRoles). + WithTracking(argoSettings.AppLabelKey, argoSettings.TrackingMethod). + WithNoCache(). + Build() + errors.CheckError(err) + diffRes, err := argodiff.StateDiff(item.live, item.target, diffConfig) + errors.CheckError(err) + + if diffRes.Modified || item.target == nil || item.live == nil { + fmt.Printf("\n===== %s/%s %s/%s ======\n", item.key.Group, item.key.Kind, item.key.Namespace, item.key.Name) + var live *unstructured.Unstructured + var target *unstructured.Unstructured + if item.target != nil && item.live != nil { + target = &unstructured.Unstructured{} + live = item.live + err = json.Unmarshal(diffRes.PredictedLive, target) + errors.CheckError(err) + } else { + live = item.live + target = item.target + } + if !foundDiffs { + foundDiffs = true + } + _ = cli.PrintDiff(item.key.Name, live, target) + } + } + return foundDiffs +} // DifferenceOption struct to store diff options type DifferenceOption struct {