From 9f537718324bdf9762453dfeec6cae5551cca936 Mon Sep 17 00:00:00 2001 From: Jan Schumacher Date: Sat, 18 May 2019 12:19:22 +0200 Subject: [PATCH] - added dry-run-garbage-collection arg - added .Values.syncGarbageCollection.dry --- chart/flux/README.md | 1 + chart/flux/templates/deployment.yaml | 4 +++- chart/flux/values.yaml | 1 + cluster/kubernetes/kubernetes.go | 2 ++ cluster/kubernetes/sync.go | 20 +++++++++++++------- cluster/kubernetes/sync_test.go | 17 +++++++++++++++++ cmd/fluxd/main.go | 20 +++++++++++--------- 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/chart/flux/README.md b/chart/flux/README.md index aa6467435e..f6b361a958 100755 --- a/chart/flux/README.md +++ b/chart/flux/README.md @@ -277,6 +277,7 @@ The following tables lists the configurable parameters of the Weave Flux chart a | `kube.config` | [See values.yaml](/chart/flux/values.yaml#L151-L165) | Override for kubectl default config in the Flux pod(s). | `prometheus.enabled` | `false` | If enabled, adds prometheus annotations to Flux and helmOperator pod(s) | `syncGarbageCollection.enabled` | `false` | If enabled, fluxd will delete resources that it created, but are no longer present in git (experimental, see [garbage collection](/site/garbagecollection.md)) +| `syncGarbageCollection.dry` | `false` | If enabled, fluxd won't delete any resources, but log the garbage collection output (experimental, see [garbage collection](/site/garbagecollection.md)) Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example: diff --git a/chart/flux/templates/deployment.yaml b/chart/flux/templates/deployment.yaml index b08e77803d..c216d74f6f 100644 --- a/chart/flux/templates/deployment.yaml +++ b/chart/flux/templates/deployment.yaml @@ -191,8 +191,10 @@ spec: - --connect=wss://cloud.weave.works/api/flux - --token={{ .Values.token }} {{- end }} - {{- if .Values.syncGarbageCollection.enabled }} + {{- if and .Values.syncGarbageCollection.enabled (not .Values.syncGarbageCollection.dry) }} - --sync-garbage-collection={{ .Values.syncGarbageCollection.enabled }} + {{- else if .Values.syncGarbageCollection.dry }} + - --sync-garbage-collection-dry={{ .Values.syncGarbageCollection.dry }} {{- end }} {{- if .Values.additionalArgs }} {{ toYaml .Values.additionalArgs | indent 10 }} diff --git a/chart/flux/values.yaml b/chart/flux/values.yaml index ddd4d6c586..3ff382857a 100644 --- a/chart/flux/values.yaml +++ b/chart/flux/values.yaml @@ -231,6 +231,7 @@ prometheus: syncGarbageCollection: enabled: false + dry: false # Add your own init container or uncomment and modify the given example. initContainers: {} diff --git a/cluster/kubernetes/kubernetes.go b/cluster/kubernetes/kubernetes.go index dbbd4d715b..300dc49983 100644 --- a/cluster/kubernetes/kubernetes.go +++ b/cluster/kubernetes/kubernetes.go @@ -85,6 +85,8 @@ func isAddon(obj k8sObject) bool { type Cluster struct { // Do garbage collection when syncing resources GC bool + // dry run garbage collection without syncing + DryGC bool client ExtendedClient applier Applier diff --git a/cluster/kubernetes/sync.go b/cluster/kubernetes/sync.go index 364cd6feac..23ea5cf52b 100644 --- a/cluster/kubernetes/sync.go +++ b/cluster/kubernetes/sync.go @@ -107,8 +107,8 @@ func (c *Cluster) Sync(syncSet cluster.SyncSet) error { } c.muSyncErrors.RUnlock() - if c.GC { - deleteErrs, gcFailure := c.collectGarbage(syncSet, checksums, logger) + if c.GC || c.DryGC { + deleteErrs, gcFailure := c.collectGarbage(syncSet, checksums, logger, c.DryGC) if gcFailure != nil { return gcFailure } @@ -129,7 +129,8 @@ func (c *Cluster) Sync(syncSet cluster.SyncSet) error { func (c *Cluster) collectGarbage( syncSet cluster.SyncSet, checksums map[string]string, - logger log.Logger) (cluster.SyncError, error) { + logger log.Logger, + dryRun bool) (cluster.SyncError, error) { orphanedResources := makeChangeSet() @@ -142,12 +143,17 @@ func (c *Cluster) collectGarbage( actual := res.GetChecksum() expected, ok := checksums[resourceID] + collectGarbage := !ok && !dryRun + onlyLogging := !ok && dryRun + skipResource := actual != expected switch { - case !ok: // was not recorded as having been staged for application - c.logger.Log("info", "cluster resource not in resources to be synced; deleting", "resource", resourceID) + case collectGarbage: + c.logger.Log("info", "Garbage-Collection: deleting resources; cluster resource not in resources to be synced", "resource", resourceID) orphanedResources.stage("delete", res.ResourceID(), "", res.IdentifyingBytes()) - case actual != expected: - c.logger.Log("warning", "resource to be synced has not been updated; skipping", "resource", resourceID) + case onlyLogging: // was not recorded as having been staged for application + c.logger.Log("info", "Garbage-Collection: dry-run, no deletion; cluster resource not in resources to be synced", "resource", resourceID) + case skipResource: + c.logger.Log("warning", "Garbage-Collection: resource to be synced has not been updated; skipping", "resource", resourceID) continue default: // The checksum is the same, indicating that it was diff --git a/cluster/kubernetes/sync_test.go b/cluster/kubernetes/sync_test.go index 3bd7803871..56d46d50d8 100644 --- a/cluster/kubernetes/sync_test.go +++ b/cluster/kubernetes/sync_test.go @@ -436,6 +436,23 @@ metadata: test(t, kube, "", "", false) }) + t.Run("sync adds and GCs dry run", func(t *testing.T) { + kube, _, cancel := setup(t) + defer cancel() + + // without GC on, resources persist if they are not mentioned in subsequent syncs. + test(t, kube, "", "", false) + test(t, kube, ns1+defs1, ns1+defs1, false) + test(t, kube, ns1+defs1+defs2, ns1+defs1+defs2, false) + test(t, kube, ns3+defs3, ns1+defs1+defs2+ns3+defs3, false) + + // with GC dry run the collect garbage routine is running but only logging results with out collecting any resources + kube.DryGC = true + test(t, kube, ns1+defs2+ns3+defs3, ns1+defs1+defs2+ns3+defs3, false) + test(t, kube, ns1+defs1+defs2, ns1+defs1+defs2+ns3+defs3, false) + test(t, kube, "", ns1+defs1+defs2+ns3+defs3, false) + }) + t.Run("sync won't incorrectly delete non-namespaced resources", func(t *testing.T) { kube, _, cancel := setup(t) defer cancel() diff --git a/cmd/fluxd/main.go b/cmd/fluxd/main.go index 8d7a4e16f6..57a4cbedf3 100644 --- a/cmd/fluxd/main.go +++ b/cmd/fluxd/main.go @@ -127,6 +127,7 @@ func main() { // syncing syncInterval = fs.Duration("sync-interval", 5*time.Minute, "apply config in git to cluster at least this often, even if there are no new commits") syncGC = fs.Bool("sync-garbage-collection", false, "experimental; delete resources that were created by fluxd, but are no longer in the git repo") + dryGC = fs.Bool("sync-garbage-collection-dry", false, "experimental; only log what would be garbage collected, rather than deleting. Implies --sync-garbage-collection") // registry memcachedHostname = fs.String("memcached-hostname", "memcached", "hostname for memcached service.") @@ -370,6 +371,7 @@ func main() { allowedNamespaces := append(*k8sNamespaceWhitelist, *k8sAllowNamespace...) k8sInst := kubernetes.NewCluster(client, kubectlApplier, sshKeyRing, logger, allowedNamespaces, *registryExcludeImage) k8sInst.GC = *syncGC + k8sInst.DryGC = *dryGC if err := k8sInst.Ping(); err != nil { logger.Log("ping", err) @@ -485,15 +487,15 @@ func main() { gitRemote := git.Remote{URL: *gitURL} gitConfig := git.Config{ - Paths: *gitPath, - Branch: *gitBranch, - SyncTag: *gitSyncTag, - NotesRef: *gitNotesRef, - UserName: *gitUser, - UserEmail: *gitEmail, - SigningKey: *gitSigningKey, - SetAuthor: *gitSetAuthor, - SkipMessage: *gitSkipMessage, + Paths: *gitPath, + Branch: *gitBranch, + SyncTag: *gitSyncTag, + NotesRef: *gitNotesRef, + UserName: *gitUser, + UserEmail: *gitEmail, + SigningKey: *gitSigningKey, + SetAuthor: *gitSetAuthor, + SkipMessage: *gitSkipMessage, } repo := git.NewRepo(gitRemote, git.PollInterval(*gitPollInterval), git.Timeout(*gitTimeout), git.Branch(*gitBranch))