diff --git a/cmd/gotk/create_alert.go b/cmd/gotk/create_alert.go new file mode 100644 index 00000000..6e7cbd53 --- /dev/null +++ b/cmd/gotk/create_alert.go @@ -0,0 +1,195 @@ +/* +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 createAlertCmd = &cobra.Command{ + Use: "alert [name]", + Short: "Create or update a Alert resource", + Long: "The create alert command generates a Alert resource.", + Example: ` # Create an Alert for kustomization events + gotk create alert \ + --event-severity info \ + --event-source Kustomization/gotk-system \ + --provider-ref slack \ + gotk-system +`, + RunE: createAlertCmdRun, +} + +var ( + aProviderRef string + aEventSeverity string + aEventSources []string +) + +func init() { + createAlertCmd.Flags().StringVar(&aProviderRef, "provider-ref", "", "reference to provider") + createAlertCmd.Flags().StringVar(&aEventSeverity, "event-severity", "", "severity of events to send alerts for") + createAlertCmd.Flags().StringArrayVar(&aEventSources, "event-source", []string{}, "sources that should generate alerts (/)") + createCmd.AddCommand(createAlertCmd) +} + +func createAlertCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("alert name is required") + } + name := args[0] + + if aProviderRef == "" { + return fmt.Errorf("provider ref is required") + } + + eventSources := []notificationv1.CrossNamespaceObjectReference{} + for _, eventSource := range aEventSources { + kind, name := utils.parseObjectKindName(eventSource) + if kind == "" { + return fmt.Errorf("invalid event source '%s', must be in format /", eventSource) + } + + eventSources = append(eventSources, notificationv1.CrossNamespaceObjectReference{ + Kind: kind, + Name: name, + }) + } + + if len(eventSources) == 0 { + return fmt.Errorf("at least one event source is required") + } + + sourceLabels, err := parseLabels() + if err != nil { + return err + } + + if !export { + logger.Generatef("generating alert") + } + + alert := notificationv1.Alert{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: sourceLabels, + }, + Spec: notificationv1.AlertSpec{ + ProviderRef: corev1.LocalObjectReference{ + Name: aProviderRef, + }, + EventSeverity: aEventSeverity, + EventSources: eventSources, + Suspend: false, + }, + } + + if export { + return exportAlert(alert) + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + logger.Actionf("applying alert") + if err := upsertAlert(ctx, kubeClient, alert); err != nil { + return err + } + + logger.Waitingf("waiting for reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isAlertReady(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("alert %s is ready", name) + + return nil +} + +func upsertAlert(ctx context.Context, kubeClient client.Client, alert notificationv1.Alert) error { + namespacedName := types.NamespacedName{ + Namespace: alert.GetNamespace(), + Name: alert.GetName(), + } + + var existing notificationv1.Alert + err := kubeClient.Get(ctx, namespacedName, &existing) + if err != nil { + if errors.IsNotFound(err) { + if err := kubeClient.Create(ctx, &alert); err != nil { + return err + } else { + logger.Successf("alert created") + return nil + } + } + return err + } + + existing.Labels = alert.Labels + existing.Spec = alert.Spec + if err := kubeClient.Update(ctx, &existing); err != nil { + return err + } + + logger.Successf("alert updated") + return nil +} + +func isAlertReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc { + return func() (bool, error) { + var alert notificationv1.Alert + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + err := kubeClient.Get(ctx, namespacedName, &alert) + if err != nil { + return false, err + } + + if c := meta.GetCondition(alert.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/create_alertprovider.go b/cmd/gotk/create_alertprovider.go new file mode 100644 index 00000000..8df247e9 --- /dev/null +++ b/cmd/gotk/create_alertprovider.go @@ -0,0 +1,189 @@ +/* +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 createAlertProviderCmd = &cobra.Command{ + Use: "alert-provider [name]", + Short: "Create or update a Provider resource", + Long: "The create alert-provider command generates a Provider resource.", + Example: ` # Create a Provider for a Slack channel + gotk create alert-provider 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 alert-provider github-podinfo \ + --type github \ + --address https://github.com/stefanprodan/podinfo \ + --secret-ref github-token +`, + RunE: createAlertProviderCmdRun, +} + +var ( + apType string + apChannel string + apUsername string + apAddress string + apSecretRef string +) + +func init() { + createAlertProviderCmd.Flags().StringVar(&apType, "type", "", "type of provider") + createAlertProviderCmd.Flags().StringVar(&apChannel, "channel", "", "channel to send messages to in the case of a chat provider") + createAlertProviderCmd.Flags().StringVar(&apUsername, "username", "", "bot username used by the provider") + createAlertProviderCmd.Flags().StringVar(&apAddress, "address", "", "path to either the git repository, chat provider or webhook") + createAlertProviderCmd.Flags().StringVar(&apSecretRef, "secret-ref", "", "name of secret containing authentication token") + createCmd.AddCommand(createAlertProviderCmd) +} + +func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("provider name is required") + } + name := args[0] + + if apType == "" { + return fmt.Errorf("type is required") + } + + sourceLabels, err := parseLabels() + if err != nil { + return err + } + + if !export { + logger.Generatef("generating provider") + } + + alertProvider := notificationv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: sourceLabels, + }, + Spec: notificationv1.ProviderSpec{ + Type: apType, + Channel: apChannel, + Username: apUsername, + Address: apAddress, + SecretRef: &corev1.LocalObjectReference{ + Name: apSecretRef, + }, + }, + } + + if export { + return exportAlertProvider(alertProvider) + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.kubeClient(kubeconfig) + if err != nil { + return err + } + + logger.Actionf("applying provider") + if err := upsertAlertProvider(ctx, kubeClient, alertProvider); err != nil { + return err + } + + logger.Waitingf("waiting for reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isAlertProviderReady(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("provider %s is ready", name) + + return nil +} + +func upsertAlertProvider(ctx context.Context, kubeClient client.Client, alertProvider notificationv1.Provider) error { + namespacedName := types.NamespacedName{ + Namespace: alertProvider.GetNamespace(), + Name: alertProvider.GetName(), + } + + var existing notificationv1.Provider + err := kubeClient.Get(ctx, namespacedName, &existing) + if err != nil { + if errors.IsNotFound(err) { + if err := kubeClient.Create(ctx, &alertProvider); err != nil { + return err + } else { + logger.Successf("provider created") + return nil + } + } + return err + } + + existing.Labels = alertProvider.Labels + existing.Spec = alertProvider.Spec + if err := kubeClient.Update(ctx, &existing); err != nil { + return err + } + + logger.Successf("provider updated") + return nil +} + +func isAlertProviderReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc { + return func() (bool, error) { + var alertProvider notificationv1.Provider + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + err := kubeClient.Get(ctx, namespacedName, &alertProvider) + if err != nil { + return false, err + } + + if c := meta.GetCondition(alertProvider.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/create_receiver.go b/cmd/gotk/create_receiver.go new file mode 100644 index 00000000..367cd6a5 --- /dev/null +++ b/cmd/gotk/create_receiver.go @@ -0,0 +1,215 @@ +/* +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" + 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" + "github.com/fluxcd/pkg/apis/meta" +) + +var createReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + Short: "Create or update a Receiver resource", + Long: "The create receiver command generates a Receiver resource.", + Example: ` # Create a Receiver + gotk create receiver github-receiver \ + --type github \ + --event ping \ + --event push \ + --secret-ref webhook-token \ + --resource GitRepository/webapp \ + --resource HelmRepository/webapp +`, + 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, "event", []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) + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + err = kubeClient.Get(ctx, namespacedName, &receiver) + if err != nil { + return fmt.Errorf("receiver sync failed: %w", err) + } + + logger.Successf("generated webhook URL %s", receiver.Status.URL) + + 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_alert.go b/cmd/gotk/delete_alert.go new file mode 100644 index 00000000..b918f2b7 --- /dev/null +++ b/cmd/gotk/delete_alert.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" + "fmt" + + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/types" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var deleteAlertCmd = &cobra.Command{ + Use: "alert [name]", + Short: "Delete a Alert resource", + Long: "The delete alert command removes the given Alert from the cluster.", + Example: ` # Delete an Alert and the Kubernetes resources created by it + gotk delete alert main +`, + RunE: deleteAlertCmdRun, +} + +func init() { + deleteCmd.AddCommand(deleteAlertCmd) +} + +func deleteAlertCmdRun(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 + } + + if !deleteSilent { + prompt := promptui.Prompt{ + Label: "Are you sure you want to delete this Alert", + IsConfirm: true, + } + if _, err := prompt.Run(); err != nil { + return fmt.Errorf("aborting") + } + } + + logger.Actionf("deleting alert %s in %s namespace", name, namespace) + err = kubeClient.Delete(ctx, &alert) + if err != nil { + return err + } + logger.Successf("alert deleted") + + return nil +} diff --git a/cmd/gotk/delete_alertprovider.go b/cmd/gotk/delete_alertprovider.go new file mode 100644 index 00000000..1b641529 --- /dev/null +++ b/cmd/gotk/delete_alertprovider.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" + "fmt" + + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/types" + + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" +) + +var deleteAlertProviderCmd = &cobra.Command{ + Use: "alert-provider [name]", + Short: "Delete a Provider resource", + Long: "The delete alert-provider command removes the given Provider from the cluster.", + Example: ` # Delete a Provider and the Kubernetes resources created by it + gotk delete alert-provider slack +`, + RunE: deleteAlertProviderCmdRun, +} + +func init() { + deleteCmd.AddCommand(deleteAlertProviderCmd) +} + +func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("provider 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 alertProvider notificationv1.Provider + err = kubeClient.Get(ctx, namespacedName, &alertProvider) + if err != nil { + return err + } + + if !deleteSilent { + prompt := promptui.Prompt{ + Label: "Are you sure you want to delete this Provider", + IsConfirm: true, + } + if _, err := prompt.Run(); err != nil { + return fmt.Errorf("aborting") + } + } + + logger.Actionf("deleting provider %s in %s namespace", name, namespace) + err = kubeClient.Delete(ctx, &alertProvider) + if err != nil { + return err + } + logger.Successf("provider deleted") + + return nil +} diff --git a/cmd/gotk/delete_receiver.go b/cmd/gotk/delete_receiver.go new file mode 100644 index 00000000..253308e0 --- /dev/null +++ b/cmd/gotk/delete_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" + "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]", + 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_alert.go b/cmd/gotk/export_alert.go new file mode 100644 index 00000000..e5a69f07 --- /dev/null +++ b/cmd/gotk/export_alert.go @@ -0,0 +1,119 @@ +/* +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 exportAlertCmd = &cobra.Command{ + Use: "alert [name]", + Short: "Export Alert resources in YAML format", + Long: "The export alert command exports one or all Alert resources in YAML format.", + Example: ` # Export all Alert resources + gotk export alert --all > alerts.yaml + + # Export a Alert + gotk export alert main > main.yaml +`, + RunE: exportAlertCmdRun, +} + +func init() { + exportCmd.AddCommand(exportAlertCmd) +} + +func exportAlertCmdRun(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.AlertList + err = kubeClient.List(ctx, &list, client.InNamespace(namespace)) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no alerts found in %s namespace", namespace) + return nil + } + + for _, alert := range list.Items { + if err := exportAlert(alert); err != nil { + return err + } + } + } else { + name := args[0] + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var alert notificationv1.Alert + err = kubeClient.Get(ctx, namespacedName, &alert) + if err != nil { + return err + } + return exportAlert(alert) + } + return nil +} + +func exportAlert(alert notificationv1.Alert) error { + gvk := notificationv1.GroupVersion.WithKind("Alert") + export := notificationv1.Alert{ + TypeMeta: metav1.TypeMeta{ + Kind: gvk.Kind, + APIVersion: gvk.GroupVersion().String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: alert.Name, + Namespace: alert.Namespace, + Labels: alert.Labels, + Annotations: alert.Annotations, + }, + Spec: alert.Spec, + } + + data, err := yaml.Marshal(export) + if err != nil { + return err + } + + fmt.Println("---") + fmt.Println(resourceToString(data)) + return nil +} diff --git a/cmd/gotk/export_alertprovider.go b/cmd/gotk/export_alertprovider.go new file mode 100644 index 00000000..88a61182 --- /dev/null +++ b/cmd/gotk/export_alertprovider.go @@ -0,0 +1,119 @@ +/* +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 exportAlertProviderCmd = &cobra.Command{ + Use: "alert-provider [name]", + Short: "Export Provider resources in YAML format", + Long: "The export alert-provider command exports one or all Provider resources in YAML format.", + Example: ` # Export all Provider resources + gotk export alert-provider --all > alert-providers.yaml + + # Export a Provider + gotk export alert-provider slack > slack.yaml +`, + RunE: exportAlertProviderCmdRun, +} + +func init() { + exportCmd.AddCommand(exportAlertProviderCmd) +} + +func exportAlertProviderCmdRun(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.ProviderList + err = kubeClient.List(ctx, &list, client.InNamespace(namespace)) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no alertproviders found in %s namespace", namespace) + return nil + } + + for _, alertProvider := range list.Items { + if err := exportAlertProvider(alertProvider); err != nil { + return err + } + } + } else { + name := args[0] + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var alertProvider notificationv1.Provider + err = kubeClient.Get(ctx, namespacedName, &alertProvider) + if err != nil { + return err + } + return exportAlertProvider(alertProvider) + } + return nil +} + +func exportAlertProvider(alertProvider notificationv1.Provider) error { + gvk := notificationv1.GroupVersion.WithKind("Provider") + export := notificationv1.Provider{ + TypeMeta: metav1.TypeMeta{ + Kind: gvk.Kind, + APIVersion: gvk.GroupVersion().String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: alertProvider.Name, + Namespace: alertProvider.Namespace, + Labels: alertProvider.Labels, + Annotations: alertProvider.Annotations, + }, + Spec: alertProvider.Spec, + } + + data, err := yaml.Marshal(export) + if err != nil { + return err + } + + fmt.Println("---") + fmt.Println(resourceToString(data)) + return nil +} diff --git a/cmd/gotk/export_receiver.go b/cmd/gotk/export_receiver.go new file mode 100644 index 00000000..1acfb164 --- /dev/null +++ b/cmd/gotk/export_receiver.go @@ -0,0 +1,119 @@ +/* +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]", + 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 receiver --all > receivers.yaml + + # Export a Receiver + gotk export receiver 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_alert.go b/cmd/gotk/get_alert.go new file mode 100644 index 00000000..c30b3226 --- /dev/null +++ b/cmd/gotk/get_alert.go @@ -0,0 +1,102 @@ +/* +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" + "os" + "strconv" + "strings" + + "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 getAlertCmd = &cobra.Command{ + Use: "alerts", + Short: "Get Alert statuses", + Long: "The get alert command prints the statuses of the resources.", + Example: ` # List all Alerts and their status + gotk get alerts +`, + RunE: getAlertCmdRun, +} + +func init() { + getCmd.AddCommand(getAlertCmd) +} + +func getAlertCmdRun(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 listOpts []client.ListOption + if !allNamespaces { + listOpts = append(listOpts, client.InNamespace(namespace)) + } + var list notificationv1.AlertList + err = kubeClient.List(ctx, &list, listOpts...) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no alerts found in %s namespace", namespace) + return nil + } + + header := []string{"Name", "Suspended", "Ready", "Message"} + if allNamespaces { + header = append([]string{"Namespace"}, header...) + } + var rows [][]string + for _, alert := range list.Items { + row := []string{} + if c := meta.GetCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil { + row = []string{ + alert.GetName(), + //alert.Status.LastAppliedRevision, + strings.Title(strconv.FormatBool(alert.Spec.Suspend)), + string(c.Status), + c.Message, + } + } else { + row = []string{ + alert.GetName(), + //alert.Status.LastAppliedRevision, + strings.Title(strconv.FormatBool(alert.Spec.Suspend)), + string(corev1.ConditionFalse), + "waiting to be reconciled", + } + } + if allNamespaces { + row = append([]string{alert.Namespace}, row...) + } + rows = append(rows, row) + } + utils.printTable(os.Stdout, header, rows) + return nil +} diff --git a/cmd/gotk/get_alertprovider.go b/cmd/gotk/get_alertprovider.go new file mode 100644 index 00000000..a9421d81 --- /dev/null +++ b/cmd/gotk/get_alertprovider.go @@ -0,0 +1,96 @@ +/* +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" + "os" + + "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 getAlertProviderCmd = &cobra.Command{ + Use: "alert-providers", + Short: "Get Provider statuses", + Long: "The get alert-provider command prints the statuses of the resources.", + Example: ` # List all Providers and their status + gotk get alert-providers +`, + RunE: getAlertProviderCmdRun, +} + +func init() { + getCmd.AddCommand(getAlertProviderCmd) +} + +func getAlertProviderCmdRun(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 listOpts []client.ListOption + if !allNamespaces { + listOpts = append(listOpts, client.InNamespace(namespace)) + } + var list notificationv1.ProviderList + err = kubeClient.List(ctx, &list, listOpts...) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no providers found in %s namespace", namespace) + return nil + } + + header := []string{"Name", "Ready", "Message"} + if allNamespaces { + header = append([]string{"Namespace"}, header...) + } + var rows [][]string + for _, provider := range list.Items { + row := []string{} + if c := meta.GetCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil { + row = []string{ + provider.GetName(), + string(c.Status), + c.Message, + } + } else { + row = []string{ + provider.GetName(), + string(corev1.ConditionFalse), + "waiting to be reconciled", + } + } + if allNamespaces { + row = append([]string{provider.Namespace}, row...) + } + rows = append(rows, row) + } + utils.printTable(os.Stdout, header, rows) + return nil +} diff --git a/cmd/gotk/get_receiver.go b/cmd/gotk/get_receiver.go new file mode 100644 index 00000000..c41bdce0 --- /dev/null +++ b/cmd/gotk/get_receiver.go @@ -0,0 +1,97 @@ +/* +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" + "os" + "strconv" + "strings" + + "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: "receivers", + Short: "Get Receiver statuses", + Long: "The get receiver command prints the statuses of the resources.", + Example: ` # List all Receiver and their status + gotk get receivers +`, + 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 listOpts []client.ListOption + if !allNamespaces { + listOpts = append(listOpts, client.InNamespace(namespace)) + } + var list notificationv1.ReceiverList + err = kubeClient.List(ctx, &list, listOpts...) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logger.Failuref("no receivers found in %s namespace", namespace) + return nil + } + + header := []string{"Name", "Suspended", "Ready", "Message"} + if allNamespaces { + header = append([]string{"Namespace"}, header...) + } + var rows [][]string + for _, receiver := range list.Items { + row := []string{} + if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil { + row = []string{ + receiver.GetName(), + strings.Title(strconv.FormatBool(receiver.Spec.Suspend)), + string(c.Status), + c.Message, + } + } else { + row = []string{ + receiver.GetName(), + strings.Title(strconv.FormatBool(receiver.Spec.Suspend)), + string(corev1.ConditionFalse), + "waiting to be reconciled", + } + } + rows = append(rows, row) + } + utils.printTable(os.Stdout, header, rows) + return nil +} diff --git a/cmd/gotk/reconcile_alert.go b/cmd/gotk/reconcile_alert.go new file mode 100644 index 00000000..6d29afda --- /dev/null +++ b/cmd/gotk/reconcile_alert.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 reconcileAlertCmd = &cobra.Command{ + Use: "alert [name]", + Short: "Reconcile an Alert", + Long: `The reconcile alert command triggers a reconciliation of an Alert resource and waits for it to finish.`, + Example: ` # Trigger a reconciliation for an existing alert + gotk reconcile alert main +`, + RunE: reconcileAlertCmdRun, +} + +func init() { + reconcileCmd.AddCommand(reconcileAlertCmd) +} + +func reconcileAlertCmdRun(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, + } + + logger.Actionf("annotating alert %s in %s namespace", name, namespace) + var alert notificationv1.Alert + err = kubeClient.Get(ctx, namespacedName, &alert) + if err != nil { + return err + } + + if alert.Annotations == nil { + alert.Annotations = map[string]string{ + meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano), + } + } else { + alert.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano) + } + if err := kubeClient.Update(ctx, &alert); err != nil { + return err + } + logger.Successf("alert annotated") + + logger.Waitingf("waiting for reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isAlertReady(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("alert reconciliation completed") + + return nil +} diff --git a/cmd/gotk/reconcile_alertprovider.go b/cmd/gotk/reconcile_alertprovider.go new file mode 100644 index 00000000..15194f79 --- /dev/null +++ b/cmd/gotk/reconcile_alertprovider.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 reconcileAlertProviderCmd = &cobra.Command{ + Use: "alert-provider [name]", + Short: "Reconcile a Provider", + Long: `The reconcile alert-provider command triggers a reconciliation of a Provider resource and waits for it to finish.`, + Example: ` # Trigger a reconciliation for an existing provider + gotk reconcile alert-provider slack +`, + RunE: reconcileAlertProviderCmdRun, +} + +func init() { + reconcileCmd.AddCommand(reconcileAlertProviderCmd) +} + +func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("provider 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 provider %s in %s namespace", name, namespace) + var alertProvider notificationv1.Provider + err = kubeClient.Get(ctx, namespacedName, &alertProvider) + if err != nil { + return err + } + + if alertProvider.Annotations == nil { + alertProvider.Annotations = map[string]string{ + meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano), + } + } else { + alertProvider.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano) + } + if err := kubeClient.Update(ctx, &alertProvider); err != nil { + return err + } + logger.Successf("provider annotated") + + logger.Waitingf("waiting for reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isAlertProviderReady(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("provider reconciliation completed") + + 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_alert.go b/cmd/gotk/resume_alert.go new file mode 100644 index 00000000..30190cb3 --- /dev/null +++ b/cmd/gotk/resume_alert.go @@ -0,0 +1,116 @@ +/* +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 resumeAlertCmd = &cobra.Command{ + Use: "alert [name]", + Short: "Resume a suspended Alert", + Long: `The resume command marks a previously suspended Alert resource for reconciliation and waits for it to +finish the apply.`, + Example: ` # Resume reconciliation for an existing Alert + gotk resume alert main +`, + RunE: resumeAlertCmdRun, +} + +func init() { + resumeCmd.AddCommand(resumeAlertCmd) +} + +func resumeAlertCmdRun(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("resuming Alert %s in %s namespace", name, namespace) + alert.Spec.Suspend = false + if err := kubeClient.Update(ctx, &alert); err != nil { + return err + } + logger.Successf("Alert resumed") + + logger.Waitingf("waiting for Alert reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isAlertResumed(ctx, kubeClient, name, namespace)); err != nil { + return err + } + + logger.Successf("Alert reconciliation completed") + + return nil +} + +func isAlertResumed(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc { + return func() (bool, error) { + var alert notificationv1.Alert + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + + err := kubeClient.Get(ctx, namespacedName, &alert) + if err != nil { + return false, err + } + + if c := meta.GetCondition(alert.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/resume_receiver.go b/cmd/gotk/resume_receiver.go new file mode 100644 index 00000000..14f30e70 --- /dev/null +++ b/cmd/gotk/resume_receiver.go @@ -0,0 +1,116 @@ +/* +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]", + 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 receiver 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 new file mode 100644 index 00000000..9e7a2388 --- /dev/null +++ b/cmd/gotk/suspend_alert.go @@ -0,0 +1,75 @@ +/* +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]", + 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 +} diff --git a/cmd/gotk/suspend_receiver.go b/cmd/gotk/suspend_receiver.go new file mode 100644 index 00000000..bb9d0c0b --- /dev/null +++ b/cmd/gotk/suspend_receiver.go @@ -0,0 +1,75 @@ +/* +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 suspendReceiverCmd = &cobra.Command{ + Use: "receiver [name]", + 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: suspendReceiverCmdRun, +} + +func init() { + suspendCmd.AddCommand(suspendReceiverCmd) +} + +func suspendReceiverCmdRun(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("suspending Receiver %s in %s namespace", name, namespace) + receiver.Spec.Suspend = true + if err := kubeClient.Update(ctx, &receiver); err != nil { + return err + } + logger.Successf("Receiver suspended") + + return nil +} diff --git a/cmd/gotk/utils.go b/cmd/gotk/utils.go index f0707de2..2d80e71d 100644 --- a/cmd/gotk/utils.go +++ b/cmd/gotk/utils.go @@ -43,6 +43,7 @@ import ( helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1" + notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1" "github.com/fluxcd/pkg/runtime/dependency" sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/olekukonko/tablewriter" @@ -137,6 +138,7 @@ func (*Utils) kubeClient(kubeConfigPath string) (client.Client, error) { _ = sourcev1.AddToScheme(scheme) _ = kustomizev1.AddToScheme(scheme) _ = helmv2.AddToScheme(scheme) + _ = notificationv1.AddToScheme(scheme) kubeClient, err := client.New(cfg, client.Options{ Scheme: scheme, diff --git a/docs/cmd/gotk_create.md b/docs/cmd/gotk_create.md index e433c236..c7dcc42a 100644 --- a/docs/cmd/gotk_create.md +++ b/docs/cmd/gotk_create.md @@ -27,7 +27,10 @@ The create sub-commands generate sources and resources. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk create alert](gotk_create_alert.md) - Create or update a Alert resource +* [gotk create alert-provider](gotk_create_alert-provider.md) - Create or update a Provider resource * [gotk create helmrelease](gotk_create_helmrelease.md) - Create or update a HelmRelease resource * [gotk create kustomization](gotk_create_kustomization.md) - Create or update a Kustomization resource +* [gotk create receiver](gotk_create_receiver.md) - Create or update a Receiver resource * [gotk create source](gotk_create_source.md) - Create or update sources diff --git a/docs/cmd/gotk_create_alert-provider.md b/docs/cmd/gotk_create_alert-provider.md new file mode 100644 index 00000000..99552023 --- /dev/null +++ b/docs/cmd/gotk_create_alert-provider.md @@ -0,0 +1,57 @@ +## gotk create alert-provider + +Create or update a Provider resource + +### Synopsis + +The create alert-provider command generates a Provider resource. + +``` +gotk create alert-provider [name] [flags] +``` + +### Examples + +``` + # Create a Provider for a Slack channel + gotk create alert-provider 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 alert-provider github-podinfo \ + --type github \ + --address https://github.com/stefanprodan/podinfo \ + --secret-ref github-token + +``` + +### Options + +``` + --address string path to either the git repository, chat provider or webhook + --channel string channel to send messages to in the case of a chat provider + -h, --help help for alert-provider + --secret-ref string name of secret containing authentication token + --type string type of provider + --username string bot username used by the provider +``` + +### Options inherited from parent commands + +``` + --export export in YAML format to stdout + --interval duration source sync interval (default 1m0s) + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + --label strings set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2) + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk create](gotk_create.md) - Create or update sources and resources + diff --git a/docs/cmd/gotk_create_alert.md b/docs/cmd/gotk_create_alert.md new file mode 100644 index 00000000..3b1e2adc --- /dev/null +++ b/docs/cmd/gotk_create_alert.md @@ -0,0 +1,49 @@ +## gotk create alert + +Create or update a Alert resource + +### Synopsis + +The create alert command generates a Alert resource. + +``` +gotk create alert [name] [flags] +``` + +### Examples + +``` + # Create an Alert for kustomization events + gotk create alert \ + --event-severity info \ + --event-source Kustomization/gotk-system \ + --provider-ref slack \ + gotk-system + +``` + +### Options + +``` + --event-severity string severity of events to send alerts for + --event-source stringArray sources that should generate alerts (/) + -h, --help help for alert + --provider-ref string reference to provider +``` + +### Options inherited from parent commands + +``` + --export export in YAML format to stdout + --interval duration source sync interval (default 1m0s) + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + --label strings set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2) + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk create](gotk_create.md) - Create or update sources and resources + diff --git a/docs/cmd/gotk_create_receiver.md b/docs/cmd/gotk_create_receiver.md new file mode 100644 index 00000000..d6d053b9 --- /dev/null +++ b/docs/cmd/gotk_create_receiver.md @@ -0,0 +1,52 @@ +## gotk create receiver + +Create or update a Receiver resource + +### Synopsis + +The create receiver command generates a Receiver resource. + +``` +gotk create receiver [name] [flags] +``` + +### Examples + +``` + # Create a Receiver + gotk create receiver github-receiver \ + --type github \ + --event ping \ + --event push \ + --secret-ref webhook-token \ + --resource GitRepository/webapp \ + --resource HelmRepository/webapp + +``` + +### Options + +``` + --event stringArray + -h, --help help for receiver + --resource stringArray + --secret-ref string + --type string +``` + +### Options inherited from parent commands + +``` + --export export in YAML format to stdout + --interval duration source sync interval (default 1m0s) + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + --label strings set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2) + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk create](gotk_create.md) - Create or update sources and resources + diff --git a/docs/cmd/gotk_delete.md b/docs/cmd/gotk_delete.md index 5f92dacc..7f9bc144 100644 --- a/docs/cmd/gotk_delete.md +++ b/docs/cmd/gotk_delete.md @@ -25,7 +25,10 @@ The delete sub-commands delete sources and resources. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk delete alert](gotk_delete_alert.md) - Delete a Alert resource +* [gotk delete alert-provider](gotk_delete_alert-provider.md) - Delete a Provider resource * [gotk delete helmrelease](gotk_delete_helmrelease.md) - Delete a HelmRelease resource * [gotk delete kustomization](gotk_delete_kustomization.md) - Delete a Kustomization resource +* [gotk delete receiver](gotk_delete_receiver.md) - Delete a Receiver resource * [gotk delete source](gotk_delete_source.md) - Delete sources diff --git a/docs/cmd/gotk_delete_alert-provider.md b/docs/cmd/gotk_delete_alert-provider.md new file mode 100644 index 00000000..b380a787 --- /dev/null +++ b/docs/cmd/gotk_delete_alert-provider.md @@ -0,0 +1,40 @@ +## gotk delete alert-provider + +Delete a Provider resource + +### Synopsis + +The delete alert-provider command removes the given Provider from the cluster. + +``` +gotk delete alert-provider [name] [flags] +``` + +### Examples + +``` + # Delete a Provider and the Kubernetes resources created by it + gotk delete alert-provider slack + +``` + +### Options + +``` + -h, --help help for alert-provider +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + -s, --silent delete resource without asking for confirmation + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk delete](gotk_delete.md) - Delete sources and resources + diff --git a/docs/cmd/gotk_delete_alert.md b/docs/cmd/gotk_delete_alert.md new file mode 100644 index 00000000..8feaa70b --- /dev/null +++ b/docs/cmd/gotk_delete_alert.md @@ -0,0 +1,40 @@ +## gotk delete alert + +Delete a Alert resource + +### Synopsis + +The delete alert command removes the given Alert from the cluster. + +``` +gotk delete alert [name] [flags] +``` + +### Examples + +``` + # Delete an Alert and the Kubernetes resources created by it + gotk delete alert main + +``` + +### Options + +``` + -h, --help help for alert +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + -s, --silent delete resource without asking for confirmation + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk delete](gotk_delete.md) - Delete sources and resources + diff --git a/docs/cmd/gotk_delete_receiver.md b/docs/cmd/gotk_delete_receiver.md new file mode 100644 index 00000000..063ec5c3 --- /dev/null +++ b/docs/cmd/gotk_delete_receiver.md @@ -0,0 +1,40 @@ +## gotk delete receiver + +Delete a Receiver resource + +### Synopsis + +The delete receiver command removes the given Receiver from the cluster. + +``` +gotk delete receiver [name] [flags] +``` + +### Examples + +``` + # Delete an Receiver and the Kubernetes resources created by it + gotk delete receiver main + +``` + +### Options + +``` + -h, --help help for receiver +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + -s, --silent delete resource without asking for confirmation + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk delete](gotk_delete.md) - Delete sources and resources + diff --git a/docs/cmd/gotk_export.md b/docs/cmd/gotk_export.md index 6c01e19b..e312609d 100644 --- a/docs/cmd/gotk_export.md +++ b/docs/cmd/gotk_export.md @@ -25,7 +25,10 @@ The export sub-commands export resources in YAML format. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk export alert](gotk_export_alert.md) - Export Alert resources in YAML format +* [gotk export alert-provider](gotk_export_alert-provider.md) - Export Provider resources in YAML format * [gotk export helmrelease](gotk_export_helmrelease.md) - Export HelmRelease resources in YAML format * [gotk export kustomization](gotk_export_kustomization.md) - Export Kustomization resources in YAML format +* [gotk export receiver](gotk_export_receiver.md) - Export Receiver resources in YAML format * [gotk export source](gotk_export_source.md) - Export sources diff --git a/docs/cmd/gotk_export_alert-provider.md b/docs/cmd/gotk_export_alert-provider.md new file mode 100644 index 00000000..f465b79f --- /dev/null +++ b/docs/cmd/gotk_export_alert-provider.md @@ -0,0 +1,43 @@ +## gotk export alert-provider + +Export Provider resources in YAML format + +### Synopsis + +The export alert-provider command exports one or all Provider resources in YAML format. + +``` +gotk export alert-provider [name] [flags] +``` + +### Examples + +``` + # Export all Provider resources + gotk export alert-provider --all > alert-providers.yaml + + # Export a Provider + gotk export alert-provider slack > slack.yaml + +``` + +### Options + +``` + -h, --help help for alert-provider +``` + +### Options inherited from parent commands + +``` + --all select all resources + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk export](gotk_export.md) - Export resources in YAML format + diff --git a/docs/cmd/gotk_export_alert.md b/docs/cmd/gotk_export_alert.md new file mode 100644 index 00000000..86222f76 --- /dev/null +++ b/docs/cmd/gotk_export_alert.md @@ -0,0 +1,43 @@ +## gotk export alert + +Export Alert resources in YAML format + +### Synopsis + +The export alert command exports one or all Alert resources in YAML format. + +``` +gotk export alert [name] [flags] +``` + +### Examples + +``` + # Export all Alert resources + gotk export alert --all > alerts.yaml + + # Export a Alert + gotk export alert main > main.yaml + +``` + +### Options + +``` + -h, --help help for alert +``` + +### Options inherited from parent commands + +``` + --all select all resources + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk export](gotk_export.md) - Export resources in YAML format + diff --git a/docs/cmd/gotk_export_receiver.md b/docs/cmd/gotk_export_receiver.md new file mode 100644 index 00000000..2d884c57 --- /dev/null +++ b/docs/cmd/gotk_export_receiver.md @@ -0,0 +1,43 @@ +## gotk export receiver + +Export Receiver resources in YAML format + +### Synopsis + +The export receiver command exports one or all Receiver resources in YAML format. + +``` +gotk export receiver [name] [flags] +``` + +### Examples + +``` + # Export all Receiver resources + gotk export receiver --all > receivers.yaml + + # Export a Receiver + gotk export receiver main > main.yaml + +``` + +### Options + +``` + -h, --help help for receiver +``` + +### Options inherited from parent commands + +``` + --all select all resources + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk export](gotk_export.md) - Export resources in YAML format + diff --git a/docs/cmd/gotk_get.md b/docs/cmd/gotk_get.md index 22163ae1..47f1ba03 100644 --- a/docs/cmd/gotk_get.md +++ b/docs/cmd/gotk_get.md @@ -25,7 +25,10 @@ The get sub-commands print the statuses of sources and resources. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk get alert-providers](gotk_get_alert-providers.md) - Get Provider statuses +* [gotk get alerts](gotk_get_alerts.md) - Get Alert statuses * [gotk get helmreleases](gotk_get_helmreleases.md) - Get HelmRelease statuses * [gotk get kustomizations](gotk_get_kustomizations.md) - Get Kustomization statuses +* [gotk get receivers](gotk_get_receivers.md) - Get Receiver statuses * [gotk get sources](gotk_get_sources.md) - Get source statuses diff --git a/docs/cmd/gotk_get_alert-provider.md b/docs/cmd/gotk_get_alert-provider.md new file mode 100644 index 00000000..0a4a8896 --- /dev/null +++ b/docs/cmd/gotk_get_alert-provider.md @@ -0,0 +1,40 @@ +## gotk get alert-provider + +Get Provider statuses + +### Synopsis + +The get alert-provider command prints the statuses of the resources. + +``` +gotk get alert-provider [flags] +``` + +### Examples + +``` + # List all Providers and their status + gotk get alert-provider + +``` + +### Options + +``` + -h, --help help for alert-provider +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk get](gotk_get.md) - Get sources and resources + diff --git a/docs/cmd/gotk_get_alert-providers.md b/docs/cmd/gotk_get_alert-providers.md new file mode 100644 index 00000000..e4827a67 --- /dev/null +++ b/docs/cmd/gotk_get_alert-providers.md @@ -0,0 +1,40 @@ +## gotk get alert-providers + +Get Provider statuses + +### Synopsis + +The get alert-provider command prints the statuses of the resources. + +``` +gotk get alert-providers [flags] +``` + +### Examples + +``` + # List all Providers and their status + gotk get alert-providers + +``` + +### Options + +``` + -h, --help help for alert-providers +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk get](gotk_get.md) - Get sources and resources + diff --git a/docs/cmd/gotk_get_alert.md b/docs/cmd/gotk_get_alert.md new file mode 100644 index 00000000..90457d46 --- /dev/null +++ b/docs/cmd/gotk_get_alert.md @@ -0,0 +1,40 @@ +## gotk get alert + +Get Alert statuses + +### Synopsis + +The get alert command prints the statuses of the resources. + +``` +gotk get alert [flags] +``` + +### Examples + +``` + # List all Alerts and their status + gotk get alert + +``` + +### Options + +``` + -h, --help help for alert +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk get](gotk_get.md) - Get sources and resources + diff --git a/docs/cmd/gotk_get_alerts.md b/docs/cmd/gotk_get_alerts.md new file mode 100644 index 00000000..4a403d00 --- /dev/null +++ b/docs/cmd/gotk_get_alerts.md @@ -0,0 +1,40 @@ +## gotk get alerts + +Get Alert statuses + +### Synopsis + +The get alert command prints the statuses of the resources. + +``` +gotk get alerts [flags] +``` + +### Examples + +``` + # List all Alerts and their status + gotk get alerts + +``` + +### Options + +``` + -h, --help help for alerts +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk get](gotk_get.md) - Get sources and resources + diff --git a/docs/cmd/gotk_get_receiver.md b/docs/cmd/gotk_get_receiver.md new file mode 100644 index 00000000..e5de9e1c --- /dev/null +++ b/docs/cmd/gotk_get_receiver.md @@ -0,0 +1,40 @@ +## gotk get receiver + +Get Receiver statuses + +### Synopsis + +The get receiver command prints the statuses of the resources. + +``` +gotk get receiver [flags] +``` + +### Examples + +``` + # List all Receiver and their status + gotk get receiver + +``` + +### Options + +``` + -h, --help help for receiver +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk get](gotk_get.md) - Get sources and resources + diff --git a/docs/cmd/gotk_get_receivers.md b/docs/cmd/gotk_get_receivers.md new file mode 100644 index 00000000..211370c7 --- /dev/null +++ b/docs/cmd/gotk_get_receivers.md @@ -0,0 +1,40 @@ +## gotk get receivers + +Get Receiver statuses + +### Synopsis + +The get receiver command prints the statuses of the resources. + +``` +gotk get receivers [flags] +``` + +### Examples + +``` + # List all Receiver and their status + gotk get receivers + +``` + +### Options + +``` + -h, --help help for receivers +``` + +### Options inherited from parent commands + +``` + -A, --all-namespaces list the requested object(s) across all namespaces + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk get](gotk_get.md) - Get sources and resources + diff --git a/docs/cmd/gotk_reconcile.md b/docs/cmd/gotk_reconcile.md index 52e41d7a..9d4e3293 100644 --- a/docs/cmd/gotk_reconcile.md +++ b/docs/cmd/gotk_reconcile.md @@ -24,7 +24,10 @@ The reconcile sub-commands trigger a reconciliation of sources and resources. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk reconcile alert](gotk_reconcile_alert.md) - Reconcile an Alert +* [gotk reconcile alert-provider](gotk_reconcile_alert-provider.md) - Reconcile a Provider * [gotk reconcile helmrelease](gotk_reconcile_helmrelease.md) - Reconcile a HelmRelease resource * [gotk reconcile kustomization](gotk_reconcile_kustomization.md) - Reconcile a Kustomization resource +* [gotk reconcile receiver](gotk_reconcile_receiver.md) - Reconcile a Receiver * [gotk reconcile source](gotk_reconcile_source.md) - Reconcile sources diff --git a/docs/cmd/gotk_reconcile_alert-provider.md b/docs/cmd/gotk_reconcile_alert-provider.md new file mode 100644 index 00000000..a8c3c2aa --- /dev/null +++ b/docs/cmd/gotk_reconcile_alert-provider.md @@ -0,0 +1,39 @@ +## gotk reconcile alert-provider + +Reconcile a Provider + +### Synopsis + +The reconcile alert-provider command triggers a reconciliation of a Provider resource and waits for it to finish. + +``` +gotk reconcile alert-provider [name] [flags] +``` + +### Examples + +``` + # Trigger a reconciliation for an existing provider + gotk reconcile alert-provider slack + +``` + +### Options + +``` + -h, --help help for alert-provider +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk reconcile](gotk_reconcile.md) - Reconcile sources and resources + diff --git a/docs/cmd/gotk_reconcile_alert.md b/docs/cmd/gotk_reconcile_alert.md new file mode 100644 index 00000000..7a9244b9 --- /dev/null +++ b/docs/cmd/gotk_reconcile_alert.md @@ -0,0 +1,39 @@ +## gotk reconcile alert + +Reconcile an Alert + +### Synopsis + +The reconcile alert command triggers a reconciliation of an Alert resource and waits for it to finish. + +``` +gotk reconcile alert [name] [flags] +``` + +### Examples + +``` + # Trigger a reconciliation for an existing alert + gotk reconcile alert main + +``` + +### Options + +``` + -h, --help help for alert +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk reconcile](gotk_reconcile.md) - Reconcile sources and resources + diff --git a/docs/cmd/gotk_reconcile_receiver.md b/docs/cmd/gotk_reconcile_receiver.md new file mode 100644 index 00000000..4072a478 --- /dev/null +++ b/docs/cmd/gotk_reconcile_receiver.md @@ -0,0 +1,39 @@ +## gotk reconcile receiver + +Reconcile a Receiver + +### Synopsis + +The reconcile receiver command triggers a reconciliation of a Receiver resource and waits for it to finish. + +``` +gotk reconcile receiver [name] [flags] +``` + +### Examples + +``` + # Trigger a reconciliation for an existing receiver + gotk reconcile receiver main + +``` + +### Options + +``` + -h, --help help for receiver +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk reconcile](gotk_reconcile.md) - Reconcile sources and resources + diff --git a/docs/cmd/gotk_resume.md b/docs/cmd/gotk_resume.md index 451681e0..ed652fb1 100644 --- a/docs/cmd/gotk_resume.md +++ b/docs/cmd/gotk_resume.md @@ -24,6 +24,8 @@ The resume sub-commands resume a suspended resource. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk resume alert](gotk_resume_alert.md) - Resume a suspended Alert * [gotk resume helmrelease](gotk_resume_helmrelease.md) - Resume a suspended HelmRelease * [gotk resume kustomization](gotk_resume_kustomization.md) - Resume a suspended Kustomization +* [gotk resume receiver](gotk_resume_receiver.md) - Resume a suspended Receiver diff --git a/docs/cmd/gotk_resume_alert.md b/docs/cmd/gotk_resume_alert.md new file mode 100644 index 00000000..81b5f9e9 --- /dev/null +++ b/docs/cmd/gotk_resume_alert.md @@ -0,0 +1,40 @@ +## gotk resume alert + +Resume a suspended Alert + +### Synopsis + +The resume command marks a previously suspended Alert resource for reconciliation and waits for it to +finish the apply. + +``` +gotk resume alert [name] [flags] +``` + +### Examples + +``` + # Resume reconciliation for an existing Alert + gotk resume alert main + +``` + +### Options + +``` + -h, --help help for alert +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk resume](gotk_resume.md) - Resume suspended resources + diff --git a/docs/cmd/gotk_resume_receiver.md b/docs/cmd/gotk_resume_receiver.md new file mode 100644 index 00000000..eb3d2317 --- /dev/null +++ b/docs/cmd/gotk_resume_receiver.md @@ -0,0 +1,40 @@ +## gotk resume receiver + +Resume a suspended Receiver + +### Synopsis + +The resume command marks a previously suspended Receiver resource for reconciliation and waits for it to +finish the apply. + +``` +gotk resume receiver [name] [flags] +``` + +### Examples + +``` + # Resume reconciliation for an existing Receiver + gotk resume receiver main + +``` + +### Options + +``` + -h, --help help for receiver +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk resume](gotk_resume.md) - Resume suspended resources + diff --git a/docs/cmd/gotk_suspend.md b/docs/cmd/gotk_suspend.md index 957cf606..157c19af 100644 --- a/docs/cmd/gotk_suspend.md +++ b/docs/cmd/gotk_suspend.md @@ -24,6 +24,8 @@ The suspend sub-commands suspend the reconciliation of a resource. ### SEE ALSO * [gotk](gotk.md) - Command line utility for assembling Kubernetes CD pipelines +* [gotk suspend alert](gotk_suspend_alert.md) - Suspend reconciliation of Alert * [gotk suspend helmrelease](gotk_suspend_helmrelease.md) - Suspend reconciliation of HelmRelease * [gotk suspend kustomization](gotk_suspend_kustomization.md) - Suspend reconciliation of Kustomization +* [gotk suspend receiver](gotk_suspend_receiver.md) - Suspend reconciliation of Receiver diff --git a/docs/cmd/gotk_suspend_alert.md b/docs/cmd/gotk_suspend_alert.md new file mode 100644 index 00000000..13fc6129 --- /dev/null +++ b/docs/cmd/gotk_suspend_alert.md @@ -0,0 +1,39 @@ +## gotk suspend alert + +Suspend reconciliation of Alert + +### Synopsis + +The suspend command disables the reconciliation of a Alert resource. + +``` +gotk suspend alert [name] [flags] +``` + +### Examples + +``` + # Suspend reconciliation for an existing Alert + gotk suspend alert main + +``` + +### Options + +``` + -h, --help help for alert +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk suspend](gotk_suspend.md) - Suspend resources + diff --git a/docs/cmd/gotk_suspend_receiver.md b/docs/cmd/gotk_suspend_receiver.md new file mode 100644 index 00000000..af78dbf0 --- /dev/null +++ b/docs/cmd/gotk_suspend_receiver.md @@ -0,0 +1,39 @@ +## gotk suspend receiver + +Suspend reconciliation of Receiver + +### Synopsis + +The suspend command disables the reconciliation of a Receiver resource. + +``` +gotk suspend receiver [name] [flags] +``` + +### Examples + +``` + # Suspend reconciliation for an existing Receiver + gotk suspend receiver main + +``` + +### Options + +``` + -h, --help help for receiver +``` + +### Options inherited from parent commands + +``` + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "gotk-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [gotk suspend](gotk_suspend.md) - Suspend resources + diff --git a/go.mod b/go.mod index 8742d0de..db86c74d 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/fluxcd/helm-controller/api v0.1.1 github.com/fluxcd/kustomize-controller/api v0.1.0 + github.com/fluxcd/notification-controller/api v0.1.0 github.com/fluxcd/pkg/apis/meta v0.0.2 github.com/fluxcd/pkg/git v0.0.7 github.com/fluxcd/pkg/runtime v0.0.6 diff --git a/go.sum b/go.sum index 727871a7..568b16c3 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,8 @@ github.com/fluxcd/helm-controller/api v0.1.1 h1:iKskkLGRYRi5hiZg/+Rn+rpneGPayGQP github.com/fluxcd/helm-controller/api v0.1.1/go.mod h1:orwdS+iYGcM8BReUQfIb5CJ+jiFdlKmnLnzp6K3FK2U= github.com/fluxcd/kustomize-controller/api v0.1.0 h1:dPowX408q0jO7wnWBj5Dglc22euAQBLxDhPS8XHlLM0= github.com/fluxcd/kustomize-controller/api v0.1.0/go.mod h1:upR7/OzX/wXJlKgiBLUn7ez4XG4Lo5edep2WKSx0u7c= +github.com/fluxcd/notification-controller/api v0.1.0 h1:+gJ0CFFg3OkjLGl48gBCVgqNbKNy54xzfjYVlPp8064= +github.com/fluxcd/notification-controller/api v0.1.0/go.mod h1:w1gILYTSqt3dFMYRmCihA/K84yDBfIkL5m5dcbaUyUY= github.com/fluxcd/pkg/apis/meta v0.0.2 h1:kyA4Y0IzNjf1joBOnFqpWG7aNDHvtLExZcaHQM7qhRI= github.com/fluxcd/pkg/apis/meta v0.0.2/go.mod h1:nCNps5JJOcEQr3MNDmZqI4o0chjePSUYL6Q2ktDtotU= github.com/fluxcd/pkg/git v0.0.7 h1:tFSYPy7tcIYfOt8H5EUERXIRz7fk0id302oQZde1NtU=