From cf63aafb16447eabfde51a79778b7f51595385a2 Mon Sep 17 00:00:00 2001 From: Travis Mattera Date: Mon, 11 Sep 2023 16:37:25 -0700 Subject: [PATCH] Adds an optional `reason` cli flag to the `suspend` command that accepts a reason for why the resource was suspended. Defines the resource metadata annotation key that stores the reason for the resource suspension. Updates the suspend and resume resource patching to add or remove the annotation holding the suspend reason. --- cmd/flux/resume_alert.go | 3 +++ cmd/flux/resume_helmrelease.go | 3 +++ cmd/flux/resume_image_repository.go | 3 +++ cmd/flux/resume_image_updateauto.go | 3 +++ cmd/flux/resume_kustomization.go | 3 +++ cmd/flux/resume_receiver.go | 3 +++ cmd/flux/resume_source_bucket.go | 3 +++ cmd/flux/resume_source_chart.go | 3 +++ cmd/flux/resume_source_git.go | 3 +++ cmd/flux/resume_source_helm.go | 3 +++ cmd/flux/resume_source_oci.go | 3 +++ cmd/flux/suspend.go | 14 +++++++++++--- cmd/flux/suspend_alert.go | 3 ++- cmd/flux/suspend_helmrelease.go | 3 ++- cmd/flux/suspend_image_repository.go | 3 ++- cmd/flux/suspend_image_updateauto.go | 3 ++- cmd/flux/suspend_kustomization.go | 3 ++- cmd/flux/suspend_receiver.go | 3 ++- cmd/flux/suspend_source_bucket.go | 3 ++- cmd/flux/suspend_source_chart.go | 3 ++- cmd/flux/suspend_source_git.go | 3 ++- cmd/flux/suspend_source_helm.go | 3 ++- cmd/flux/suspend_source_oci.go | 3 ++- 23 files changed, 66 insertions(+), 14 deletions(-) diff --git a/cmd/flux/resume_alert.go b/cmd/flux/resume_alert.go index 713aebb3..7ed29221 100644 --- a/cmd/flux/resume_alert.go +++ b/cmd/flux/resume_alert.go @@ -49,6 +49,9 @@ func (obj alertAdapter) getObservedGeneration() int64 { func (obj alertAdapter) setUnsuspended() { obj.Alert.Spec.Suspend = false + if _, ok := obj.Alert.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.Alert.Annotations, SuspendReasonAnnotation) + } } func (obj alertAdapter) successMessage() string { diff --git a/cmd/flux/resume_helmrelease.go b/cmd/flux/resume_helmrelease.go index b058d273..6acbd2b3 100644 --- a/cmd/flux/resume_helmrelease.go +++ b/cmd/flux/resume_helmrelease.go @@ -52,6 +52,9 @@ func (obj helmReleaseAdapter) getObservedGeneration() int64 { func (obj helmReleaseAdapter) setUnsuspended() { obj.HelmRelease.Spec.Suspend = false + if _, ok := obj.HelmRelease.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.HelmRelease.Annotations, SuspendReasonAnnotation) + } } func (obj helmReleaseAdapter) successMessage() string { diff --git a/cmd/flux/resume_image_repository.go b/cmd/flux/resume_image_repository.go index a9ab36cd..b1e49364 100644 --- a/cmd/flux/resume_image_repository.go +++ b/cmd/flux/resume_image_repository.go @@ -48,6 +48,9 @@ func (obj imageRepositoryAdapter) getObservedGeneration() int64 { func (obj imageRepositoryAdapter) setUnsuspended() { obj.ImageRepository.Spec.Suspend = false + if _, ok := obj.ImageRepository.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.ImageRepository.Annotations, SuspendReasonAnnotation) + } } func (a imageRepositoryListAdapter) resumeItem(i int) resumable { diff --git a/cmd/flux/resume_image_updateauto.go b/cmd/flux/resume_image_updateauto.go index d50fddf7..d0131c98 100644 --- a/cmd/flux/resume_image_updateauto.go +++ b/cmd/flux/resume_image_updateauto.go @@ -44,6 +44,9 @@ func init() { func (obj imageUpdateAutomationAdapter) setUnsuspended() { obj.ImageUpdateAutomation.Spec.Suspend = false + if _, ok := obj.ImageUpdateAutomation.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.ImageUpdateAutomation.Annotations, SuspendReasonAnnotation) + } } func (obj imageUpdateAutomationAdapter) getObservedGeneration() int64 { diff --git a/cmd/flux/resume_kustomization.go b/cmd/flux/resume_kustomization.go index a03aed62..ab8ed7dc 100644 --- a/cmd/flux/resume_kustomization.go +++ b/cmd/flux/resume_kustomization.go @@ -52,6 +52,9 @@ func (obj kustomizationAdapter) getObservedGeneration() int64 { func (obj kustomizationAdapter) setUnsuspended() { obj.Kustomization.Spec.Suspend = false + if _, ok := obj.Kustomization.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.Kustomization.Annotations, SuspendReasonAnnotation) + } } func (obj kustomizationAdapter) successMessage() string { diff --git a/cmd/flux/resume_receiver.go b/cmd/flux/resume_receiver.go index c99bd755..1659c6bf 100644 --- a/cmd/flux/resume_receiver.go +++ b/cmd/flux/resume_receiver.go @@ -49,6 +49,9 @@ func (obj receiverAdapter) getObservedGeneration() int64 { func (obj receiverAdapter) setUnsuspended() { obj.Receiver.Spec.Suspend = false + if _, ok := obj.Receiver.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.Receiver.Annotations, SuspendReasonAnnotation) + } } func (obj receiverAdapter) successMessage() string { diff --git a/cmd/flux/resume_source_bucket.go b/cmd/flux/resume_source_bucket.go index ea1fe37d..de0ec2b6 100644 --- a/cmd/flux/resume_source_bucket.go +++ b/cmd/flux/resume_source_bucket.go @@ -48,6 +48,9 @@ func (obj bucketAdapter) getObservedGeneration() int64 { func (obj bucketAdapter) setUnsuspended() { obj.Bucket.Spec.Suspend = false + if _, ok := obj.Bucket.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.Bucket.Annotations, SuspendReasonAnnotation) + } } func (a bucketListAdapter) resumeItem(i int) resumable { diff --git a/cmd/flux/resume_source_chart.go b/cmd/flux/resume_source_chart.go index 6322f06f..beb3ed97 100644 --- a/cmd/flux/resume_source_chart.go +++ b/cmd/flux/resume_source_chart.go @@ -50,6 +50,9 @@ func (obj helmChartAdapter) getObservedGeneration() int64 { func (obj helmChartAdapter) setUnsuspended() { obj.HelmChart.Spec.Suspend = false + if _, ok := obj.HelmChart.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.HelmChart.Annotations, SuspendReasonAnnotation) + } } func (obj helmChartAdapter) successMessage() string { diff --git a/cmd/flux/resume_source_git.go b/cmd/flux/resume_source_git.go index 751714a4..23289870 100644 --- a/cmd/flux/resume_source_git.go +++ b/cmd/flux/resume_source_git.go @@ -48,6 +48,9 @@ func (obj gitRepositoryAdapter) getObservedGeneration() int64 { func (obj gitRepositoryAdapter) setUnsuspended() { obj.GitRepository.Spec.Suspend = false + if _, ok := obj.GitRepository.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.GitRepository.Annotations, SuspendReasonAnnotation) + } } func (a gitRepositoryListAdapter) resumeItem(i int) resumable { diff --git a/cmd/flux/resume_source_helm.go b/cmd/flux/resume_source_helm.go index 0ac641eb..54531cb8 100644 --- a/cmd/flux/resume_source_helm.go +++ b/cmd/flux/resume_source_helm.go @@ -48,6 +48,9 @@ func (obj helmRepositoryAdapter) getObservedGeneration() int64 { func (obj helmRepositoryAdapter) setUnsuspended() { obj.HelmRepository.Spec.Suspend = false + if _, ok := obj.HelmRepository.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.HelmRepository.Annotations, SuspendReasonAnnotation) + } } func (a helmRepositoryListAdapter) resumeItem(i int) resumable { diff --git a/cmd/flux/resume_source_oci.go b/cmd/flux/resume_source_oci.go index 04b20a4b..db40ec05 100644 --- a/cmd/flux/resume_source_oci.go +++ b/cmd/flux/resume_source_oci.go @@ -48,6 +48,9 @@ func (obj ociRepositoryAdapter) getObservedGeneration() int64 { func (obj ociRepositoryAdapter) setUnsuspended() { obj.OCIRepository.Spec.Suspend = false + if _, ok := obj.OCIRepository.Annotations[SuspendReasonAnnotation]; ok { + delete(obj.OCIRepository.Annotations, SuspendReasonAnnotation) + } } func (a ociRepositoryListAdapter) resumeItem(i int) resumable { diff --git a/cmd/flux/suspend.go b/cmd/flux/suspend.go index e0023c7e..2ac84f94 100644 --- a/cmd/flux/suspend.go +++ b/cmd/flux/suspend.go @@ -34,7 +34,8 @@ var suspendCmd = &cobra.Command{ } type SuspendFlags struct { - all bool + all bool + reason string } var suspendArgs SuspendFlags @@ -42,6 +43,8 @@ var suspendArgs SuspendFlags func init() { suspendCmd.PersistentFlags().BoolVarP(&suspendArgs.all, "all", "", false, "suspend all resources in that namespace") + suspendCmd.PersistentFlags().StringVarP(&suspendArgs.reason, "reason", "r", "suspended", + "set a reason for why the resource is suspended") rootCmd.AddCommand(suspendCmd) } @@ -49,7 +52,7 @@ type suspendable interface { adapter copyable isSuspended() bool - setSuspended() + setSuspended(reason string) } type suspendCommand struct { @@ -76,6 +79,7 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error { return err } + // in case of all, get all in namespace and patch 'em if len(args) < 1 && suspendArgs.all { listOpts := []client.ListOption{ client.InNamespace(*kubeconfigArgs.Namespace), @@ -88,6 +92,7 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error { return nil } + // when not all, patch list of args processed := make(map[string]struct{}, len(args)) for _, arg := range args { if _, has := processed[arg]; has { @@ -130,7 +135,7 @@ func (suspend suspendCommand) patch(ctx context.Context, kubeClient client.WithW obj := suspend.list.item(i) patch := client.MergeFrom(obj.deepCopyClientObject()) - obj.setSuspended() + obj.setSuspended(suspendArgs.reason) if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil { return err } @@ -140,3 +145,6 @@ func (suspend suspendCommand) patch(ctx context.Context, kubeClient client.WithW return nil } + +// SuspendReasonAnnotation is the metadata key used to store the reason for resource suspension +const SuspendReasonAnnotation string = "suspend.fluxcd.io/reason" diff --git a/cmd/flux/suspend_alert.go b/cmd/flux/suspend_alert.go index 17cdd801..87262765 100644 --- a/cmd/flux/suspend_alert.go +++ b/cmd/flux/suspend_alert.go @@ -47,8 +47,9 @@ func (obj alertAdapter) isSuspended() bool { return obj.Alert.Spec.Suspend } -func (obj alertAdapter) setSuspended() { +func (obj alertAdapter) setSuspended(reason string) { obj.Alert.Spec.Suspend = true + obj.Alert.Annotations[SuspendReasonAnnotation] = reason } func (a alertListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_helmrelease.go b/cmd/flux/suspend_helmrelease.go index 5872c8b4..88d78742 100644 --- a/cmd/flux/suspend_helmrelease.go +++ b/cmd/flux/suspend_helmrelease.go @@ -48,8 +48,9 @@ func (obj helmReleaseAdapter) isSuspended() bool { return obj.HelmRelease.Spec.Suspend } -func (obj helmReleaseAdapter) setSuspended() { +func (obj helmReleaseAdapter) setSuspended(reason string) { obj.HelmRelease.Spec.Suspend = true + obj.HelmRelease.Annotations[SuspendReasonAnnotation] = reason } func (a helmReleaseListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_image_repository.go b/cmd/flux/suspend_image_repository.go index c6e562d1..3b9f901c 100644 --- a/cmd/flux/suspend_image_repository.go +++ b/cmd/flux/suspend_image_repository.go @@ -47,8 +47,9 @@ func (obj imageRepositoryAdapter) isSuspended() bool { return obj.ImageRepository.Spec.Suspend } -func (obj imageRepositoryAdapter) setSuspended() { +func (obj imageRepositoryAdapter) setSuspended(reason string) { obj.ImageRepository.Spec.Suspend = true + obj.ImageRepository.Annotations[SuspendReasonAnnotation] = reason } func (a imageRepositoryListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_image_updateauto.go b/cmd/flux/suspend_image_updateauto.go index 1c8f11ef..5649fa4e 100644 --- a/cmd/flux/suspend_image_updateauto.go +++ b/cmd/flux/suspend_image_updateauto.go @@ -47,8 +47,9 @@ func (update imageUpdateAutomationAdapter) isSuspended() bool { return update.ImageUpdateAutomation.Spec.Suspend } -func (update imageUpdateAutomationAdapter) setSuspended() { +func (update imageUpdateAutomationAdapter) setSuspended(reason string) { update.ImageUpdateAutomation.Spec.Suspend = true + update.ImageUpdateAutomation.Annotations[SuspendReasonAnnotation] = reason } func (a imageUpdateAutomationListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_kustomization.go b/cmd/flux/suspend_kustomization.go index ac6c72e1..7689c904 100644 --- a/cmd/flux/suspend_kustomization.go +++ b/cmd/flux/suspend_kustomization.go @@ -48,8 +48,9 @@ func (obj kustomizationAdapter) isSuspended() bool { return obj.Kustomization.Spec.Suspend } -func (obj kustomizationAdapter) setSuspended() { +func (obj kustomizationAdapter) setSuspended(reason string) { obj.Kustomization.Spec.Suspend = true + obj.Kustomization.Annotations[SuspendReasonAnnotation] = reason } func (a kustomizationListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_receiver.go b/cmd/flux/suspend_receiver.go index 7f2e6dd7..b512238b 100644 --- a/cmd/flux/suspend_receiver.go +++ b/cmd/flux/suspend_receiver.go @@ -47,8 +47,9 @@ func (obj receiverAdapter) isSuspended() bool { return obj.Receiver.Spec.Suspend } -func (obj receiverAdapter) setSuspended() { +func (obj receiverAdapter) setSuspended(reason string) { obj.Receiver.Spec.Suspend = true + obj.Receiver.Annotations[SuspendReasonAnnotation] = reason } func (a receiverListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_source_bucket.go b/cmd/flux/suspend_source_bucket.go index 7fdcfced..1a625f3f 100644 --- a/cmd/flux/suspend_source_bucket.go +++ b/cmd/flux/suspend_source_bucket.go @@ -47,8 +47,9 @@ func (obj bucketAdapter) isSuspended() bool { return obj.Bucket.Spec.Suspend } -func (obj bucketAdapter) setSuspended() { +func (obj bucketAdapter) setSuspended(reason string) { obj.Bucket.Spec.Suspend = true + obj.Bucket.Annotations[SuspendReasonAnnotation] = reason } func (a bucketListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_source_chart.go b/cmd/flux/suspend_source_chart.go index e91327e8..aeccf034 100644 --- a/cmd/flux/suspend_source_chart.go +++ b/cmd/flux/suspend_source_chart.go @@ -47,8 +47,9 @@ func (obj helmChartAdapter) isSuspended() bool { return obj.HelmChart.Spec.Suspend } -func (obj helmChartAdapter) setSuspended() { +func (obj helmChartAdapter) setSuspended(reason string) { obj.HelmChart.Spec.Suspend = true + obj.HelmChart.Annotations[SuspendReasonAnnotation] = reason } func (a helmChartListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_source_git.go b/cmd/flux/suspend_source_git.go index 4decf796..a40cdb05 100644 --- a/cmd/flux/suspend_source_git.go +++ b/cmd/flux/suspend_source_git.go @@ -47,8 +47,9 @@ func (obj gitRepositoryAdapter) isSuspended() bool { return obj.GitRepository.Spec.Suspend } -func (obj gitRepositoryAdapter) setSuspended() { +func (obj gitRepositoryAdapter) setSuspended(reason string) { obj.GitRepository.Spec.Suspend = true + obj.GitRepository.Annotations[SuspendReasonAnnotation] = reason } func (a gitRepositoryListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_source_helm.go b/cmd/flux/suspend_source_helm.go index 22598c64..6b7a7669 100644 --- a/cmd/flux/suspend_source_helm.go +++ b/cmd/flux/suspend_source_helm.go @@ -47,8 +47,9 @@ func (obj helmRepositoryAdapter) isSuspended() bool { return obj.HelmRepository.Spec.Suspend } -func (obj helmRepositoryAdapter) setSuspended() { +func (obj helmRepositoryAdapter) setSuspended(reason string) { obj.HelmRepository.Spec.Suspend = true + obj.HelmRepository.Annotations[SuspendReasonAnnotation] = reason } func (a helmRepositoryListAdapter) item(i int) suspendable { diff --git a/cmd/flux/suspend_source_oci.go b/cmd/flux/suspend_source_oci.go index 3b8e36d6..e756b06f 100644 --- a/cmd/flux/suspend_source_oci.go +++ b/cmd/flux/suspend_source_oci.go @@ -47,8 +47,9 @@ func (obj ociRepositoryAdapter) isSuspended() bool { return obj.OCIRepository.Spec.Suspend } -func (obj ociRepositoryAdapter) setSuspended() { +func (obj ociRepositoryAdapter) setSuspended(reason string) { obj.OCIRepository.Spec.Suspend = true + obj.OCIRepository.Annotations[SuspendReasonAnnotation] = reason } func (a ociRepositoryListAdapter) item(i int) suspendable {