From 7ebb34de8053a823c148f65820a22fa5bc01eeac Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Sun, 4 Oct 2020 20:20:30 +0200 Subject: [PATCH] Add receiver command --- cmd/gotk/create_receiver.go | 209 +++++++++++++++++++++++++++++++++ cmd/gotk/delete_receiver.go | 88 ++++++++++++++ cmd/gotk/export_receiver.go | 120 +++++++++++++++++++ cmd/gotk/get_receiver.go | 87 ++++++++++++++ cmd/gotk/reconcile_receiver.go | 93 +++++++++++++++ cmd/gotk/resume_receiver.go | 117 ++++++++++++++++++ cmd/gotk/suspend_alert.go | 34 +++--- cmd/gotk/suspend_receiver.go | 76 ++++++++++++ 8 files changed, 807 insertions(+), 17 deletions(-) create mode 100644 cmd/gotk/create_receiver.go create mode 100644 cmd/gotk/delete_receiver.go create mode 100644 cmd/gotk/export_receiver.go create mode 100644 cmd/gotk/get_receiver.go create mode 100644 cmd/gotk/reconcile_receiver.go create mode 100644 cmd/gotk/resume_receiver.go create mode 100644 cmd/gotk/suspend_receiver.go diff --git a/cmd/gotk/create_receiver.go b/cmd/gotk/create_receiver.go new file mode 100644 index 00000000..1a1a12bf --- /dev/null +++ b/cmd/gotk/create_receiver.go @@ -0,0 +1,209 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + "github.com/fluxcd/pkg/apis/meta" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "sigs.k8s.io/controller-runtime/pkg/client" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var createReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Aliases: []string{"rcv"}, + Short: "Create or update a Receiver resource", + Long: "The create receiver command generates a Receiver resource.", + Example: ` # Create a Provider for a Slack channel + gotk create ap slack \ + --type slack \ + --channel general \ + --address https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \ + --secret-ref webhook-url + + # Create a Provider for a Github repository + gotk create ap github-podinfo \ + --type github \ + --address https://github.com/stefanprodan/podinfo \ + --secret-ref github-token +`, + RunE: createReceiverCmdRun, +} + +var ( + rcvType string + rcvSecretRef string + rcvEvents []string + rcvResources []string +) + +func init() { + createReceiverCmd.Flags().StringVar(&rcvType, "type", "", "") + createReceiverCmd.Flags().StringVar(&rcvSecretRef, "secret-ref", "", "") + createReceiverCmd.Flags().StringArrayVar(&rcvEvents, "events", []string{}, "") + createReceiverCmd.Flags().StringArrayVar(&rcvResources, "resource", []string{}, "") + createCmd.AddCommand(createReceiverCmd) +} + +func createReceiverCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("receiver name is required") + } + name := args[0] + + if rcvType == "" { + return fmt.Errorf("type is required") + } + + if rcvSecretRef == "" { + return fmt.Errorf("secret ref is required") + } + + resources := []notificationv1.CrossNamespaceObjectReference{} + for _, resource := range rcvResources { + kind, name := utils.parseObjectKindName(resource) + if kind == "" { + return fmt.Errorf("invalid event source '%s', must be in format /", resource) + } + + resources = append(resources, notificationv1.CrossNamespaceObjectReference{ + Kind: kind, + Name: name, + }) + } + + if len(resources) == 0 { + return fmt.Errorf("atleast one resource is required") + } + + sourceLabels, err := parseLabels() + if err != nil { + return err + } + + if !export { + logger.Generatef("generating receiver") + } + + receiver := notificationv1.Receiver{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: sourceLabels, + }, + Spec: notificationv1.ReceiverSpec{ + Type: rcvType, + Events: rcvEvents, + Resources: resources, + SecretRef: corev1.LocalObjectReference{ + Name: rcvSecretRef, + }, + Suspend: false, + }, + } + + if export { + return exportReceiver(receiver) + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + logger.Actionf("applying receiver") + if err := upsertReceiver(ctx, kubeClient, receiver); err != nil { + return err + } + + logger.Waitingf("waiting for reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isReceiverReady(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("receiver %s is ready", name) + + return nil +} + +func upsertReceiver(ctx context.Context, kubeClient client.Client, receiver notificationv1.Receiver) error { + namespacedName := types.NamespacedName{ + Namespace: receiver.GetNamespace(), + Name: receiver.GetName(), + } + + var existing notificationv1.Receiver + err := kubeClient.Get(ctx, namespacedName, &existing) + if err != nil { + if errors.IsNotFound(err) { + if err := kubeClient.Create(ctx, &receiver); err != nil { + return err + } else { + logger.Successf("receiver created") + return nil + } + } + return err + } + + existing.Labels = receiver.Labels + existing.Spec = receiver.Spec + if err := kubeClient.Update(ctx, &existing); err != nil { + return err + } + + logger.Successf("receiver updated") + return nil +} + +func isReceiverReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc { + return func() (bool, error) { + var receiver notificationv1.Receiver + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + err := kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return false, err + } + + if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case corev1.ConditionTrue: + return true, nil + case corev1.ConditionFalse: + return false, fmt.Errorf(c.Message) + } + } + return false, nil + } +} diff --git a/cmd/gotk/delete_receiver.go b/cmd/gotk/delete_receiver.go new file mode 100644 index 00000000..63ba151a --- /dev/null +++ b/cmd/gotk/delete_receiver.go @@ -0,0 +1,88 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/types" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var deleteReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Aliases: []string{"rcv"}, + Short: "Delete a Receiver resource", + Long: "The delete receiver command removes the given Receiver from the cluster.", + Example: ` # Delete an Receiver and the Kubernetes resources created by it + gotk delete receiver main +`, + RunE: deleteReceiverCmdRun, +} + +func init() { + deleteCmd.AddCommand(deleteReceiverCmd) +} + +func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("receiver name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + var receiver notificationv1.Receiver + err = kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return err + } + + if !deleteSilent { + prompt := promptui.Prompt{ + Label: "Are you sure you want to delete this Receiver", + IsConfirm: true, + } + if _, err := prompt.Run(); err != nil { + return fmt.Errorf("aborting") + } + } + + logger.Actionf("deleting receiver %s in %s namespace", name, namespace) + err = kubeClient.Delete(ctx, &receiver) + if err != nil { + return err + } + logger.Successf("receiver deleted") + + return nil +} diff --git a/cmd/gotk/export_receiver.go b/cmd/gotk/export_receiver.go new file mode 100644 index 00000000..cafbde69 --- /dev/null +++ b/cmd/gotk/export_receiver.go @@ -0,0 +1,120 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var exportReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Aliases: []string{"rcv"}, + Short: "Export Receiver resources in YAML format", + Long: "The export receiver command exports one or all Receiver resources in YAML format.", + Example: ` # Export all Receiver resources + gotk export rcv --all > kustomizations.yaml + + # Export a Receiver + gotk export rcv main > main.yaml +`, + RunE: exportReceiverCmdRun, +} + +func init() { + exportCmd.AddCommand(exportReceiverCmd) +} + +func exportReceiverCmdRun(cmd *cobra.Command, args []string) error { + if !exportAll && len(args) < 1 { + return fmt.Errorf("name is required") + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + if exportAll { + var list notificationv1.ReceiverList + err = kubeClient.List(ctx, &list, client.InNamespace(namespace)) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no receivers found in %s namespace", namespace) + return nil + } + + for _, receiver := range list.Items { + if err := exportReceiver(receiver); err != nil { + return err + } + } + } else { + name := args[0] + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var receiver notificationv1.Receiver + err = kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return err + } + return exportReceiver(receiver) + } + return nil +} + +func exportReceiver(receiver notificationv1.Receiver) error { + gvk := notificationv1.GroupVersion.WithKind("Receiver") + export := notificationv1.Receiver{ + TypeMeta: metav1.TypeMeta{ + Kind: gvk.Kind, + APIVersion: gvk.GroupVersion().String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: receiver.Name, + Namespace: receiver.Namespace, + Labels: receiver.Labels, + Annotations: receiver.Annotations, + }, + Spec: receiver.Spec, + } + + data, err := yaml.Marshal(export) + if err != nil { + return err + } + + fmt.Println("---") + fmt.Println(resourceToString(data)) + return nil +} diff --git a/cmd/gotk/get_receiver.go b/cmd/gotk/get_receiver.go new file mode 100644 index 00000000..a9aa680b --- /dev/null +++ b/cmd/gotk/get_receiver.go @@ -0,0 +1,87 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" + "github.com/fluxcd/pkg/apis/meta" +) + +var getReceiverCmd = &cobra.Command{ + Use: "receiver", + Aliases: []string{"rcv"}, + Short: "Get Receiver statuses", + Long: "The get receiver command prints the statuses of the resources.", + Example: ` # List all Receiver and their status + gotk get receiver +`, + RunE: getReceiverCmdRun, +} + +func init() { + getCmd.AddCommand(getReceiverCmd) +} + +func getReceiverCmdRun(cmd *cobra.Command, args []string) error { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + var list notificationv1.ReceiverList + err = kubeClient.List(ctx, &list, client.InNamespace(namespace)) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no receivers found in %s namespace", namespace) + return nil + } + + for _, receiver := range list.Items { + if receiver.Spec.Suspend { + logger.Successf("%s is suspended", receiver.GetName()) + continue + } + isInitialized := false + if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case corev1.ConditionTrue: + logger.Successf("%s is ready", receiver.GetName()) + case corev1.ConditionUnknown: + logger.Successf("%s reconciling", receiver.GetName()) + default: + logger.Failuref("%s %s", receiver.GetName(), c.Message) + } + isInitialized = true + } + if !isInitialized { + logger.Failuref("%s is not ready", receiver.GetName()) + } + } + return nil +} diff --git a/cmd/gotk/reconcile_receiver.go b/cmd/gotk/reconcile_receiver.go new file mode 100644 index 00000000..7a7f6a86 --- /dev/null +++ b/cmd/gotk/reconcile_receiver.go @@ -0,0 +1,93 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + "github.com/fluxcd/pkg/apis/meta" + "time" + + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var reconcileReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Short: "Reconcile a Receiver", + Long: `The reconcile receiver command triggers a reconciliation of a Receiver resource and waits for it to finish.`, + Example: ` # Trigger a reconciliation for an existing receiver + gotk reconcile receiver main +`, + RunE: reconcileReceiverCmdRun, +} + +func init() { + reconcileCmd.AddCommand(reconcileReceiverCmd) +} + +func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("receiver name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + logger.Actionf("annotating receiver %s in %s namespace", name, namespace) + var receiver notificationv1.Receiver + err = kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return err + } + + if receiver.Annotations == nil { + receiver.Annotations = map[string]string{ + meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano), + } + } else { + receiver.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano) + } + if err := kubeClient.Update(ctx, &receiver); err != nil { + return err + } + logger.Successf("receiver annotated") + + logger.Waitingf("waiting for reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isReceiverReady(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("receiver reconciliation completed") + + return nil +} diff --git a/cmd/gotk/resume_receiver.go b/cmd/gotk/resume_receiver.go new file mode 100644 index 00000000..eb4c0da3 --- /dev/null +++ b/cmd/gotk/resume_receiver.go @@ -0,0 +1,117 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + "github.com/fluxcd/pkg/apis/meta" + + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "sigs.k8s.io/controller-runtime/pkg/client" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var resumeReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Aliases: []string{"rcv"}, + Short: "Resume a suspended Receiver", + Long: `The resume command marks a previously suspended Receiver resource for reconciliation and waits for it to +finish the apply.`, + Example: ` # Resume reconciliation for an existing Receiver + gotk resume rcv main +`, + RunE: resumeReceiverCmdRun, +} + +func init() { + resumeCmd.AddCommand(resumeReceiverCmd) +} + +func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("Receiver name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var receiver notificationv1.Receiver + err = kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return err + } + + logger.Actionf("resuming Receiver %s in %s namespace", name, namespace) + receiver.Spec.Suspend = false + if err := kubeClient.Update(ctx, &receiver); err != nil { + return err + } + logger.Successf("Receiver resumed") + + logger.Waitingf("waiting for Receiver reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isReceiverResumed(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("Receiver reconciliation completed") + + return nil +} + +func isReceiverResumed(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc { + return func() (bool, error) { + var receiver notificationv1.Receiver + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + err := kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return false, err + } + + if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case corev1.ConditionTrue: + return true, nil + case corev1.ConditionFalse: + if c.Reason == meta.SuspendedReason { + return false, nil + } + return false, fmt.Errorf(c.Message) + } + } + return false, nil + } +} diff --git a/cmd/gotk/suspend_alert.go b/cmd/gotk/suspend_alert.go index 555f9e3b..8cfb8dc4 100644 --- a/cmd/gotk/suspend_alert.go +++ b/cmd/gotk/suspend_alert.go @@ -26,24 +26,24 @@ import ( notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" ) -var suspendAlertCmd = &cobra.Command{ - Use: "alert [name]", - Aliases: []string{}, - Short: "Suspend reconciliation of Alert", - Long: "The suspend command disables the reconciliation of a Alert resource.", - Example: ` # Suspend reconciliation for an existing Alert - gotk suspend alert main +var suspendReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Aliases: []string{"rcv"}, + Short: "Suspend reconciliation of Receiver", + Long: "The suspend command disables the reconciliation of a Receiver resource.", + Example: ` # Suspend reconciliation for an existing Receiver + gotk suspend receiver main `, - RunE: suspendAlertCmdRun, + RunE: suspendReceiverCmdRun, } func init() { - suspendCmd.AddCommand(suspendAlertCmd) + suspendCmd.AddCommand(suspendReceiverCmd) } -func suspendAlertCmdRun(cmd *cobra.Command, args []string) error { +func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error { if len(args) < 1 { - return fmt.Errorf("Alert name is required") + return fmt.Errorf("Receiver name is required") } name := args[0] @@ -59,18 +59,18 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error { Namespace: namespace, Name: name, } - var alert notificationv1.Alert - err = kubeClient.Get(ctx, namespacedName, &alert) + var receiver notificationv1.Receiver + err = kubeClient.Get(ctx, namespacedName, &receiver) if err != nil { return err } - logger.Actionf("suspending Alert %s in %s namespace", name, namespace) - alert.Spec.Suspend = true - if err := kubeClient.Update(ctx, &alert); err != nil { + logger.Actionf("suspending Receiver %s in %s namespace", name, namespace) + receiver.Spec.Suspend = true + if err := kubeClient.Update(ctx, &receiver); err != nil { return err } - logger.Successf("Alert suspended") + logger.Successf("Receiver suspended") return nil } diff --git a/cmd/gotk/suspend_receiver.go b/cmd/gotk/suspend_receiver.go new file mode 100644 index 00000000..555f9e3b --- /dev/null +++ b/cmd/gotk/suspend_receiver.go @@ -0,0 +1,76 @@ +/* +Copyright 2020 The Flux CD contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/types" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var suspendAlertCmd = &cobra.Command{ + Use: "alert [name]", + Aliases: []string{}, + Short: "Suspend reconciliation of Alert", + Long: "The suspend command disables the reconciliation of a Alert resource.", + Example: ` # Suspend reconciliation for an existing Alert + gotk suspend alert main +`, + RunE: suspendAlertCmdRun, +} + +func init() { + suspendCmd.AddCommand(suspendAlertCmd) +} + +func suspendAlertCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("Alert name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var alert notificationv1.Alert + err = kubeClient.Get(ctx, namespacedName, &alert) + if err != nil { + return err + } + + logger.Actionf("suspending Alert %s in %s namespace", name, namespace) + alert.Spec.Suspend = true + if err := kubeClient.Update(ctx, &alert); err != nil { + return err + } + logger.Successf("Alert suspended") + + return nil +}