1
0
mirror of synced 2026-03-01 19:26:55 +00:00

Compare commits

..

42 Commits

Author SHA1 Message Date
Stefan Prodan
22df860eca Merge pull request #849 from fluxcd/update-components
Update toolkit components
2021-02-02 18:07:29 +02:00
fluxcdbot
f395044d65 Update toolkit components 2021-02-02 15:40:37 +00:00
Hidde Beydals
afe0ddcd84 Merge pull request #824 from fluxcd/upgrade-semver-tip
Highlight PATCH versions can be used to upgrade
2021-02-01 18:41:34 +01:00
Hidde Beydals
2c0323684c Highlight PATCH versions can be used to upgrade
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-02-01 18:21:54 +01:00
Hidde Beydals
6d5ffdea57 Merge pull request #841 from fluxcd/update-components
Update toolkit components
2021-02-01 18:07:15 +01:00
fluxcdbot
648af6e645 Update toolkit components 2021-02-01 16:50:07 +00:00
Hidde Beydals
e1895a4e21 Merge pull request #840 from relu/fix-image-update-docs-ecr-cronjob
Improve image update CronJob examples
2021-02-01 17:49:31 +01:00
Aurel Canciu
d5f45800ae Clarify how to use the generated cronjob secret
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-02-01 17:11:14 +01:00
Aurel Canciu
51f9d249ff Fix image update guide ECR cronjob manifest
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-02-01 17:11:14 +01:00
Hidde Beydals
6f525356cb Merge pull request #837 from aholbreich/patch-1 2021-02-01 17:10:54 +01:00
Alexander Holbreich
5008f9064e Update image-update.md
Increase attention to missing flux components.

Signed-off-by: Alexander Holbreich <alexander@holbreich.org>
2021-02-01 16:53:19 +01:00
Stefan Prodan
cff96ed7ca Merge pull request #834 from fluxcd/fix-secret-cmd
Fix create secret commands
2021-01-30 16:36:44 +02:00
Stefan Prodan
4e8a600f34 Add e2e tests for create secret commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-30 15:19:45 +02:00
Stefan Prodan
4fd5684277 Fix create secret commands
Regression bug introduced in https://github.com/fluxcd/flux2/pull/788

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-30 15:07:48 +02:00
Hidde Beydals
06bf469ba7 Merge pull request #825 from SomtochiAma/refactor-reconcile-command
Refactor resume command
2021-01-29 19:52:07 +01:00
Somtochi Onyekwere
b8a215230c refactor resume command
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-29 19:05:38 +01:00
Stefan Prodan
2460cfcf1c Merge pull request #821 from fluxcd/docs-helm-faq
Add HelmChart not ready to FAQ
2021-01-29 17:05:39 +02:00
Stefan Prodan
364242c857 Add HelmChart not ready to FAQ
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-29 16:20:35 +02:00
Stefan Prodan
29e2900f59 Merge pull request #818 from fluxcd/docs-image-webhook
Add webhook section to image update docs
2021-01-29 13:33:17 +02:00
Stefan Prodan
61e1fb770e Add webhook section to image update docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-29 13:09:01 +02:00
Stefan Prodan
2d3fcbdea3 Merge pull request #815 from fluxcd/e2e-kube-1.20.2
Update e2e tests to Kubernetes v1.20.2
2021-01-29 09:49:42 +02:00
Stefan Prodan
47e15cee3d Update e2e tests to Kubernetes v1.20.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-01-28 19:50:19 +02:00
Stefan Prodan
adeb3e3f42 Merge pull request #814 from mewzherder/patch-9
Community section clarity of purpose + support page link
2021-01-28 19:42:42 +02:00
mewzherder
fb1278285b Community section clarity of purpose + support page link
Signed-off-by: mewzherder <tamao@weave.works>
2021-01-28 09:24:08 -08:00
Stefan Prodan
e371610849 Merge pull request #812 from chanwit/network_policy_e2e
Enable network policy in e2e
2021-01-28 16:46:45 +02:00
Chanwit Kaewkasi
424de63bd1 update KIND to v0.10.0 and node to 1.16.15
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-01-28 21:21:02 +07:00
Chanwit Kaewkasi
832c925d39 setup Calico to enable network policy for e2e testing
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-01-28 21:21:02 +07:00
Chanwit Kaewkasi
378f118d51 add kind config to disable kind-net
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
2021-01-28 21:21:02 +07:00
Hidde Beydals
d651777122 Merge pull request #813 from fluxcd/iua-docs-example-update
Update docs ImageUpdateAutomation example
2021-01-28 15:13:40 +01:00
Aurel Canciu
65d8ebabb8 Update docs ImageUpdateAutomation example
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2021-01-28 15:57:25 +02:00
Hidde Beydals
9195ed9a1b Merge pull request #809 from SomtochiAma/refactor-reconcile-command
Refactor reconcile commands
2021-01-28 14:16:15 +01:00
Somtochi Onyekwere
5df8f7313c Refactor reconcile commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-28 13:21:29 +01:00
Hidde Beydals
25ed6ca0a4 Merge pull request #780 from dholbach/link-to-support-page 2021-01-28 11:59:08 +01:00
Daniel Holbach
9f972995bd add very basic issue template
Also link to support page.

	Fixes: fluxcd/website#77

Signed-off-by: Daniel Holbach <daniel@weave.works>
2021-01-27 17:34:26 +01:00
Hidde Beydals
29c46a9892 Merge pull request #791 from SomtochiAma/refactor-reconcile-commands
Refactor suspend commands
2021-01-27 10:05:32 +01:00
Somtochi Onyekwere
ef579fe596 Refactor suspend commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-27 09:57:37 +01:00
Hidde Beydals
5b268f62a3 Merge pull request #789 from SomtochiAma/refactor-delete-command 2021-01-27 09:57:17 +01:00
Somtochi Onyekwere
1f1c8286a5 Refactor delete command for kustomizations, sources and helmreleases
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2021-01-27 09:43:39 +01:00
Hidde Beydals
5401e1ace4 Merge pull request #794 from fluxcd/get-type-fixes
Use correct type in various get source commands
2021-01-27 09:37:25 +01:00
Hidde Beydals
69294ef56d Use correct type in various get source commands
This fixes a bug where the wrong type was displayed for various
`get source` commands.

```console
$ flux get sources helm --namespace default
✗ no Bucket objects found in default namespace
```

Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-27 09:28:48 +01:00
Hidde Beydals
a685ed8029 Merge pull request #793 from fluxcd/reconcile-w-source-other-ns
Set source namespace when reconciling with source
2021-01-27 09:21:12 +01:00
Hidde Beydals
68d0be3818 Set source namespace when reconciling with source
Signed-off-by: Hidde Beydals <hello@hidde.co>
2021-01-26 22:21:40 +01:00
42 changed files with 562 additions and 1306 deletions

46
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,46 @@
---
name: Bug report
about: Create a report to help us improve Flux v2
title: ''
assignees: ''
---
<!--
Find out more about your support options and getting help at
https://fluxcd.io/support/
-->
### Describe the bug
A clear and concise description of what the bug is.
### To Reproduce
Steps to reproduce the behaviour:
1. Provide Flux install instructions
2. Provide a GitHub repository with Kubernetes manifests
### Expected behavior
A clear and concise description of what you expected to happen.
### Additional context
- Kubernetes version:
- Git provider:
- Container registry provider:
Below please provide the output of the following commands:
```cli
flux --version
flux check
kubectl -n <namespace> get all
kubectl -n <namespace> logs deploy/source-controller
kubectl -n <namespace> logs deploy/kustomize-controller
```

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Ask a question
url: https://github.com/fluxcd/flux2/discussions
about: Please ask and answer questions here.

5
.github/kind/config.yaml vendored Normal file
View File

@@ -0,0 +1,5 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
disableDefaultCNI: true # disable kindnet
podSubnet: 192.168.0.0/16 # set to Calico's default subnet

View File

@@ -26,7 +26,13 @@ jobs:
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0
with:
image: kindest/node:v1.16.9
version: "v0.10.0"
image: kindest/node:v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab
config: .github/kind/config.yaml # disable KIND-net
- name: Setup Calico for network policy
run: |
kubectl apply -f https://docs.projectcalico.org/v3.16/manifests/calico.yaml
kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true
- name: Run test
run: make test
- name: Check if working tree is dirty
@@ -44,6 +50,15 @@ jobs:
- name: flux install --manifests
run: |
./bin/flux install --manifests ./manifests/install/
- name: flux create secret
run: |
./bin/flux create secret git git-ssh-test \
--url ssh://git@github.com/stefanprodan/podinfo
./bin/flux create secret git git-https-test \
--url https://github.com/stefanprodan/podinfo \
--username=test --password=test
./bin/flux create secret helm helm-test \
--username=test --password=test
- name: flux create source git
run: |
./bin/flux create source git podinfo \

View File

@@ -66,6 +66,8 @@ the following guides:
- [Setup Notifications](https://toolkit.fluxcd.io/guides/notifications/)
- [Setup Webhook Receivers](https://toolkit.fluxcd.io/guides/webhook-receivers/)
If you should need help, please refer to our **[Support page](https://fluxcd.io/support/)**.
## GitOps Toolkit
The GitOps Toolkit is the set of APIs and controllers that make up the
@@ -97,15 +99,19 @@ guides](https://toolkit.fluxcd.io/dev-guides/source-watcher/).
## Community
The Flux project is always looking for new contributors and there are a multitude of ways to get involved.
Depending on what you want to do, some of the following bits might be your first steps:
Need help or want to contribute? Please see the links below. The Flux project is always looking for new contributors and there are a multitude of ways to get involved.
- Join our upcoming dev meetings ([meeting access and agenda](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view))
- Talk to us in the #flux channel on [CNCF Slack](https://slack.cncf.io/)
- Ask questions and propose features on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- And if you are completely new to Flux and the GitOps Toolkit, take a look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
- To be part of the conversation about Flux's development, [join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
- Check out [how to contribute](CONTRIBUTING.md) to the project
- Getting Started?
- Look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
- Need help?
- First: Ask questions on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- Second: Talk to us in the #flux channel on [CNCF Slack](https://slack.cncf.io/)
- Please follow our [Support Guidelines](https://fluxcd.io/support/) (in short: be nice, be respectful of volunteers' time, understand that maintainers and contributors cannot respond to all DMs, and keep discussions in the public #flux channel as much as possible).
- Have feature proposals or want to contribute?
- Propose features on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
- Join our upcoming dev meetings ([meeting access and agenda](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view))
- [Join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
- Check out [how to contribute](CONTRIBUTING.md) to the project
### Events

View File

@@ -22,7 +22,7 @@ Note that this action can only be used on GitHub **Linux AMD64** runners.
### Automate Flux updates
Example workflow for updating Flux's components generated with `flux bootstrap --arch=amd64 --path=clusters/production`:
Example workflow for updating Flux's components generated with `flux bootstrap --path=clusters/production`:
```yaml
name: update-flux
@@ -43,7 +43,7 @@ jobs:
- name: Check for updates
id: update
run: |
flux install --arch=amd64 \
flux install \
--export > ./clusters/production/flux-system/gotk-components.yaml
VERSION="$(flux -v)"

View File

@@ -51,6 +51,8 @@ func makeSecret(name string) (corev1.Secret, error) {
Namespace: rootArgs.namespace,
Labels: secretLabels,
},
StringData: map[string]string{},
Data: nil,
}, nil
}

View File

@@ -133,10 +133,10 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return err
}
secret.Data = map[string][]byte{
"identity": pair.PrivateKey,
"identity.pub": pair.PublicKey,
"known_hosts": hostKey,
secret.StringData = map[string]string{
"identity": string(pair.PrivateKey),
"identity.pub": string(pair.PublicKey),
"known_hosts": string(hostKey),
}
if !createArgs.export {
@@ -148,9 +148,9 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
}
// TODO: add cert data when it's implemented in source-controller
secret.Data = map[string][]byte{
"username": []byte(secretGitArgs.username),
"password": []byte(secretGitArgs.password),
secret.StringData = map[string]string{
"username": secretGitArgs.username,
"password": secretGitArgs.password,
}
default:
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)

View File

@@ -17,15 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
)
var deleteHelmReleaseCmd = &cobra.Command{
@@ -36,57 +29,12 @@ var deleteHelmReleaseCmd = &cobra.Command{
Example: ` # Delete a Helm release and the Kubernetes resources created by it
flux delete hr podinfo
`,
RunE: deleteHelmReleaseCmdRun,
RunE: deleteCommand{
apiType: helmReleaseType,
object: universalAdapter{&helmv2.HelmRelease{}},
}.run,
}
func init() {
deleteCmd.AddCommand(deleteHelmReleaseCmd)
}
func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("release name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if !deleteArgs.silent {
if !helmRelease.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s Helm release!", name)
}
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this Helm release",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting release %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &helmRelease)
if err != nil {
return err
}
logger.Successf("release deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var deleteKsCmd = &cobra.Command{
@@ -35,57 +29,12 @@ var deleteKsCmd = &cobra.Command{
Example: ` # Delete a kustomization and the Kubernetes resources created by it
flux delete kustomization podinfo
`,
RunE: deleteKsCmdRun,
RunE: deleteCommand{
apiType: kustomizationType,
object: universalAdapter{&kustomizev1.Kustomization{}},
}.run,
}
func init() {
deleteCmd.AddCommand(deleteKsCmd)
}
func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("kustomization name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
if !deleteArgs.silent {
if !kustomization.Spec.Suspend {
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name)
}
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this kustomization",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting kustomization %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &kustomization)
if err != nil {
return err
}
logger.Successf("kustomization deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var deleteSourceBucketCmd = &cobra.Command{
@@ -34,54 +28,12 @@ var deleteSourceBucketCmd = &cobra.Command{
Example: ` # Delete a Bucket source
flux delete source bucket podinfo
`,
RunE: deleteSourceBucketCmdRun,
RunE: deleteCommand{
apiType: bucketType,
object: universalAdapter{&sourcev1.Bucket{}},
}.run,
}
func init() {
deleteSourceCmd.AddCommand(deleteSourceBucketCmd)
}
func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &bucket)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var deleteSourceGitCmd = &cobra.Command{
@@ -34,54 +28,12 @@ var deleteSourceGitCmd = &cobra.Command{
Example: ` # Delete a Git repository
flux delete source git podinfo
`,
RunE: deleteSourceGitCmdRun,
RunE: deleteCommand{
apiType: gitRepositoryType,
object: universalAdapter{&sourcev1.GitRepository{}},
}.run,
}
func init() {
deleteSourceCmd.AddCommand(deleteSourceGitCmd)
}
func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("git name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var git sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &git)
if err != nil {
return err
}
if !deleteArgs.silent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this source",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
err = kubeClient.Delete(ctx, &git)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -34,7 +34,10 @@ var deleteSourceHelmCmd = &cobra.Command{
Example: ` # Delete a Helm repository
flux delete source helm podinfo
`,
RunE: deleteSourceHelmCmdRun,
RunE: deleteCommand{
apiType: helmRepositoryType,
object: universalAdapter{&sourcev1.HelmRepository{}},
}.run,
}
func init() {

View File

@@ -35,7 +35,7 @@ var getSourceHelmChartCmd = &cobra.Command{
flux get sources chart --all-namespaces
`,
RunE: getCommand{
apiType: bucketType,
apiType: helmChartType,
list: &helmChartListAdapter{&sourcev1.HelmChartList{}},
}.run,
}

View File

@@ -35,7 +35,7 @@ var getSourceGitCmd = &cobra.Command{
flux get sources git --all-namespaces
`,
RunE: getCommand{
apiType: bucketType,
apiType: gitRepositoryType,
list: &gitRepositoryListAdapter{&sourcev1.GitRepositoryList{}},
}.run,
}

View File

@@ -35,7 +35,7 @@ var getSourceHelmCmd = &cobra.Command{
flux get sources helm --all-namespaces
`,
RunE: getCommand{
apiType: bucketType,
apiType: helmRepositoryType,
list: &helmRepositoryListAdapter{&sourcev1.HelmRepositoryList{}},
}.run,
}

View File

@@ -93,17 +93,31 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
}
if rhrArgs.syncHrWithSource {
nsCopy := rootArgs.namespace
if helmRelease.Spec.Chart.Spec.SourceRef.Namespace != "" {
rootArgs.namespace = helmRelease.Spec.Chart.Spec.SourceRef.Namespace
}
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
case sourcev1.HelmRepositoryKind:
err = reconcileSourceHelmCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
case sourcev1.BucketKind:
err = reconcileSourceBucketCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
}
if err != nil {
return err
}
rootArgs.namespace = nsCopy
}
lastHandledReconcileAt := helmRelease.Status.LastHandledReconcileAt

View File

@@ -91,15 +91,26 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
}
if rksArgs.syncKsWithSource {
nsCopy := rootArgs.namespace
if kustomization.Spec.SourceRef.Namespace != "" {
rootArgs.namespace = kustomization.Spec.SourceRef.Namespace
}
switch kustomization.Spec.SourceRef.Kind {
case sourcev1.GitRepositoryKind:
err = reconcileSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run(nil, []string{kustomization.Spec.SourceRef.Name})
case sourcev1.BucketKind:
err = reconcileSourceBucketCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
err = reconcileCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run(nil, []string{kustomization.Spec.SourceRef.Name})
}
if err != nil {
return err
}
rootArgs.namespace = nsCopy
}
lastHandledReconcileAt := kustomization.Status.LastHandledReconcileAt

View File

@@ -19,13 +19,7 @@ package main
import (
"context"
"fmt"
"time"
"github.com/fluxcd/pkg/apis/meta"
"k8s.io/client-go/util/retry"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -43,64 +37,16 @@ var reconcileSourceBucketCmd = &cobra.Command{
Example: ` # Trigger a reconciliation for an existing source
flux reconcile source bucket podinfo
`,
RunE: reconcileSourceBucketCmdRun,
RunE: reconcileCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd)
}
func reconcileSourceBucketCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
if bucket.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
lastHandledReconcileAt := bucket.Status.LastHandledReconcileAt
logger.Actionf("annotating Bucket source %s in %s namespace", name, rootArgs.namespace)
if err := requestBucketReconciliation(ctx, kubeClient, namespacedName, &bucket); err != nil {
return err
}
logger.Successf("Bucket source annotated")
logger.Waitingf("waiting for Bucket source reconciliation")
if err := wait.PollImmediate(
rootArgs.pollInterval, rootArgs.timeout,
bucketReconciliationHandled(ctx, kubeClient, namespacedName, &bucket, lastHandledReconcileAt),
); err != nil {
return err
}
logger.Successf("Bucket source reconciliation completed")
if apimeta.IsStatusConditionFalse(bucket.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("Bucket source reconciliation failed")
}
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
return nil
}
func isBucketReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
return func() (bool, error) {
@@ -126,30 +72,10 @@ func isBucketReady(ctx context.Context, kubeClient client.Client,
}
}
func bucketReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, bucket)
if err != nil {
return false, err
}
return bucket.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
func (obj bucketAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest()
}
func requestBucketReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, bucket); err != nil {
return err
}
if bucket.Annotations == nil {
bucket.Annotations = map[string]string{
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
bucket.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, bucket)
})
func (obj bucketAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,21 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
"time"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/spf13/cobra"
)
var reconcileSourceGitCmd = &cobra.Command{
@@ -41,86 +29,20 @@ var reconcileSourceGitCmd = &cobra.Command{
Example: ` # Trigger a git pull for an existing source
flux reconcile source git podinfo
`,
RunE: reconcileSourceGitCmdRun,
RunE: reconcileCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceGitCmd)
}
func reconcileSourceGitCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
if repository.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating GitRepository source %s in %s namespace", name, rootArgs.namespace)
if err := requestGitRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
return err
}
logger.Successf("GitRepository source annotated")
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
logger.Waitingf("waiting for GitRepository source reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
gitRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
return err
}
logger.Successf("GitRepository source reconciliation completed")
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("GitRepository source reconciliation failed")
}
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
func (obj gitRepositoryAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest()
}
func gitRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.GitRepository, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, repository)
if err != nil {
return false, err
}
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestGitRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
return err
}
if repository.Annotations == nil {
repository.Annotations = map[string]string{
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})
func (obj gitRepositoryAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,22 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
"time"
"github.com/fluxcd/pkg/apis/meta"
"k8s.io/client-go/util/retry"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"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"
"github.com/spf13/cobra"
)
var reconcileSourceHelmCmd = &cobra.Command{
@@ -42,86 +29,20 @@ var reconcileSourceHelmCmd = &cobra.Command{
Example: ` # Trigger a reconciliation for an existing source
flux reconcile source helm podinfo
`,
RunE: reconcileSourceHelmCmdRun,
RunE: reconcileCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceHelmCmd)
}
func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRepository source name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
if repository.Spec.Suspend {
return fmt.Errorf("resource is suspended")
}
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, rootArgs.namespace)
if err := requestHelmRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
return err
}
logger.Successf("HelmRepository source annotated")
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
logger.Waitingf("waiting for HelmRepository source reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
helmRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
return err
}
logger.Successf("HelmRepository source reconciliation completed")
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
return fmt.Errorf("HelmRepository source reconciliation failed")
}
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
return nil
func (obj helmRepositoryAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest()
}
func helmRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository, lastHandledReconcileAt string) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, repository)
if err != nil {
return false, err
}
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
}
}
func requestHelmRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
return err
}
if repository.Annotations == nil {
repository.Annotations = map[string]string{
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
repository.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
}
return kubeClient.Update(ctx, repository)
})
func (obj helmRepositoryAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,20 +17,9 @@ 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"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
)
var resumeHrCmd = &cobra.Command{
@@ -42,76 +31,24 @@ finish the apply.`,
Example: ` # Resume reconciliation for an existing Helm release
flux resume hr podinfo
`,
RunE: resumeHrCmdRun,
RunE: resumeCommand{
apiType: helmReleaseType,
object: helmReleaseAdapter{&helmv2.HelmRelease{}},
}.run,
}
func init() {
resumeCmd.AddCommand(resumeHrCmd)
}
func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRelease name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
logger.Actionf("resuming HelmRelease %s in %s namespace", name, rootArgs.namespace)
helmRelease.Spec.Suspend = false
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err
}
logger.Successf("HelmRelease resumed")
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isHelmReleaseResumed(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
return err
}
logger.Successf("HelmRelease reconciliation completed")
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
return nil
func (obj helmReleaseAdapter) getObservedGeneration() int64 {
return obj.HelmRelease.Status.ObservedGeneration
}
func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, helmRelease)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if helmRelease.Generation != helmRelease.Status.ObservedGeneration {
return false, err
}
if c := apimeta.FindStatusCondition(helmRelease.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
}
func (obj helmReleaseAdapter) setUnsuspended() {
obj.HelmRelease.Spec.Suspend = false
}
func (obj helmReleaseAdapter) successMessage() string {
return fmt.Sprintf("applied revision %s", obj.Status.LastAppliedRevision)
}

View File

@@ -17,19 +17,10 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"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"
)
var resumeKsCmd = &cobra.Command{
@@ -41,76 +32,24 @@ finish the apply.`,
Example: ` # Resume reconciliation for an existing Kustomization
flux resume ks podinfo
`,
RunE: resumeKsCmdRun,
RunE: resumeCommand{
apiType: kustomizationType,
object: kustomizationAdapter{&kustomizev1.Kustomization{}},
}.run,
}
func init() {
resumeCmd.AddCommand(resumeKsCmd)
}
func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Kustomization name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
logger.Actionf("resuming Kustomization %s in %s namespace", name, rootArgs.namespace)
kustomization.Spec.Suspend = false
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
}
logger.Successf("Kustomization resumed")
logger.Waitingf("waiting for Kustomization reconciliation")
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isKustomizationResumed(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
return err
}
logger.Successf("Kustomization reconciliation completed")
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
return nil
func (obj kustomizationAdapter) getObservedGeneration() int64 {
return obj.Kustomization.Status.ObservedGeneration
}
func isKustomizationResumed(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, kustomization)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if kustomization.Generation != kustomization.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(kustomization.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
}
func (obj kustomizationAdapter) setUnsuspended() {
obj.Kustomization.Spec.Suspend = false
}
func (obj kustomizationAdapter) successMessage() string {
return fmt.Sprintf("applied revision %s", obj.Status.LastAppliedRevision)
}

View File

@@ -17,20 +17,8 @@ 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"
"github.com/spf13/cobra"
)
var resumeSourceBucketCmd = &cobra.Command{
@@ -40,76 +28,20 @@ var resumeSourceBucketCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing Bucket
flux resume source bucket podinfo
`,
RunE: resumeSourceBucketCmdRun,
RunE: resumeCommand{
apiType: bucketType,
object: &bucketAdapter{&sourcev1.Bucket{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(rootArgs.pollInterval, rootArgs.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 (obj bucketAdapter) getObservedGeneration() int64 {
return obj.Bucket.Status.ObservedGeneration
}
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
}
func (obj bucketAdapter) setUnsuspended() {
obj.Bucket.Spec.Suspend = false
}

View File

@@ -17,20 +17,10 @@ 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"
"github.com/spf13/cobra"
)
var resumeSourceHelmChartCmd = &cobra.Command{
@@ -40,76 +30,24 @@ var resumeSourceHelmChartCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing HelmChart
flux resume source chart podinfo
`,
RunE: resumeSourceHelmChartCmdRun,
RunE: resumeCommand{
apiType: helmChartType,
object: &helmChartAdapter{&sourcev1.HelmChart{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(rootArgs.pollInterval, rootArgs.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 (obj helmChartAdapter) getObservedGeneration() int64 {
return obj.HelmChart.Status.ObservedGeneration
}
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
}
func (obj helmChartAdapter) setUnsuspended() {
obj.HelmChart.Spec.Suspend = false
}
func (obj helmChartAdapter) successMessage() string {
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
}

View File

@@ -17,20 +17,8 @@ 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"
"github.com/spf13/cobra"
)
var resumeSourceGitCmd = &cobra.Command{
@@ -40,76 +28,20 @@ var resumeSourceGitCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing GitRepository
flux resume source git podinfo
`,
RunE: resumeSourceGitCmdRun,
RunE: resumeCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(rootArgs.pollInterval, rootArgs.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 (obj gitRepositoryAdapter) getObservedGeneration() int64 {
return obj.GitRepository.Status.ObservedGeneration
}
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
}
func (obj gitRepositoryAdapter) setUnsuspended() {
obj.GitRepository.Spec.Suspend = false
}

View File

@@ -17,20 +17,8 @@ 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"
"github.com/spf13/cobra"
)
var resumeSourceHelmCmd = &cobra.Command{
@@ -40,76 +28,20 @@ var resumeSourceHelmCmd = &cobra.Command{
Example: ` # Resume reconciliation for an existing HelmRepository
flux resume source helm bitnami
`,
RunE: resumeSourceHelmCmdRun,
RunE: resumeCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run,
}
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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.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, rootArgs.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(rootArgs.pollInterval, rootArgs.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 (obj helmRepositoryAdapter) getObservedGeneration() int64 {
return obj.HelmRepository.Status.ObservedGeneration
}
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
}
func (obj helmRepositoryAdapter) setUnsuspended() {
obj.HelmRepository.Spec.Suspend = false
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/spf13/cobra"
)
var suspendHrCmd = &cobra.Command{
@@ -35,43 +29,20 @@ var suspendHrCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing Helm release
flux suspend hr podinfo
`,
RunE: suspendHrCmdRun,
RunE: suspendCommand{
apiType: helmReleaseType,
object: &helmReleaseAdapter{&helmv2.HelmRelease{}},
}.run,
}
func init() {
suspendCmd.AddCommand(suspendHrCmd)
}
func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRelease name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
logger.Actionf("suspending HelmRelease %s in %s namespace", name, rootArgs.namespace)
helmRelease.Spec.Suspend = true
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err
}
logger.Successf("HelmRelease suspended")
return nil
func (obj helmReleaseAdapter) isSuspended() bool {
return obj.HelmRelease.Spec.Suspend
}
func (obj helmReleaseAdapter) setSuspended() {
obj.HelmRelease.Spec.Suspend = true
}

View File

@@ -17,13 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendKsCmd = &cobra.Command{
@@ -34,43 +29,20 @@ var suspendKsCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing Kustomization
flux suspend ks podinfo
`,
RunE: suspendKsCmdRun,
RunE: suspendCommand{
apiType: kustomizationType,
object: kustomizationAdapter{&kustomizev1.Kustomization{}},
}.run,
}
func init() {
suspendCmd.AddCommand(suspendKsCmd)
}
func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("kustomization name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var kustomization kustomizev1.Kustomization
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
return err
}
logger.Actionf("suspending kustomization %s in %s namespace", name, rootArgs.namespace)
kustomization.Spec.Suspend = true
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
}
logger.Successf("kustomization suspended")
return nil
func (obj kustomizationAdapter) isSuspended() bool {
return obj.Kustomization.Spec.Suspend
}
func (obj kustomizationAdapter) setSuspended() {
obj.Kustomization.Spec.Suspend = true
}

View File

@@ -17,13 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceBucketCmd = &cobra.Command{
@@ -33,43 +28,20 @@ var suspendSourceBucketCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing Bucket
flux suspend source bucket podinfo
`,
RunE: suspendSourceBucketCmdRun,
RunE: suspendCommand{
apiType: bucketType,
object: bucketAdapter{&sourcev1.Bucket{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceBucketCmd)
}
func suspendSourceBucketCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var bucket sourcev1.Bucket
err = kubeClient.Get(ctx, namespacedName, &bucket)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
bucket.Spec.Suspend = true
if err := kubeClient.Update(ctx, &bucket); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj bucketAdapter) isSuspended() bool {
return obj.Bucket.Spec.Suspend
}
func (obj bucketAdapter) setSuspended() {
obj.Bucket.Spec.Suspend = true
}

View File

@@ -17,13 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceHelmChartCmd = &cobra.Command{
@@ -33,43 +29,20 @@ var suspendSourceHelmChartCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing HelmChart
flux suspend source chart podinfo
`,
RunE: suspendSourceHelmChartCmdRun,
RunE: suspendCommand{
apiType: helmChartType,
object: helmChartAdapter{&sourcev1.HelmChart{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceHelmChartCmd)
}
func suspendSourceHelmChartCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var chart sourcev1.HelmChart
err = kubeClient.Get(ctx, namespacedName, &chart)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
chart.Spec.Suspend = true
if err := kubeClient.Update(ctx, &chart); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj helmChartAdapter) isSuspended() bool {
return obj.HelmChart.Spec.Suspend
}
func (obj helmChartAdapter) setSuspended() {
obj.HelmChart.Spec.Suspend = true
}

View File

@@ -17,13 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceGitCmd = &cobra.Command{
@@ -33,43 +29,20 @@ var suspendSourceGitCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing GitRepository
flux suspend source git podinfo
`,
RunE: suspendSourceGitCmdRun,
RunE: suspendCommand{
apiType: gitRepositoryType,
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceGitCmd)
}
func suspendSourceGitCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.GitRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = true
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj gitRepositoryAdapter) isSuspended() bool {
return obj.GitRepository.Spec.Suspend
}
func (obj gitRepositoryAdapter) setSuspended() {
obj.GitRepository.Spec.Suspend = true
}

View File

@@ -17,13 +17,9 @@ limitations under the License.
package main
import (
"context"
"fmt"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var suspendSourceHelmCmd = &cobra.Command{
@@ -33,43 +29,20 @@ var suspendSourceHelmCmd = &cobra.Command{
Example: ` # Suspend reconciliation for an existing HelmRepository
flux suspend source helm bitnami
`,
RunE: suspendSourceHelmCmdRun,
RunE: suspendCommand{
apiType: helmRepositoryType,
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
}.run,
}
func init() {
suspendSourceCmd.AddCommand(suspendSourceHelmCmd)
}
func suspendSourceHelmCmdRun(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(), rootArgs.timeout)
defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
logger.Actionf("suspending source %s in %s namespace", name, rootArgs.namespace)
repository.Spec.Suspend = true
if err := kubeClient.Update(ctx, &repository); err != nil {
return err
}
logger.Successf("source suspended")
return nil
func (obj helmRepositoryAdapter) isSuspended() bool {
return obj.HelmRepository.Spec.Suspend
}
func (obj helmRepositoryAdapter) setSuspended() {
obj.HelmRepository.Spec.Suspend = true
}

View File

@@ -1,98 +1,5 @@
# Frequently asked questions
## General questions
### What does Flux v2 mean for Flux?
Flux v1 is a monolithic do-it-all operator; Flux v2 separates the functionalities into specialized controllers, collectively called the GitOps Toolkit.
You can install and operate Flux v2 simply using the `flux` command. You can easily pick and choose the functionality you need and extend it to serve your own purposes.
The timeline we are looking at right now is:
1. Put Flux v1 into maintenance mode (no new features being added; bugfixes and CVEs patched only).
1. Continue work on the [Flux v2 roadmap](https://toolkit.fluxcd.io/roadmap/).
1. We will provide transition guides for specific user groups, e.g. users of Flux v1 in read-only mode, or of Helm Operator v1, etc. once the functionality is integrated into Flux v2 and it's deemed "ready".
1. Once the use-cases of Flux v1 are covered, we will continue supporting Flux v1 for 6 months. This will be the transition period before it's considered unsupported.
### Why did you rewrite Flux?
Flux v2 implements its functionality in individual controllers, which allowed us to address long-standing feature requests much more easily.
By basing these controllers on modern Kubernetes tooling (`controller-runtime` libraries), they can be dynamically configured with Kubernetes custom resources either by cluster admins or by other automated tools -- and you get greatly increased observability.
This gave us the opportunity to build Flux v2 with the top Flux v1 feature requests in mind:
- Supporting multiple source Git repositories
- Operational insight through health checks, events and alerts
- Multi-tenancy capabilities, like applying each source repository with its own set of permissions
On top of that, testing the individual components and understanding the codebase becomes a lot easier.
### What are significant new differences between Flux v1 and Flux v2?
#### Reconciliation
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Limited to a single Git repository | Multiple Git repositories
Declarative config via arguments in the Flux deployment | `GitRepository` custom resource, which produces an artifact which can be reconciled by other controllers
Follow `HEAD` of Git branches | Supports Git branches, pinning on commits and tags, follow SemVer tag ranges
Suspending of reconciliation by downscaling Flux deployment | Reconciliation can be paused per resource by suspending the `GitRepository`
Credentials config via Arguments and/or Secret volume mounts in the Flux pod | Credentials config per `GitRepository` resource: SSH private key, HTTP/S username/password/token, OpenPGP public keys
#### `kustomize` support
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config through `.flux.yaml` files in the Git repository | Declarative config through a `Kustomization` custom resource, consuming the artifact from the GitRepository
Manifests are generated via shell exec and then reconciled by `fluxd` | Generation, server-side validation, and reconciliation is handled by a specialised `kustomize-controller`
Reconciliation using the service account of the Flux deployment | Support for service account impersonation
Garbage collection needs cluster role binding for Flux to query the Kubernetes discovery API | Garbage collection needs no cluster role binding or access to Kubernetes discovery API
Support for custom commands and generators executed by fluxd in a POSIX shell | No support for custom commands
#### Helm integration
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config in a single Helm custom resource | Declarative config through `HelmRepository`, `GitRepository`, `Bucket`, `HelmChart` and `HelmRelease` custom resources
Chart synchronisation embedded in the operator | Extensive release configuration options, and a reconciliation interval per source
Support for fixed SemVer versions from Helm repositories | Support for SemVer ranges for `HelmChart` resources
Git repository synchronisation on a global interval | Planned support for charts from GitRepository sources
Limited observability via the status object of the HelmRelease resource | Better observability via the HelmRelease status object, Kubernetes events, and notifications
Resource heavy, relatively slow | Better performance
Chart changes from Git sources are determined from Git metadata | Chart changes must be accompanied by a version bump in `Chart.yaml` to produce a new artifact
#### Notifications, webhooks, observability
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Emits "custom Flux events" to a webhook endpoint | Emits Kubernetes events for included custom resources
RPC endpoint can be configured to a 3rd party solution like FluxCloud to be forwarded as notifications to e.g. Slack | Flux v2 components can be configured to POST the events to a `notification-controller` endpoint. Selective forwarding of POSTed events as notifications using `Provider` and `Alert` custom resources.
Webhook receiver is a side-project | Webhook receiver, handling a wide range of platforms, is included
Unstructured logging | Structured logging for all components
Custom Prometheus metrics | Generic / common `controller-runtime` Prometheus metrics
### How can I get involved?
There are a variety of ways and we look forward to having you on board building the future of GitOps together:
- [Discuss the direction](https://github.com/fluxcd/flux2/discussions) of Flux v2 with us
- Join us in #flux-dev on the [CNCF Slack](https://slack.cncf.io)
- Check out our [contributor docs](https://toolkit.fluxcd.io/contributing/)
- Take a look at the [roadmap for Flux v2](https://toolkit.fluxcd.io/roadmap/)
### Are there any breaking changes?
- In Flux v1 Kustomize support was implemented through `.flux.yaml` files in the Git repository. As indicated in the comparison table above, while this approach worked, we found it to be error-prone and hard to debug. The new [Kustomization CR](https://github.com/fluxcd/kustomize-controller/blob/master/docs/spec/v1alpha1/kustomization.md) should make troubleshooting much easier. Unfortunately we needed to drop the support for custom commands as running arbitrary shell scripts in-cluster poses serious security concerns.
- Helm users: we redesigned the `HelmRelease` API and the automation will work quite differently, so upgrading to `HelmRelease` v2 will require a little work from you, but you will gain more flexibility, better observability and performance.
### Is the GitOps Toolkit related to the GitOps Engine?
In an announcement in August 2019, the expectation was set that the Flux project would integrate the GitOps Engine, then being factored out of ArgoCD. Since the result would be backward-incompatible, it would require a major version bump: Flux v2.
After experimentation and considerable thought, we (the maintainers) have found a path to Flux v2 that we think better serves our vision of GitOps: the GitOps Toolkit. In consequence, we do not now plan to integrate GitOps Engine into Flux.
## Kustomize questions
### Are there two Kustomization types?
@@ -242,3 +149,127 @@ The kustomize-controller creates `kustomization.yaml` files similar to:
```sh
cd ./deploy/prod && kustomize create --autodetect --recursive
```
## Helm questions
### How to debug "not ready" errors?
Misconfiguring the `HelmRelease.spec.chart`, like a typo in the chart name, version or chart source URL
would result in a "HelmChart is not ready" error displayed by:
```console
$ flux get helmreleases --all-namespaces
NAMESPACE NAME READY MESSAGE
default podinfo False HelmChart 'default/default-podinfo' is not ready
```
In order to get to the root cause, first make sure the source e.g. the `HelmRepository`
is configured properly and has access to the remote `index.yaml`:
```console
$ flux get sources helm --all-namespaces
NAMESPACE NAME READY MESSAGE
default podinfo False failed to fetch https://stefanprodan.github.io/podinfo2/index.yaml : 404 Not Found
```
If the source is `Ready`, then the error must be caused by the chart,
for example due to an invalid chart name or non-existing version:
```console
$ flux get sources chart --all-namespaces
NAMESPACE NAME READY MESSAGE
default default-podinfo False no chart version found for podinfo-9.0.0
```
## Flux v1 vs v2 questions
### What does Flux v2 mean for Flux?
Flux v1 is a monolithic do-it-all operator; Flux v2 separates the functionalities into specialized controllers, collectively called the GitOps Toolkit.
You can install and operate Flux v2 simply using the `flux` command. You can easily pick and choose the functionality you need and extend it to serve your own purposes.
The timeline we are looking at right now is:
1. Put Flux v1 into maintenance mode (no new features being added; bugfixes and CVEs patched only).
1. Continue work on the [Flux v2 roadmap](https://toolkit.fluxcd.io/roadmap/).
1. We will provide transition guides for specific user groups, e.g. users of Flux v1 in read-only mode, or of Helm Operator v1, etc. once the functionality is integrated into Flux v2 and it's deemed "ready".
1. Once the use-cases of Flux v1 are covered, we will continue supporting Flux v1 for 6 months. This will be the transition period before it's considered unsupported.
### Why did you rewrite Flux?
Flux v2 implements its functionality in individual controllers, which allowed us to address long-standing feature requests much more easily.
By basing these controllers on modern Kubernetes tooling (`controller-runtime` libraries), they can be dynamically configured with Kubernetes custom resources either by cluster admins or by other automated tools -- and you get greatly increased observability.
This gave us the opportunity to build Flux v2 with the top Flux v1 feature requests in mind:
- Supporting multiple source Git repositories
- Operational insight through health checks, events and alerts
- Multi-tenancy capabilities, like applying each source repository with its own set of permissions
On top of that, testing the individual components and understanding the codebase becomes a lot easier.
### What are significant new differences between Flux v1 and Flux v2?
#### Reconciliation
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Limited to a single Git repository | Multiple Git repositories
Declarative config via arguments in the Flux deployment | `GitRepository` custom resource, which produces an artifact which can be reconciled by other controllers
Follow `HEAD` of Git branches | Supports Git branches, pinning on commits and tags, follow SemVer tag ranges
Suspending of reconciliation by downscaling Flux deployment | Reconciliation can be paused per resource by suspending the `GitRepository`
Credentials config via Arguments and/or Secret volume mounts in the Flux pod | Credentials config per `GitRepository` resource: SSH private key, HTTP/S username/password/token, OpenPGP public keys
#### `kustomize` support
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config through `.flux.yaml` files in the Git repository | Declarative config through a `Kustomization` custom resource, consuming the artifact from the GitRepository
Manifests are generated via shell exec and then reconciled by `fluxd` | Generation, server-side validation, and reconciliation is handled by a specialised `kustomize-controller`
Reconciliation using the service account of the Flux deployment | Support for service account impersonation
Garbage collection needs cluster role binding for Flux to query the Kubernetes discovery API | Garbage collection needs no cluster role binding or access to Kubernetes discovery API
Support for custom commands and generators executed by fluxd in a POSIX shell | No support for custom commands
#### Helm integration
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Declarative config in a single Helm custom resource | Declarative config through `HelmRepository`, `GitRepository`, `Bucket`, `HelmChart` and `HelmRelease` custom resources
Chart synchronisation embedded in the operator | Extensive release configuration options, and a reconciliation interval per source
Support for fixed SemVer versions from Helm repositories | Support for SemVer ranges for `HelmChart` resources
Git repository synchronisation on a global interval | Planned support for charts from GitRepository sources
Limited observability via the status object of the HelmRelease resource | Better observability via the HelmRelease status object, Kubernetes events, and notifications
Resource heavy, relatively slow | Better performance
Chart changes from Git sources are determined from Git metadata | Chart changes must be accompanied by a version bump in `Chart.yaml` to produce a new artifact
#### Notifications, webhooks, observability
Flux v1 | Flux v2
---------------------------------- | ----------------------------------
Emits "custom Flux events" to a webhook endpoint | Emits Kubernetes events for included custom resources
RPC endpoint can be configured to a 3rd party solution like FluxCloud to be forwarded as notifications to e.g. Slack | Flux v2 components can be configured to POST the events to a `notification-controller` endpoint. Selective forwarding of POSTed events as notifications using `Provider` and `Alert` custom resources.
Webhook receiver is a side-project | Webhook receiver, handling a wide range of platforms, is included
Unstructured logging | Structured logging for all components
Custom Prometheus metrics | Generic / common `controller-runtime` Prometheus metrics
### How can I get involved?
There are a variety of ways and we look forward to having you on board building the future of GitOps together:
- [Discuss the direction](https://github.com/fluxcd/flux2/discussions) of Flux v2 with us
- Join us in #flux-dev on the [CNCF Slack](https://slack.cncf.io)
- Check out our [contributor docs](https://toolkit.fluxcd.io/contributing/)
- Take a look at the [roadmap for Flux v2](https://toolkit.fluxcd.io/roadmap/)
### Are there any breaking changes?
- In Flux v1 Kustomize support was implemented through `.flux.yaml` files in the Git repository. As indicated in the comparison table above, while this approach worked, we found it to be error-prone and hard to debug. The new [Kustomization CR](https://github.com/fluxcd/kustomize-controller/blob/master/docs/spec/v1alpha1/kustomization.md) should make troubleshooting much easier. Unfortunately we needed to drop the support for custom commands as running arbitrary shell scripts in-cluster poses serious security concerns.
- Helm users: we redesigned the `HelmRelease` API and the automation will work quite differently, so upgrading to `HelmRelease` v2 will require a little work from you, but you will gain more flexibility, better observability and performance.
### Is the GitOps Toolkit related to the GitOps Engine?
In an announcement in August 2019, the expectation was set that the Flux project would integrate the GitOps Engine, then being factored out of ArgoCD. Since the result would be backward-incompatible, it would require a major version bump: Flux v2.
After experimentation and considerable thought, we (the maintainers) have found a path to Flux v2 that we think better serves our vision of GitOps: the GitOps Toolkit. In consequence, we do not now plan to integrate GitOps Engine into Flux.

View File

@@ -5,7 +5,7 @@ This guide walks you through configuring container image scanning and deployment
For a container image you can configure Flux to:
- scan the container registry and fetch the image tags
- select the latest tag based on a semver range
- select the latest tag based on the defined policy (semver, calver, regex)
- replace the tag in Kubernetes manifests (YAML format)
- checkout a branch, commit and push the changes to the remote Git repository
- apply the changes in-cluster and rollout the container image
@@ -17,10 +17,7 @@ For a container image you can configure Flux to:
For production environments, this feature allows you to automatically deploy application patches
(CVEs and bug fixes), and keep a record of all deployments in Git history.
For staging environments, this features allow you to deploy the latest prerelease of an application,
without having to manually edit its deployment manifests in Git.
Production CI/CD workflow:
**Production CI/CD workflow**
* DEV: push a bug fix to the app repository
* DEV: bump the patch version and release e.g. `v1.0.1`
@@ -29,6 +26,17 @@ Production CI/CD workflow:
* CD: update the image tag in the app manifest to `v1.0.1` (Flux cluster to Git reconciliation)
* CD: deploy `v1.0.1` to production clusters (Flux Git to cluster reconciliation)
For staging environments, this features allow you to deploy the latest build of a branch,
without having to manually edit the app deployment manifest in Git.
**Staging CI/CD workflow**
* DEV: push code changes to the app repository `main` branch
* CI: build and push a container image tagged as `${GIT_BRANCH}-${GIT_SHA:0:7}-$(date +%s)`
* CD: pull the latest image metadata from the app registry (Flux image scanning)
* CD: update the image tag in the app manifest to `main-2d3fcbd-1611906956` (Flux cluster to Git reconciliation)
* CD: deploy `main-2d3fcbd-1611906956` to staging clusters (Flux Git to cluster reconciliation)
## Prerequisites
You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18.
@@ -48,6 +56,11 @@ export GITHUB_USER=<your-username>
## Install Flux
!!! hint "Enable image automation components"
If you bootstrapped Flux before without the `--components-extra=` argument, you need to add
`--components-extra=image-reflector-controller,image-automation-controller` to your
bootstrapping routine as image automation components are not installed by default.
Install Flux with the image automation components:
```sh
@@ -260,7 +273,7 @@ spec:
messageTemplate: '[ci skip] update image'
interval: 1m0s
update:
setters: {}
strategy: Setters
```
Commit and push changes to main branch:
@@ -362,6 +375,60 @@ images:
newTag: 5.0.0 # {"$imagepolicy": "flux-system:podinfo:tag"}
```
## Trigger image updates with webhooks
You may want to trigger a deployment
as soon as a new image tag is pushed to your container registry.
In order to notify the image-reflector-controller about new images,
you can [setup webhook receivers](webhook-receivers.md).
First generate a random string and create a secret with a `token` field:
```sh
TOKEN=$(head -c 12 /dev/urandom | shasum | cut -d ' ' -f1)
echo $TOKEN
kubectl -n flux-system create secret generic webhook-token \
--from-literal=token=$TOKEN
```
Define a receiver for DockerHub:
```yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Receiver
metadata:
name: podinfo
namespace: flux-system
spec:
type: dockerhub
secretRef:
name: webhook-token
resources:
- kind: ImageRepository
name: podinfo
```
The notification-controller generates a unique URL using the provided token and the receiver name/namespace.
Find the URL with:
```console
$ kubectl -n flux-system get receiver/podinfo
NAME READY STATUS
podinfo True Receiver initialised with URL: /hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b
```
Log in to DockerHub web interface, go to your image registry Settings and select Webhooks.
Fill the form "Webhook URL" by composing the address using the receiver
LB and the generated URL `http://<LoadBalancerAddress>/<ReceiverURL>`.
!!! hint "Note"
Besides DockerHub, you can define receivers for **Harbor**, **Quay**, **Nexus**, **GCR**,
and any other system that supports webhooks e.g. GitHub Actions, Jenkins, CircleCI, etc.
See the [Receiver CRD docs](../components/notification/receiver.md) for more details.
## ImageRepository cloud providers authentication
If relying on a cloud provider image repository, you might need to do some extra
@@ -417,6 +484,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: ecr-credentials-sync
namespace: flux-system
# Uncomment and edit if using IRSA
# annotations:
# eks.amazonaws.com/role-arn: <role arn>
@@ -466,8 +534,8 @@ spec:
imagePullPolicy: IfNotPresent
env:
- name: SECRET_NAME
value: <secret name> # this is the generated Secret name
- name:
value: ecr-credentials
- name: ECR_REGISTRY
value: <account id>.dkr.ecr.<region>.amazonaws.com # fill in the account id and region
volumeMounts:
- mountPath: /token
@@ -496,15 +564,26 @@ you can manually create an init job using the following command:
$ kubectl create job --from=cronjob/ecr-credentials-sync -n flux-system ecr-credentials-sync-init
```
After the job runs, a secret named `ecr-credentials` should be created. Use this
name in your ECR ImageRepository resource manifest as the value for
`.spec.secretRef.name`.
```yaml
spec:
secretRef:
name: ecr-credentials
```
### GCP Container Registry
#### Using access token [short-lived]
!!!note "Workload Identity"
Please ensure that you enable workload identity for your cluster, create a GCP service account that has access to the container registry and create an IAM policy binding between the GCP service account and the Kubernetes service account so that the pods created by the cronjob can access GCP APIs and get the token.
Please ensure that you enable workload identity for your cluster, create a GCP service account that has
access to the container registry and create an IAM policy binding between the GCP service account and
the Kubernetes service account so that the pods created by the cronjob can access GCP APIs and get the token.
Take a look at [this guide](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
The access token for GCR expires hourly.
Considering this limitation, one needs to ensure the credentials are being
refreshed before expiration so that the controller can rely on them for
@@ -573,7 +652,7 @@ spec:
imagePullPolicy: IfNotPresent
env:
- name: SECRET_NAME
value: <SECRET_NAME> # this is the generated Secret name
value: gcr-credentials
- name: GCR_REGISTRY
value: <REGISTRY_NAME> # fill in the registry name e.g gcr.io, eu.gcr.io
command:
@@ -594,18 +673,37 @@ you can manually create an init job using the following command:
$ kubectl create job --from=cronjob/gcr-credentials-sync -n flux-system gcr-credentials-sync-init
```
After the job runs, a secret named `gcr-credentials` should be created. Use this
name in your GCR ImageRepository resource manifest as the value for
`.spec.secretRef.name`.
```yaml
spec:
secretRef:
name: gcr-credentials
```
#### Using a JSON key [long-lived]
!!! warning "Less secure option"
From [Google documentation on authenticating container registry](https://cloud.google.com/container-registry/docs/advanced-authentication#json-key)
> A user-managed key-pair that you can use as a credential for a service account. Because the credential is long-lived, it is the least secure option of all the available authentication methods. When possible, use an access token or another available authentication method to reduce the risk of unauthorized access to your artifacts. If you must use a service account key, ensure that you follow best practices for managing credentials.
> A user-managed key-pair that you can use as a credential for a service account.
> Because the credential is long-lived, it is the least secure option of all the available authentication methods.
> When possible, use an access token or another available authentication method to reduce the risk of
> unauthorized access to your artifacts. If you must use a service account key,
> ensure that you follow best practices for managing credentials.
A Json key doesn't expire, so we don't need a cronjob,
we just need to create the secret and reference it in the ImagePolicy.
Json keys doesn't expire so we don't need a cronjob, we just need to create the secret and reference it in the ImagePolicy.
First, create a json key file by following this
[documentation](https://cloud.google.com/container-registry/docs/advanced-authentication).
Grant the service account the role of `Container Registry Service Agent`
so that it can access GCR and download the json file.
First, create a json key file by following this [documentation](https://cloud.google.com/container-registry/docs/advanced-authentication). Grant the service account the role of `Container Registry Service Agent` so that it can access GCR and download the json file.
Then create a secret, encrypt it using [Mozilla SOPS](mozilla-sops.md)
or [Sealed Secrets](sealed-secrets.md) , commit and push the encypted file to git.
Then create a secret, encrypt it using [Mozilla SOPS](mozilla-sops.md) or [Sealed Secrets](sealed-secrets.md) , commit and push the encypted file to git.
```
kubectl create secret docker-registry <secret-name> \
--docker-server=<GCR-REGISTRY> \ # e.g gcr.io
@@ -615,4 +713,4 @@ Then create a secret, encrypt it using [Mozilla SOPS](mozilla-sops.md) or [Seale
### Azure Container Registry
TODO
TODO

View File

@@ -512,6 +512,10 @@ flux create helmrelease nginx \
## Upgrade
!!! note "Patch versions"
It is safe and advised to use the latest PATCH version when upgrading to a
new MINOR version.
Update Flux CLI to the latest release with `brew upgrade fluxcd/tap/flux` or by
downloading the binary from [GitHub](https://github.com/fluxcd/flux2/releases).

View File

@@ -53,6 +53,8 @@ the API.
After installing the `flux` CLI and running a couple of very simple commands,
you will have a GitOps workflow setup which involves a staging and a production cluster.
If you should need help, please refer to our **[Support page](https://fluxcd.io/support/)**.
## More detail on what's in Flux
Features:

6
go.mod
View File

@@ -7,15 +7,15 @@ require (
github.com/cyphar/filepath-securejoin v0.2.2
github.com/fluxcd/helm-controller/api v0.6.1
github.com/fluxcd/image-automation-controller/api v0.4.0
github.com/fluxcd/image-reflector-controller/api v0.4.1
github.com/fluxcd/kustomize-controller/api v0.7.2
github.com/fluxcd/image-reflector-controller/api v0.5.0
github.com/fluxcd/kustomize-controller/api v0.7.4
github.com/fluxcd/notification-controller/api v0.7.1
github.com/fluxcd/pkg/apis/meta v0.7.0
github.com/fluxcd/pkg/git v0.2.3
github.com/fluxcd/pkg/runtime v0.8.0
github.com/fluxcd/pkg/ssh v0.0.5
github.com/fluxcd/pkg/untar v0.0.5
github.com/fluxcd/source-controller/api v0.7.1
github.com/fluxcd/source-controller/api v0.7.3
github.com/google/go-containerregistry v0.2.0
github.com/manifoldco/promptui v0.7.0
github.com/olekukonko/tablewriter v0.0.4

12
go.sum
View File

@@ -195,10 +195,10 @@ github.com/fluxcd/helm-controller/api v0.6.1 h1:vraSNIXdSiqrjpKs53hnr2NMpL0YKGQc
github.com/fluxcd/helm-controller/api v0.6.1/go.mod h1:vd4Nt6ZZlDkXwJLkmHRgvNc1bvBPMEIZ0o1qFyEWglo=
github.com/fluxcd/image-automation-controller/api v0.4.0 h1:WMPVYfPQTLMvoINdoBDp5u26PJLO1EUZLyeQ95yHKgA=
github.com/fluxcd/image-automation-controller/api v0.4.0/go.mod h1:lHGxbFJNIwgK32YWx9uNf4WR/Z92Hdrl8cn6TzixfUI=
github.com/fluxcd/image-reflector-controller/api v0.4.1 h1:D1gJL6m7NYE8833eBoLT0qAJZ5Q2Yic3UtAEI10fiWg=
github.com/fluxcd/image-reflector-controller/api v0.4.1/go.mod h1:MS3mGjZLnzZsfSqVLGbp0WNJr/k8XRFpw4G6ApLFTbc=
github.com/fluxcd/kustomize-controller/api v0.7.2 h1:+Qv63+nQPcDLfUJfVj7DjkZZjNMflSOOTBvAhULvGm8=
github.com/fluxcd/kustomize-controller/api v0.7.2/go.mod h1:GMdry0llCMT50hDcQ70ujmtd3vOXUWCJMTggPpGNM+I=
github.com/fluxcd/image-reflector-controller/api v0.5.0 h1:xzE+Vi5NevR2TkD9OrEYmjBLTYxeQ28VY5mo0x1Q93Q=
github.com/fluxcd/image-reflector-controller/api v0.5.0/go.mod h1:MS3mGjZLnzZsfSqVLGbp0WNJr/k8XRFpw4G6ApLFTbc=
github.com/fluxcd/kustomize-controller/api v0.7.4 h1:SbcwYh0041yVmODnHtUFNpqtD8HYPoDm1AhL40WkgB8=
github.com/fluxcd/kustomize-controller/api v0.7.4/go.mod h1:GMdry0llCMT50hDcQ70ujmtd3vOXUWCJMTggPpGNM+I=
github.com/fluxcd/notification-controller/api v0.7.1 h1:BDeJ172oJN0LKC6VJlu42NkeBCvTKn9cDPVaUo8M1Xs=
github.com/fluxcd/notification-controller/api v0.7.1/go.mod h1:n1ow7Mxdcedrio5pf/HhBbaVp/4yGTFACPgfCtiyWoU=
github.com/fluxcd/pkg/apis/meta v0.5.0 h1:FaU++mQY0g4sVVl+hG+vk0CXBLbb4EVfRuzs3IjLXvo=
@@ -215,8 +215,8 @@ github.com/fluxcd/pkg/ssh v0.0.5 h1:rnbFZ7voy2JBlUfMbfyqArX2FYaLNpDhccGFC3qW83A=
github.com/fluxcd/pkg/ssh v0.0.5/go.mod h1:7jXPdXZpc0ttMNz2kD9QuMi3RNn/e0DOFbj0Tij/+Hs=
github.com/fluxcd/pkg/untar v0.0.5 h1:UGI3Ch1UIEIaqQvMicmImL1s9npQa64DJ/ozqHKB7gk=
github.com/fluxcd/pkg/untar v0.0.5/go.mod h1:O6V9+rtl8c1mHBafgqFlJN6zkF1HS5SSYn7RpQJ/nfw=
github.com/fluxcd/source-controller/api v0.7.1 h1:GsiPhpApnt83H1TOA5aw/55N/oiMItaf+j9dVpvJedA=
github.com/fluxcd/source-controller/api v0.7.1/go.mod h1:u2sdc/QDm0tzXHL7mZVj928hc3MMU+4mKCuAQg+94Bk=
github.com/fluxcd/source-controller/api v0.7.3 h1:bxJaNttoyY3dnnv6tCXrQk/w6fJuSK2OlIzf/CkhP0A=
github.com/fluxcd/source-controller/api v0.7.3/go.mod h1:u2sdc/QDm0tzXHL7mZVj928hc3MMU+4mKCuAQg+94Bk=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=

View File

@@ -1,8 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://github.com/fluxcd/image-reflector-controller/archive/v0.4.1.zip//image-reflector-controller-0.4.1/config/crd
- https://github.com/fluxcd/image-reflector-controller/archive/v0.4.1.zip//image-reflector-controller-0.4.1/config/manager
- https://github.com/fluxcd/image-reflector-controller/archive/v0.5.0.zip//image-reflector-controller-0.5.0/config/crd
- https://github.com/fluxcd/image-reflector-controller/archive/v0.5.0.zip//image-reflector-controller-0.5.0/config/manager
- account.yaml
patchesJson6902:
- target:

View File

@@ -1,8 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://github.com/fluxcd/kustomize-controller/archive/v0.7.2.zip//kustomize-controller-0.7.2/config/crd
- https://github.com/fluxcd/kustomize-controller/archive/v0.7.2.zip//kustomize-controller-0.7.2/config/manager
- https://github.com/fluxcd/kustomize-controller/archive/v0.7.4.zip//kustomize-controller-0.7.4/config/crd
- https://github.com/fluxcd/kustomize-controller/archive/v0.7.4.zip//kustomize-controller-0.7.4/config/manager
- account.yaml
patchesJson6902:
- target:

View File

@@ -1,8 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- https://github.com/fluxcd/source-controller/archive/v0.7.1.zip//source-controller-0.7.1/config/crd
- https://github.com/fluxcd/source-controller/archive/v0.7.1.zip//source-controller-0.7.1/config/manager
- https://github.com/fluxcd/source-controller/archive/v0.7.3.zip//source-controller-0.7.3/config/crd
- https://github.com/fluxcd/source-controller/archive/v0.7.3.zip//source-controller-0.7.3/config/manager
- account.yaml
patchesJson6902:
- target: