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.

Signed-off-by: Travis Mattera <travis@mattera.io>
This commit is contained in:
Travis Mattera 2023-09-11 19:53:34 -07:00
parent 0d18dc128a
commit 479fc3cd3b
No known key found for this signature in database
GPG key ID: 6E9A8A6A0A74CA52
23 changed files with 66 additions and 14 deletions

View file

@ -49,6 +49,9 @@ func (obj alertAdapter) getObservedGeneration() int64 {
func (obj alertAdapter) setUnsuspended() { func (obj alertAdapter) setUnsuspended() {
obj.Alert.Spec.Suspend = false obj.Alert.Spec.Suspend = false
if _, ok := obj.Alert.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.Alert.Annotations, SuspendReasonAnnotation)
}
} }
func (obj alertAdapter) successMessage() string { func (obj alertAdapter) successMessage() string {

View file

@ -52,6 +52,9 @@ func (obj helmReleaseAdapter) getObservedGeneration() int64 {
func (obj helmReleaseAdapter) setUnsuspended() { func (obj helmReleaseAdapter) setUnsuspended() {
obj.HelmRelease.Spec.Suspend = false obj.HelmRelease.Spec.Suspend = false
if _, ok := obj.HelmRelease.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.HelmRelease.Annotations, SuspendReasonAnnotation)
}
} }
func (obj helmReleaseAdapter) successMessage() string { func (obj helmReleaseAdapter) successMessage() string {

View file

@ -48,6 +48,9 @@ func (obj imageRepositoryAdapter) getObservedGeneration() int64 {
func (obj imageRepositoryAdapter) setUnsuspended() { func (obj imageRepositoryAdapter) setUnsuspended() {
obj.ImageRepository.Spec.Suspend = false obj.ImageRepository.Spec.Suspend = false
if _, ok := obj.ImageRepository.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.ImageRepository.Annotations, SuspendReasonAnnotation)
}
} }
func (a imageRepositoryListAdapter) resumeItem(i int) resumable { func (a imageRepositoryListAdapter) resumeItem(i int) resumable {

View file

@ -44,6 +44,9 @@ func init() {
func (obj imageUpdateAutomationAdapter) setUnsuspended() { func (obj imageUpdateAutomationAdapter) setUnsuspended() {
obj.ImageUpdateAutomation.Spec.Suspend = false obj.ImageUpdateAutomation.Spec.Suspend = false
if _, ok := obj.ImageUpdateAutomation.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.ImageUpdateAutomation.Annotations, SuspendReasonAnnotation)
}
} }
func (obj imageUpdateAutomationAdapter) getObservedGeneration() int64 { func (obj imageUpdateAutomationAdapter) getObservedGeneration() int64 {

View file

@ -52,6 +52,9 @@ func (obj kustomizationAdapter) getObservedGeneration() int64 {
func (obj kustomizationAdapter) setUnsuspended() { func (obj kustomizationAdapter) setUnsuspended() {
obj.Kustomization.Spec.Suspend = false obj.Kustomization.Spec.Suspend = false
if _, ok := obj.Kustomization.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.Kustomization.Annotations, SuspendReasonAnnotation)
}
} }
func (obj kustomizationAdapter) successMessage() string { func (obj kustomizationAdapter) successMessage() string {

View file

@ -49,6 +49,9 @@ func (obj receiverAdapter) getObservedGeneration() int64 {
func (obj receiverAdapter) setUnsuspended() { func (obj receiverAdapter) setUnsuspended() {
obj.Receiver.Spec.Suspend = false obj.Receiver.Spec.Suspend = false
if _, ok := obj.Receiver.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.Receiver.Annotations, SuspendReasonAnnotation)
}
} }
func (obj receiverAdapter) successMessage() string { func (obj receiverAdapter) successMessage() string {

View file

@ -48,6 +48,9 @@ func (obj bucketAdapter) getObservedGeneration() int64 {
func (obj bucketAdapter) setUnsuspended() { func (obj bucketAdapter) setUnsuspended() {
obj.Bucket.Spec.Suspend = false obj.Bucket.Spec.Suspend = false
if _, ok := obj.Bucket.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.Bucket.Annotations, SuspendReasonAnnotation)
}
} }
func (a bucketListAdapter) resumeItem(i int) resumable { func (a bucketListAdapter) resumeItem(i int) resumable {

View file

@ -50,6 +50,9 @@ func (obj helmChartAdapter) getObservedGeneration() int64 {
func (obj helmChartAdapter) setUnsuspended() { func (obj helmChartAdapter) setUnsuspended() {
obj.HelmChart.Spec.Suspend = false obj.HelmChart.Spec.Suspend = false
if _, ok := obj.HelmChart.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.HelmChart.Annotations, SuspendReasonAnnotation)
}
} }
func (obj helmChartAdapter) successMessage() string { func (obj helmChartAdapter) successMessage() string {

View file

@ -48,6 +48,9 @@ func (obj gitRepositoryAdapter) getObservedGeneration() int64 {
func (obj gitRepositoryAdapter) setUnsuspended() { func (obj gitRepositoryAdapter) setUnsuspended() {
obj.GitRepository.Spec.Suspend = false obj.GitRepository.Spec.Suspend = false
if _, ok := obj.GitRepository.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.GitRepository.Annotations, SuspendReasonAnnotation)
}
} }
func (a gitRepositoryListAdapter) resumeItem(i int) resumable { func (a gitRepositoryListAdapter) resumeItem(i int) resumable {

View file

@ -48,6 +48,9 @@ func (obj helmRepositoryAdapter) getObservedGeneration() int64 {
func (obj helmRepositoryAdapter) setUnsuspended() { func (obj helmRepositoryAdapter) setUnsuspended() {
obj.HelmRepository.Spec.Suspend = false obj.HelmRepository.Spec.Suspend = false
if _, ok := obj.HelmRepository.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.HelmRepository.Annotations, SuspendReasonAnnotation)
}
} }
func (a helmRepositoryListAdapter) resumeItem(i int) resumable { func (a helmRepositoryListAdapter) resumeItem(i int) resumable {

View file

@ -48,6 +48,9 @@ func (obj ociRepositoryAdapter) getObservedGeneration() int64 {
func (obj ociRepositoryAdapter) setUnsuspended() { func (obj ociRepositoryAdapter) setUnsuspended() {
obj.OCIRepository.Spec.Suspend = false obj.OCIRepository.Spec.Suspend = false
if _, ok := obj.OCIRepository.Annotations[SuspendReasonAnnotation]; ok {
delete(obj.OCIRepository.Annotations, SuspendReasonAnnotation)
}
} }
func (a ociRepositoryListAdapter) resumeItem(i int) resumable { func (a ociRepositoryListAdapter) resumeItem(i int) resumable {

View file

@ -34,7 +34,8 @@ var suspendCmd = &cobra.Command{
} }
type SuspendFlags struct { type SuspendFlags struct {
all bool all bool
reason string
} }
var suspendArgs SuspendFlags var suspendArgs SuspendFlags
@ -42,6 +43,8 @@ var suspendArgs SuspendFlags
func init() { func init() {
suspendCmd.PersistentFlags().BoolVarP(&suspendArgs.all, "all", "", false, suspendCmd.PersistentFlags().BoolVarP(&suspendArgs.all, "all", "", false,
"suspend all resources in that namespace") "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) rootCmd.AddCommand(suspendCmd)
} }
@ -49,7 +52,7 @@ type suspendable interface {
adapter adapter
copyable copyable
isSuspended() bool isSuspended() bool
setSuspended() setSuspended(reason string)
} }
type suspendCommand struct { type suspendCommand struct {
@ -76,6 +79,7 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
return err return err
} }
// in case of all, get all in namespace and patch 'em
if len(args) < 1 && suspendArgs.all { if len(args) < 1 && suspendArgs.all {
listOpts := []client.ListOption{ listOpts := []client.ListOption{
client.InNamespace(*kubeconfigArgs.Namespace), client.InNamespace(*kubeconfigArgs.Namespace),
@ -88,6 +92,7 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
return nil return nil
} }
// when not all, patch list of args
processed := make(map[string]struct{}, len(args)) processed := make(map[string]struct{}, len(args))
for _, arg := range args { for _, arg := range args {
if _, has := processed[arg]; has { if _, has := processed[arg]; has {
@ -130,7 +135,7 @@ func (suspend suspendCommand) patch(ctx context.Context, kubeClient client.WithW
obj := suspend.list.item(i) obj := suspend.list.item(i)
patch := client.MergeFrom(obj.deepCopyClientObject()) patch := client.MergeFrom(obj.deepCopyClientObject())
obj.setSuspended() obj.setSuspended(suspendArgs.reason)
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil { if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
return err return err
} }
@ -140,3 +145,6 @@ func (suspend suspendCommand) patch(ctx context.Context, kubeClient client.WithW
return nil return nil
} }
// SuspendReasonAnnotation is the metadata key used to store the reason for resource suspension
const SuspendReasonAnnotation string = "suspend.fluxcd.io/reason"

View file

@ -47,8 +47,9 @@ func (obj alertAdapter) isSuspended() bool {
return obj.Alert.Spec.Suspend return obj.Alert.Spec.Suspend
} }
func (obj alertAdapter) setSuspended() { func (obj alertAdapter) setSuspended(reason string) {
obj.Alert.Spec.Suspend = true obj.Alert.Spec.Suspend = true
obj.Alert.Annotations[SuspendReasonAnnotation] = reason
} }
func (a alertListAdapter) item(i int) suspendable { func (a alertListAdapter) item(i int) suspendable {

View file

@ -48,8 +48,9 @@ func (obj helmReleaseAdapter) isSuspended() bool {
return obj.HelmRelease.Spec.Suspend return obj.HelmRelease.Spec.Suspend
} }
func (obj helmReleaseAdapter) setSuspended() { func (obj helmReleaseAdapter) setSuspended(reason string) {
obj.HelmRelease.Spec.Suspend = true obj.HelmRelease.Spec.Suspend = true
obj.HelmRelease.Annotations[SuspendReasonAnnotation] = reason
} }
func (a helmReleaseListAdapter) item(i int) suspendable { func (a helmReleaseListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj imageRepositoryAdapter) isSuspended() bool {
return obj.ImageRepository.Spec.Suspend return obj.ImageRepository.Spec.Suspend
} }
func (obj imageRepositoryAdapter) setSuspended() { func (obj imageRepositoryAdapter) setSuspended(reason string) {
obj.ImageRepository.Spec.Suspend = true obj.ImageRepository.Spec.Suspend = true
obj.ImageRepository.Annotations[SuspendReasonAnnotation] = reason
} }
func (a imageRepositoryListAdapter) item(i int) suspendable { func (a imageRepositoryListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (update imageUpdateAutomationAdapter) isSuspended() bool {
return update.ImageUpdateAutomation.Spec.Suspend return update.ImageUpdateAutomation.Spec.Suspend
} }
func (update imageUpdateAutomationAdapter) setSuspended() { func (update imageUpdateAutomationAdapter) setSuspended(reason string) {
update.ImageUpdateAutomation.Spec.Suspend = true update.ImageUpdateAutomation.Spec.Suspend = true
update.ImageUpdateAutomation.Annotations[SuspendReasonAnnotation] = reason
} }
func (a imageUpdateAutomationListAdapter) item(i int) suspendable { func (a imageUpdateAutomationListAdapter) item(i int) suspendable {

View file

@ -48,8 +48,9 @@ func (obj kustomizationAdapter) isSuspended() bool {
return obj.Kustomization.Spec.Suspend return obj.Kustomization.Spec.Suspend
} }
func (obj kustomizationAdapter) setSuspended() { func (obj kustomizationAdapter) setSuspended(reason string) {
obj.Kustomization.Spec.Suspend = true obj.Kustomization.Spec.Suspend = true
obj.Kustomization.Annotations[SuspendReasonAnnotation] = reason
} }
func (a kustomizationListAdapter) item(i int) suspendable { func (a kustomizationListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj receiverAdapter) isSuspended() bool {
return obj.Receiver.Spec.Suspend return obj.Receiver.Spec.Suspend
} }
func (obj receiverAdapter) setSuspended() { func (obj receiverAdapter) setSuspended(reason string) {
obj.Receiver.Spec.Suspend = true obj.Receiver.Spec.Suspend = true
obj.Receiver.Annotations[SuspendReasonAnnotation] = reason
} }
func (a receiverListAdapter) item(i int) suspendable { func (a receiverListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj bucketAdapter) isSuspended() bool {
return obj.Bucket.Spec.Suspend return obj.Bucket.Spec.Suspend
} }
func (obj bucketAdapter) setSuspended() { func (obj bucketAdapter) setSuspended(reason string) {
obj.Bucket.Spec.Suspend = true obj.Bucket.Spec.Suspend = true
obj.Bucket.Annotations[SuspendReasonAnnotation] = reason
} }
func (a bucketListAdapter) item(i int) suspendable { func (a bucketListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj helmChartAdapter) isSuspended() bool {
return obj.HelmChart.Spec.Suspend return obj.HelmChart.Spec.Suspend
} }
func (obj helmChartAdapter) setSuspended() { func (obj helmChartAdapter) setSuspended(reason string) {
obj.HelmChart.Spec.Suspend = true obj.HelmChart.Spec.Suspend = true
obj.HelmChart.Annotations[SuspendReasonAnnotation] = reason
} }
func (a helmChartListAdapter) item(i int) suspendable { func (a helmChartListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj gitRepositoryAdapter) isSuspended() bool {
return obj.GitRepository.Spec.Suspend return obj.GitRepository.Spec.Suspend
} }
func (obj gitRepositoryAdapter) setSuspended() { func (obj gitRepositoryAdapter) setSuspended(reason string) {
obj.GitRepository.Spec.Suspend = true obj.GitRepository.Spec.Suspend = true
obj.GitRepository.Annotations[SuspendReasonAnnotation] = reason
} }
func (a gitRepositoryListAdapter) item(i int) suspendable { func (a gitRepositoryListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj helmRepositoryAdapter) isSuspended() bool {
return obj.HelmRepository.Spec.Suspend return obj.HelmRepository.Spec.Suspend
} }
func (obj helmRepositoryAdapter) setSuspended() { func (obj helmRepositoryAdapter) setSuspended(reason string) {
obj.HelmRepository.Spec.Suspend = true obj.HelmRepository.Spec.Suspend = true
obj.HelmRepository.Annotations[SuspendReasonAnnotation] = reason
} }
func (a helmRepositoryListAdapter) item(i int) suspendable { func (a helmRepositoryListAdapter) item(i int) suspendable {

View file

@ -47,8 +47,9 @@ func (obj ociRepositoryAdapter) isSuspended() bool {
return obj.OCIRepository.Spec.Suspend return obj.OCIRepository.Spec.Suspend
} }
func (obj ociRepositoryAdapter) setSuspended() { func (obj ociRepositoryAdapter) setSuspended(reason string) {
obj.OCIRepository.Spec.Suspend = true obj.OCIRepository.Spec.Suspend = true
obj.OCIRepository.Annotations[SuspendReasonAnnotation] = reason
} }
func (a ociRepositoryListAdapter) item(i int) suspendable { func (a ociRepositoryListAdapter) item(i int) suspendable {