diff --git a/cmd/flux/diff_kustomization_test.go b/cmd/flux/diff_kustomization_test.go index 69577dd0..46ef2b44 100644 --- a/cmd/flux/diff_kustomization_test.go +++ b/cmd/flux/diff_kustomization_test.go @@ -270,3 +270,36 @@ func createObjectFromFile(objectFile string, templateValues map[string]string, t return clientObjects } + +// TestDiffKustomizationDriftIgnoreRules tests `flux diff ks` with drift ignore +// rules. A service with a drifted port is pre-applied to the cluster, and the +// kustomization specifies driftIgnoreRules that ignore /spec/ports on Services. +// The diff should not show the service as drifted. +func TestDiffKustomizationDriftIgnoreRules(t *testing.T) { + tmpl := map[string]string{ + "fluxns": allocateNamespace("flux-system"), + } + setupTestNamespace(tmpl["fluxns"], t) + + b, _ := build.NewBuilder("podinfo", "", build.WithClientConfig(kubeconfigArgs, kubeclientOptions)) + resourceManager, err := b.Manager() + if err != nil { + t.Fatal(err) + } + + // Pre-apply the drifted service (port 9899 instead of 9898) without Flux labels. + if _, err := resourceManager.ApplyAll(context.Background(), createObjectFromFile("./testdata/diff-kustomization/drifted-service-no-labels.yaml", tmpl, t), ssa.DefaultApplyOptions()); err != nil { + t.Fatal(err) + } + + cmd := cmdTestCase{ + args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false " + + "--kustomization-file ./testdata/diff-kustomization/flux-kustomization-drift-ignore.yaml " + + "--ignore-not-found" + + " -n " + tmpl["fluxns"], + assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drift-ignore.golden"), + } + cmd.runTestCmd(t) + + testEnv.DeleteObjectFile("./testdata/diff-kustomization/drifted-service-no-labels.yaml", tmpl, t) +} diff --git a/cmd/flux/testdata/diff-kustomization/diff-with-drift-ignore.golden b/cmd/flux/testdata/diff-kustomization/diff-with-drift-ignore.golden new file mode 100644 index 00000000..67b137de --- /dev/null +++ b/cmd/flux/testdata/diff-kustomization/diff-with-drift-ignore.golden @@ -0,0 +1,14 @@ +► Deployment/default/podinfo created +► HorizontalPodAutoscaler/default/podinfo created +► Service/default/podinfo drifted + +metadata ++ one map entry added: + labels: + kustomize.toolkit.fluxcd.io/name: podinfo + kustomize.toolkit.fluxcd.io/namespace: + +► Secret/default/docker-secret created +► Secret/default/secret-basic-auth-stringdata created +► Secret/default/podinfo-token-77t89m9b67 created +► Secret/default/db-user-pass-bkbd782d2c created diff --git a/cmd/flux/testdata/diff-kustomization/drifted-service-no-labels.yaml b/cmd/flux/testdata/diff-kustomization/drifted-service-no-labels.yaml new file mode 100644 index 00000000..539a99db --- /dev/null +++ b/cmd/flux/testdata/diff-kustomization/drifted-service-no-labels.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: podinfo + namespace: default +spec: + type: ClusterIP + selector: + app: podinfo + ports: + - name: http + port: 9899 + protocol: TCP + targetPort: http + - port: 9999 + targetPort: grpc + protocol: TCP + name: grpc diff --git a/cmd/flux/testdata/diff-kustomization/flux-kustomization-drift-ignore.yaml b/cmd/flux/testdata/diff-kustomization/flux-kustomization-drift-ignore.yaml new file mode 100644 index 00000000..157b56b5 --- /dev/null +++ b/cmd/flux/testdata/diff-kustomization/flux-kustomization-drift-ignore.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: podinfo +spec: + interval: 5m0s + path: ./kustomize + force: true + prune: true + sourceRef: + kind: GitRepository + name: podinfo + targetNamespace: default + ignore: + - paths: + - "/spec/ports" + target: + kind: Service diff --git a/internal/build/diff.go b/internal/build/diff.go index 72063d9f..ce6800ed 100644 --- a/internal/build/diff.go +++ b/internal/build/diff.go @@ -41,6 +41,7 @@ import ( "github.com/fluxcd/cli-utils/pkg/object" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" "github.com/fluxcd/pkg/ssa" + "github.com/fluxcd/pkg/ssa/jsondiff" "github.com/fluxcd/pkg/ssa/normalize" ssautil "github.com/fluxcd/pkg/ssa/utils" @@ -94,6 +95,28 @@ func (b *Builder) diff() (string, bool, error) { ctx, cancel := context.WithTimeout(context.Background(), b.timeout) defer cancel() + // Convert drift ignore rules from the Kustomization spec to jsondiff.IgnoreRule. + var driftIgnoreRules []jsondiff.IgnoreRule + if rules := b.kustomization.Spec.Ignore; len(rules) > 0 { + driftIgnoreRules = make([]jsondiff.IgnoreRule, len(rules)) + for i, rule := range rules { + driftIgnoreRules[i] = jsondiff.IgnoreRule{ + Paths: rule.Paths, + } + if rule.Target != nil { + driftIgnoreRules[i].Selector = &jsondiff.Selector{ + Group: rule.Target.Group, + Version: rule.Target.Version, + Kind: rule.Target.Kind, + Name: rule.Target.Name, + Namespace: rule.Target.Namespace, + AnnotationSelector: rule.Target.AnnotationSelector, + LabelSelector: rule.Target.LabelSelector, + } + } + } + } + var diffErrs []error // create an inventory of objects to be reconciled newInventory := newInventory() @@ -109,6 +132,7 @@ func (b *Builder) diff() (string, bool, error) { ForceSelector: map[string]string{ "kustomize.toolkit.fluxcd.io/force": "enabled", }, + DriftIgnoreRules: driftIgnoreRules, } change, liveObject, mergedObject, err := resourceManager.Diff(ctx, obj, diffOptions) if err != nil {