From e7ff319685556b0a5a490b7722c54d23b4f1f84d Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Thu, 26 Nov 2020 16:40:54 +0200 Subject: [PATCH] Add resume source commands Signed-off-by: Stefan Prodan --- cmd/flux/resume_helmrelease.go | 3 - cmd/flux/resume_kustomization.go | 3 - cmd/flux/resume_source.go | 31 +++++++ cmd/flux/resume_source_bucket.go | 115 ++++++++++++++++++++++++++ cmd/flux/resume_source_chart.go | 115 ++++++++++++++++++++++++++ cmd/flux/resume_source_git.go | 115 ++++++++++++++++++++++++++ cmd/flux/resume_source_helm.go | 115 ++++++++++++++++++++++++++ docs/cmd/flux_resume.md | 1 + docs/cmd/flux_resume_source.md | 32 +++++++ docs/cmd/flux_resume_source_bucket.md | 40 +++++++++ docs/cmd/flux_resume_source_chart.md | 40 +++++++++ docs/cmd/flux_resume_source_git.md | 40 +++++++++ docs/cmd/flux_resume_source_helm.md | 40 +++++++++ 13 files changed, 684 insertions(+), 6 deletions(-) create mode 100644 cmd/flux/resume_source.go create mode 100644 cmd/flux/resume_source_bucket.go create mode 100644 cmd/flux/resume_source_chart.go create mode 100644 cmd/flux/resume_source_git.go create mode 100644 cmd/flux/resume_source_helm.go create mode 100644 docs/cmd/flux_resume_source.md create mode 100644 docs/cmd/flux_resume_source_bucket.md create mode 100644 docs/cmd/flux_resume_source_chart.md create mode 100644 docs/cmd/flux_resume_source_git.md create mode 100644 docs/cmd/flux_resume_source_helm.md diff --git a/cmd/flux/resume_helmrelease.go b/cmd/flux/resume_helmrelease.go index 7b0da873..4e5eebb0 100644 --- a/cmd/flux/resume_helmrelease.go +++ b/cmd/flux/resume_helmrelease.go @@ -109,9 +109,6 @@ func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client, case metav1.ConditionTrue: return true, nil case metav1.ConditionFalse: - if c.Reason == meta.SuspendedReason { - return false, nil - } return false, fmt.Errorf(c.Message) } } diff --git a/cmd/flux/resume_kustomization.go b/cmd/flux/resume_kustomization.go index b1046674..58d41cdc 100644 --- a/cmd/flux/resume_kustomization.go +++ b/cmd/flux/resume_kustomization.go @@ -108,9 +108,6 @@ func isKustomizationResumed(ctx context.Context, kubeClient client.Client, case metav1.ConditionTrue: return true, nil case metav1.ConditionFalse: - if c.Reason == meta.SuspendedReason { - return false, nil - } return false, fmt.Errorf(c.Message) } } diff --git a/cmd/flux/resume_source.go b/cmd/flux/resume_source.go new file mode 100644 index 00000000..dae04830 --- /dev/null +++ b/cmd/flux/resume_source.go @@ -0,0 +1,31 @@ +/* +Copyright 2020 The Flux authors + +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 ( + "github.com/spf13/cobra" +) + +var resumeSourceCmd = &cobra.Command{ + Use: "source", + Short: "Resume sources", + Long: "The resume sub-commands resume a suspended source.", +} + +func init() { + resumeCmd.AddCommand(resumeSourceCmd) +} diff --git a/cmd/flux/resume_source_bucket.go b/cmd/flux/resume_source_bucket.go new file mode 100644 index 00000000..895d1c69 --- /dev/null +++ b/cmd/flux/resume_source_bucket.go @@ -0,0 +1,115 @@ +/* +Copyright 2020 The Flux authors + +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/flux2/internal/utils" + "github.com/fluxcd/pkg/apis/meta" + + "github.com/spf13/cobra" + apimeta "k8s.io/apimachinery/pkg/api/meta" + 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" + + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" +) + +var resumeSourceBucketCmd = &cobra.Command{ + Use: "bucket [name]", + Short: "Resume a suspended Bucket", + Long: `The resume command marks a previously suspended Bucket resource for reconciliation and waits for it to finish.`, + Example: ` # Resume reconciliation for an existing Bucket + flux resume source bucket podinfo +`, + RunE: resumeSourceBucketCmdRun, +} + +func init() { + resumeSourceCmd.AddCommand(resumeSourceBucketCmd) +} + +func resumeSourceBucketCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("source name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var bucket sourcev1.Bucket + err = kubeClient.Get(ctx, namespacedName, &bucket) + if err != nil { + return err + } + + logger.Actionf("resuming source %s in %s namespace", name, namespace) + bucket.Spec.Suspend = false + if err := kubeClient.Update(ctx, &bucket); err != nil { + return err + } + logger.Successf("source resumed") + + logger.Waitingf("waiting for Bucket reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isBucketResumed(ctx, kubeClient, namespacedName, &bucket)); err != nil { + return err + } + logger.Successf("Bucket reconciliation completed") + + logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision) + return nil +} + +func isBucketResumed(ctx context.Context, kubeClient client.Client, + namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc { + return func() (bool, error) { + err := kubeClient.Get(ctx, namespacedName, bucket) + if err != nil { + return false, err + } + + // Confirm the state we are observing is for the current generation + if bucket.Generation != bucket.Status.ObservedGeneration { + return false, nil + } + + if c := apimeta.FindStatusCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case metav1.ConditionTrue: + return true, nil + case metav1.ConditionFalse: + return false, fmt.Errorf(c.Message) + } + } + return false, nil + } +} diff --git a/cmd/flux/resume_source_chart.go b/cmd/flux/resume_source_chart.go new file mode 100644 index 00000000..8f3d1bfe --- /dev/null +++ b/cmd/flux/resume_source_chart.go @@ -0,0 +1,115 @@ +/* +Copyright 2020 The Flux authors + +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/flux2/internal/utils" + "github.com/fluxcd/pkg/apis/meta" + + "github.com/spf13/cobra" + apimeta "k8s.io/apimachinery/pkg/api/meta" + 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" + + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" +) + +var resumeSourceHelmChartCmd = &cobra.Command{ + Use: "chart [name]", + Short: "Resume a suspended HelmChart", + Long: `The resume command marks a previously suspended HelmChart resource for reconciliation and waits for it to finish.`, + Example: ` # Resume reconciliation for an existing HelmChart + flux resume source chart podinfo +`, + RunE: resumeSourceHelmChartCmdRun, +} + +func init() { + resumeSourceCmd.AddCommand(resumeSourceHelmChartCmd) +} + +func resumeSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("source name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var repository sourcev1.HelmChart + err = kubeClient.Get(ctx, namespacedName, &repository) + if err != nil { + return err + } + + logger.Actionf("resuming source %s in %s namespace", name, namespace) + repository.Spec.Suspend = false + if err := kubeClient.Update(ctx, &repository); err != nil { + return err + } + logger.Successf("source resumed") + + logger.Waitingf("waiting for HelmChart reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isHelmChartResumed(ctx, kubeClient, namespacedName, &repository)); err != nil { + return err + } + logger.Successf("HelmChart reconciliation completed") + + logger.Successf("fetched revision %s", repository.Status.Artifact.Revision) + return nil +} + +func isHelmChartResumed(ctx context.Context, kubeClient client.Client, + namespacedName types.NamespacedName, chart *sourcev1.HelmChart) wait.ConditionFunc { + return func() (bool, error) { + err := kubeClient.Get(ctx, namespacedName, chart) + if err != nil { + return false, err + } + + // Confirm the state we are observing is for the current generation + if chart.Generation != chart.Status.ObservedGeneration { + return false, nil + } + + if c := apimeta.FindStatusCondition(chart.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case metav1.ConditionTrue: + return true, nil + case metav1.ConditionFalse: + return false, fmt.Errorf(c.Message) + } + } + return false, nil + } +} diff --git a/cmd/flux/resume_source_git.go b/cmd/flux/resume_source_git.go new file mode 100644 index 00000000..53b386c5 --- /dev/null +++ b/cmd/flux/resume_source_git.go @@ -0,0 +1,115 @@ +/* +Copyright 2020 The Flux authors + +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/flux2/internal/utils" + "github.com/fluxcd/pkg/apis/meta" + + "github.com/spf13/cobra" + apimeta "k8s.io/apimachinery/pkg/api/meta" + 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" + + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" +) + +var resumeSourceGitCmd = &cobra.Command{ + Use: "git [name]", + Short: "Resume a suspended GitRepository", + Long: `The resume command marks a previously suspended GitRepository resource for reconciliation and waits for it to finish.`, + Example: ` # Resume reconciliation for an existing GitRepository + flux resume source git podinfo +`, + RunE: resumeSourceGitCmdRun, +} + +func init() { + resumeSourceCmd.AddCommand(resumeSourceGitCmd) +} + +func resumeSourceGitCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("source name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var repository sourcev1.GitRepository + err = kubeClient.Get(ctx, namespacedName, &repository) + if err != nil { + return err + } + + logger.Actionf("resuming source %s in %s namespace", name, namespace) + repository.Spec.Suspend = false + if err := kubeClient.Update(ctx, &repository); err != nil { + return err + } + logger.Successf("source resumed") + + logger.Waitingf("waiting for GitRepository reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isGitRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil { + return err + } + logger.Successf("GitRepository reconciliation completed") + + logger.Successf("fetched revision %s", repository.Status.Artifact.Revision) + return nil +} + +func isGitRepositoryResumed(ctx context.Context, kubeClient client.Client, + namespacedName types.NamespacedName, repository *sourcev1.GitRepository) wait.ConditionFunc { + return func() (bool, error) { + err := kubeClient.Get(ctx, namespacedName, repository) + if err != nil { + return false, err + } + + // Confirm the state we are observing is for the current generation + if repository.Generation != repository.Status.ObservedGeneration { + return false, nil + } + + if c := apimeta.FindStatusCondition(repository.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case metav1.ConditionTrue: + return true, nil + case metav1.ConditionFalse: + return false, fmt.Errorf(c.Message) + } + } + return false, nil + } +} diff --git a/cmd/flux/resume_source_helm.go b/cmd/flux/resume_source_helm.go new file mode 100644 index 00000000..59d01b5d --- /dev/null +++ b/cmd/flux/resume_source_helm.go @@ -0,0 +1,115 @@ +/* +Copyright 2020 The Flux authors + +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/flux2/internal/utils" + "github.com/fluxcd/pkg/apis/meta" + + "github.com/spf13/cobra" + apimeta "k8s.io/apimachinery/pkg/api/meta" + 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" + + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" +) + +var resumeSourceHelmCmd = &cobra.Command{ + Use: "helm [name]", + Short: "Resume a suspended HelmRepository", + Long: `The resume command marks a previously suspended HelmRepository resource for reconciliation and waits for it to finish.`, + Example: ` # Resume reconciliation for an existing HelmRepository + flux resume source helm bitnami +`, + RunE: resumeSourceHelmCmdRun, +} + +func init() { + resumeSourceCmd.AddCommand(resumeSourceHelmCmd) +} + +func resumeSourceHelmCmdRun(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return fmt.Errorf("source name is required") + } + name := args[0] + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) + if err != nil { + return err + } + + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var repository sourcev1.HelmRepository + err = kubeClient.Get(ctx, namespacedName, &repository) + if err != nil { + return err + } + + logger.Actionf("resuming source %s in %s namespace", name, namespace) + repository.Spec.Suspend = false + if err := kubeClient.Update(ctx, &repository); err != nil { + return err + } + logger.Successf("source resumed") + + logger.Waitingf("waiting for HelmRepository reconciliation") + if err := wait.PollImmediate(pollInterval, timeout, + isHelmRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil { + return err + } + logger.Successf("HelmRepository reconciliation completed") + + logger.Successf("fetched revision %s", repository.Status.Artifact.Revision) + return nil +} + +func isHelmRepositoryResumed(ctx context.Context, kubeClient client.Client, + namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) wait.ConditionFunc { + return func() (bool, error) { + err := kubeClient.Get(ctx, namespacedName, repository) + if err != nil { + return false, err + } + + // Confirm the state we are observing is for the current generation + if repository.Generation != repository.Status.ObservedGeneration { + return false, nil + } + + if c := apimeta.FindStatusCondition(repository.Status.Conditions, meta.ReadyCondition); c != nil { + switch c.Status { + case metav1.ConditionTrue: + return true, nil + case metav1.ConditionFalse: + return false, fmt.Errorf(c.Message) + } + } + return false, nil + } +} diff --git a/docs/cmd/flux_resume.md b/docs/cmd/flux_resume.md index ad74fb86..71bb21fd 100644 --- a/docs/cmd/flux_resume.md +++ b/docs/cmd/flux_resume.md @@ -29,4 +29,5 @@ The resume sub-commands resume a suspended resource. * [flux resume helmrelease](flux_resume_helmrelease.md) - Resume a suspended HelmRelease * [flux resume kustomization](flux_resume_kustomization.md) - Resume a suspended Kustomization * [flux resume receiver](flux_resume_receiver.md) - Resume a suspended Receiver +* [flux resume source](flux_resume_source.md) - Resume sources diff --git a/docs/cmd/flux_resume_source.md b/docs/cmd/flux_resume_source.md new file mode 100644 index 00000000..d2c06c14 --- /dev/null +++ b/docs/cmd/flux_resume_source.md @@ -0,0 +1,32 @@ +## flux resume source + +Resume sources + +### Synopsis + +The resume sub-commands resume a suspended source. + +### Options + +``` + -h, --help help for source +``` + +### Options inherited from parent commands + +``` + --context string kubernetes context to use + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux resume](flux_resume.md) - Resume suspended resources +* [flux resume source bucket](flux_resume_source_bucket.md) - Resume a suspended Bucket +* [flux resume source chart](flux_resume_source_chart.md) - Resume a suspended HelmChart +* [flux resume source git](flux_resume_source_git.md) - Resume a suspended GitRepository +* [flux resume source helm](flux_resume_source_helm.md) - Resume a suspended HelmRepository + diff --git a/docs/cmd/flux_resume_source_bucket.md b/docs/cmd/flux_resume_source_bucket.md new file mode 100644 index 00000000..58916381 --- /dev/null +++ b/docs/cmd/flux_resume_source_bucket.md @@ -0,0 +1,40 @@ +## flux resume source bucket + +Resume a suspended Bucket + +### Synopsis + +The resume command marks a previously suspended Bucket resource for reconciliation and waits for it to finish. + +``` +flux resume source bucket [name] [flags] +``` + +### Examples + +``` + # Resume reconciliation for an existing Bucket + flux resume source bucket podinfo + +``` + +### Options + +``` + -h, --help help for bucket +``` + +### Options inherited from parent commands + +``` + --context string kubernetes context to use + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux resume source](flux_resume_source.md) - Resume sources + diff --git a/docs/cmd/flux_resume_source_chart.md b/docs/cmd/flux_resume_source_chart.md new file mode 100644 index 00000000..8d3c562e --- /dev/null +++ b/docs/cmd/flux_resume_source_chart.md @@ -0,0 +1,40 @@ +## flux resume source chart + +Resume a suspended HelmChart + +### Synopsis + +The resume command marks a previously suspended HelmChart resource for reconciliation and waits for it to finish. + +``` +flux resume source chart [name] [flags] +``` + +### Examples + +``` + # Resume reconciliation for an existing HelmChart + flux resume source chart podinfo + +``` + +### Options + +``` + -h, --help help for chart +``` + +### Options inherited from parent commands + +``` + --context string kubernetes context to use + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux resume source](flux_resume_source.md) - Resume sources + diff --git a/docs/cmd/flux_resume_source_git.md b/docs/cmd/flux_resume_source_git.md new file mode 100644 index 00000000..195be5ed --- /dev/null +++ b/docs/cmd/flux_resume_source_git.md @@ -0,0 +1,40 @@ +## flux resume source git + +Resume a suspended GitRepository + +### Synopsis + +The resume command marks a previously suspended GitRepository resource for reconciliation and waits for it to finish. + +``` +flux resume source git [name] [flags] +``` + +### Examples + +``` + # Resume reconciliation for an existing GitRepository + flux resume source git podinfo + +``` + +### Options + +``` + -h, --help help for git +``` + +### Options inherited from parent commands + +``` + --context string kubernetes context to use + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux resume source](flux_resume_source.md) - Resume sources + diff --git a/docs/cmd/flux_resume_source_helm.md b/docs/cmd/flux_resume_source_helm.md new file mode 100644 index 00000000..be7f75cd --- /dev/null +++ b/docs/cmd/flux_resume_source_helm.md @@ -0,0 +1,40 @@ +## flux resume source helm + +Resume a suspended HelmRepository + +### Synopsis + +The resume command marks a previously suspended HelmRepository resource for reconciliation and waits for it to finish. + +``` +flux resume source helm [name] [flags] +``` + +### Examples + +``` + # Resume reconciliation for an existing HelmRepository + flux resume source helm bitnami + +``` + +### Options + +``` + -h, --help help for helm +``` + +### Options inherited from parent commands + +``` + --context string kubernetes context to use + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux resume source](flux_resume_source.md) - Resume sources +