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

Compare commits

..

61 Commits

Author SHA1 Message Date
Hidde Beydals
aa2b5ae18d Merge pull request #2569 from fluxcd/update-components 2022-03-23 21:47:35 +01:00
Hidde Beydals
e2ccbe2088 tests/azure: update toolkit components
- helm-controller to v0.18.1
  https://github.com/fluxcd/helm-controller/blob/v0.18.1/CHANGELOG.md
- source-controller to v0.22.2
  https://github.com/fluxcd/source-controller/blob/v0.22.2/CHANGELOG.md
- notification-controller to v0.23.1
  https://github.com/fluxcd/notification-controller/blob/v0.23.1/CHANGELOG.md
- image-reflector-controller to v0.17.1
  https://github.com/fluxcd/image-reflector-controller/blob/v0.17.1/CHANGELOG.md
- image-automation-controller to v0.21.1
  https://github.com/fluxcd/image-automation-controller/blob/v0.21.1/CHANGELOG.md

Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-03-23 21:33:34 +01:00
Hidde Beydals
775891fc88 build: ensure component update runs with make tidy
This to include the `-compat` flag.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-03-23 21:32:00 +01:00
fluxcdbot
c85954ddef Update toolkit components
- helm-controller to v0.18.1
  https://github.com/fluxcd/helm-controller/blob/v0.18.1/CHANGELOG.md
- source-controller to v0.22.2
  https://github.com/fluxcd/source-controller/blob/v0.22.2/CHANGELOG.md
- notification-controller to v0.23.1
  https://github.com/fluxcd/notification-controller/blob/v0.23.1/CHANGELOG.md
- image-reflector-controller to v0.17.1
  https://github.com/fluxcd/image-reflector-controller/blob/v0.17.1/CHANGELOG.md
- image-automation-controller to v0.21.1
  https://github.com/fluxcd/image-automation-controller/blob/v0.21.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-03-23 21:30:38 +01:00
Hidde Beydals
dd6db2cbd9 Merge pull request #2566 from fluxcd/fix-resume-bucket 2022-03-23 14:50:41 +01:00
Stefan Prodan
5f74c7d294 Fix resume source bucket panic
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-23 15:33:57 +02:00
Hidde Beydals
ed87a632b0 Merge pull request #2565 from fluxcd/source-create-wait 2022-03-23 12:55:08 +01:00
Hidde Beydals
3edcd16b62 fix: wait for Source objects observed generation
This ensures the command will wait for the object to report a Ready
Condition with an ObservedGeneration matching the Generation of the
resource. Ensuring that when a "create" is actually a mutation, it waits
instead of prematurely assuming the Source to be Ready.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-03-23 12:38:42 +01:00
Hidde Beydals
b01d3aeecd Merge pull request #2561 from fluxcd/update-deps 2022-03-23 11:55:57 +01:00
Hidde Beydals
0717c8bdbb Update fluxcd/source-controller to v0.22.1
Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-03-23 11:33:35 +01:00
Hidde Beydals
f1e4561bdd tests/azure: update dependencies
- github.com/Azure/azure-event-hubs-go/v3 to v3.3.17
- github.com/fluxcd/helm-controller/api to v0.18.0
- github.com/fluxcd/image-automation-controller/api to v0.21.0
- github.com/fluxcd/image-reflector-controller/api to v0.17.0
- github.com/fluxcd/kustomize-controller/api to v0.22.0
- github.com/fluxcd/notification-controller/api to v0.23.0
- github.com/fluxcd/pkg/runtime to v0.13.2
- github.com/hashicorp/terraform-exec to v0.15.0
- github.com/libgit2/git2go/v31 to v31.7.9
- github.com/stretchr/testify to v1.7.1
- go.uber.org/multierr to v1.8.0
- k8s.io/api to v0.23.4
- k8s.io/client-go to v0.23.4

For `github.com/hashicorp/terraform-exec`, a newer version (v0.16.0)
is availabe. This version however contains a breaking change (as it
removes the `tfinstall` module), which I did not want to deal with at
the moment.

Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-03-23 11:33:35 +01:00
Hidde Beydals
efe9a30523 Update dependencies
- github.com/Masterminds/semver/v3 to v3.1.1
- github.com/ProtonMail/go-crypto to v0.0.0-20220113124808-70ae35bab23f
- github.com/cyphar/filepath-securejoin to v0.2.3
- github.com/fluxcd/pkg/kustomize to v0.0.3
- github.com/fluxcd/pkg/runtime to v0.13.2
- github.com/fluxcd/pkg/ssa to v0.15.1
- github.com/fluxcd/pkg/ssh to v0.3.2
- github.com/fluxcd/pkg/untar to v0.1.0
- github.com/fluxcd/pkg/version to v0.1.0
- github.com/gonvenience/bunt to v1.3.3
- github.com/gonvenience/ytbx to v1.4.4
- github.com/google/go-containerregistry to v0.8.0
- github.com/homeport/dyff to v1.5.1
- github.com/olekukonko/tablewriter to v0.0.5
- github.com/spf13/cobra to v1.4.0
- golang.org/x/crypto to v0.0.0-20220321153916-2c7772ba3064
- k8s.io/kubectl to v0.23.4
- k8s.io/cli-runtime to v0.23.4
- sigs.k8s.io/cli-utils to v0.29.3

Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-03-23 11:33:35 +01:00
Paulo Gomes
e5ede275f8 Update Source API to v1beta2
The creation of oldConditions, statusableConditions and
reconcilableConditions is an adhoc solution to deal with the upstream
changes on `pkg/apis/meta`, which are yet to be replicated across other
Flux API components.

Signed-off-by: Paulo Gomes <paulo.gomes@weave.works>
2022-03-23 11:33:35 +01:00
fluxcdbot
a929d24924 Update toolkit components
- helm-controller to v0.18.0
  https://github.com/fluxcd/helm-controller/blob/v0.18.0/CHANGELOG.md
- kustomize-controller to v0.22.0
  https://github.com/fluxcd/kustomize-controller/blob/v0.22.0/CHANGELOG.md
- source-controller to v0.22.0
  https://github.com/fluxcd/source-controller/blob/v0.22.0/CHANGELOG.md
- notification-controller to v0.23.0
  https://github.com/fluxcd/notification-controller/blob/v0.23.0/CHANGELOG.md
- image-reflector-controller to v0.17.0
  https://github.com/fluxcd/image-reflector-controller/blob/v0.17.0/CHANGELOG.md
- image-automation-controller to v0.21.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.21.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-03-23 11:33:35 +01:00
Stefan Prodan
368f2d3542 Merge pull request #2564 from fluxcd/dot-domain-nc
Use absolute domain name for the events address
2022-03-23 12:17:35 +02:00
Stefan Prodan
139bbbb87c Use absolute domain name for the events address
Add ending dot to the events address to be consistent with source controller address.
This will affect bootstrap and install by setting `--events-addr=http://notification-controller.flux-system.svc.cluster.local./`.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-23 11:57:46 +02:00
Stefan Prodan
51f5d85861 Merge pull request #2559 from fluxcd/fix-non-fast-forward
Retry bootstrap operations on Git conflict errors
2022-03-22 17:12:31 +02:00
Stefan Prodan
7756faec1f Retry bootstrap operations on Git conflict errors
When running bootstrap in-parallel for many clusters that target the same repository, the 2nd commit with the sync files fails with ` non-fast-forward update`. We now detect the conflict, and we retry the operations by creating a fresh clone from upstream.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-22 16:09:31 +02:00
Sunny
d9e3e3aa95 Merge pull request #2542 from fluxcd/update-components
Update toolkit components
2022-03-16 03:16:19 +05:30
fluxcdbot
ff65491bb6 Update toolkit components
- helm-controller to v0.17.2
  https://github.com/fluxcd/helm-controller/blob/v0.17.2/CHANGELOG.md
- notification-controller to v0.22.3
  https://github.com/fluxcd/notification-controller/blob/v0.22.3/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-03-15 20:41:25 +00:00
Stefan Prodan
8f514d8991 Merge pull request #2530 from fluxcd/components-extra-example
Add components-extra example usage to CLI help
2022-03-11 11:34:22 +02:00
Stefan Prodan
2e1000c31a Add components-extra example usage to CLI help
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-03-11 09:19:56 +02:00
Stefan Prodan
c5171a1f2e Merge pull request #2512 from souleb/introduce-printer-interface
Introduce a printer interface for flux resources
2022-03-07 13:55:33 +02:00
Soule BA
7359e63960 Introduce a printer interface for flux resource
If implemented, there will a common interface to print flux resource.

We are adding new way to print resource information e.g. diff of
objects.

Signed-off-by: Soule BA <soule@weave.works>
2022-03-07 12:15:35 +01:00
Stefan Prodan
307309504b Merge pull request #2484 from cuishuang/main
all: fix some typos
2022-03-02 14:23:04 +02:00
cuishuang
1fda202cf9 all: fix some typos
Signed-off-by: cuishuang <imcusg@gmail.com>
2022-03-02 19:36:08 +08:00
Sunny
7e634c154f Merge pull request #2483 from fluxcd/update-components
Update toolkit components
2022-03-01 21:18:05 +05:30
fluxcdbot
3c72e35381 Update toolkit components
- image-automation-controller to v0.20.1
  https://github.com/fluxcd/image-automation-controller/blob/v0.20.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-03-01 15:07:34 +00:00
Stefan Prodan
7e23430882 Merge pull request #2467 from fluxcd/update-get-column-order
Update `get` subcommand column order
2022-02-28 15:34:38 +02:00
Sunny
2c4c3fd749 test: ignore golden template files with -update
Add a template values check in the `assertGoldenTemplateFile()` function
to only update golden files if they aren't templates. A note is printed
when an update to a template golden file is needed and `-update` flag
can't update it.

Signed-off-by: Sunny <darkowlzz@protonmail.com>
2022-02-28 08:56:08 +05:30
Sunny
edaf6ca522 Add test flag -update to update the golden files
Test flag `-update` can be used to update all the golden files whenever
the CLI output changes.

Signed-off-by: Sunny <darkowlzz@protonmail.com>
2022-02-24 08:58:19 +05:30
Sunny
21f0d5d82c Move MESSAGE to the end of get subcommand output
Message content could be long compared to other fields. Moving it to
the end helps improve the visibility of the other fields.

Signed-off-by: Sunny <darkowlzz@protonmail.com>
2022-02-24 04:21:47 +05:30
Stefan Prodan
059751b3c9 Merge pull request #2462 from fluxcd/update-components
Update notification-controller to v0.22.2
2022-02-23 15:53:19 +02:00
fluxcdbot
05479756d8 Update toolkit components
- notification-controller to v0.22.2
  https://github.com/fluxcd/notification-controller/blob/v0.22.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-02-23 13:37:43 +00:00
Stefan Prodan
34e19cb638 Merge pull request #2440 from fluxcd/diagrams
Add e2e sequence diagrams
2022-02-23 13:52:55 +02:00
Stefan Prodan
5312f81c8e Add e2e sequence diagrams
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-23 13:28:25 +02:00
Stefan Prodan
7f02898539 Merge pull request #2460 from fluxcd/update-components
Update toolkit components
2022-02-23 13:27:31 +02:00
fluxcdbot
8aabc544f1 Update toolkit components
- helm-controller to v0.17.1
  https://github.com/fluxcd/helm-controller/blob/v0.17.1/CHANGELOG.md
- kustomize-controller to v0.21.1
  https://github.com/fluxcd/kustomize-controller/blob/v0.21.1/CHANGELOG.md
- notification-controller to v0.22.1
  https://github.com/fluxcd/notification-controller/blob/v0.22.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-02-23 09:00:51 +00:00
Stefan Prodan
3b62955e81 Merge pull request #2450 from SomtochiAma/resume-all-wait
Add `--wait` flag to flux `resume` cmd
2022-02-21 12:26:53 +02:00
Somtochi Onyekwere
9c76ba903b add wait flag to flux resume cmd
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-21 11:07:55 +01:00
Stefan Prodan
b4118b73ed Merge pull request #2448 from SomtochiAma/metadata-client
Use `metadata.Client` for reconcile operations
2022-02-21 12:02:53 +02:00
Somtochi Onyekwere
82a8697f28 Add gvk to rest of api type
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-21 10:40:35 +01:00
Stefan Prodan
5b9a1ce5c6 Merge pull request #2452 from souleb/fix-stringData-diff
Diff: fix stringData Secret issue
2022-02-21 11:20:24 +02:00
Soule BA
32ad462ebe Fix stringData Secret issue
This commit migrate to the last version of pkg/ssa v0.14.1 that contains a fix
for stringData secrets. The test case was changed accordingly to
    validate a stringData drift.

A progress-bar flag option has also been added in order to be able to
disable it.

Signed-off-by: Soule BA <soule@weave.works>
2022-02-18 17:18:16 +01:00
Stefan Prodan
1ff8c2806c Merge pull request #2441 from andrewjjenkins/fix-trace-test-tz
Fix failure in TestTrace/* when timezone isn't UTC
2022-02-17 13:51:46 +02:00
Andrew Jenkins
437a7a2852 Fix failure in TestTrace/* when timezone isn't UTC
The TestTrace/Deployment and TestTrace/HelmRelease test cases fail in
environments where the timezone isn't UTC, because they compare a local time
string to the golden file, which has time in UTC.  Here is an example:

```
--- FAIL: TestTrace (0.12s)
    --- FAIL: TestTrace/Deployment (0.08s)
        main_test.go:337: Mismatch from golden file 'testdata/trace/deployment.golden': Mismatch from expected value (-want +got):
              strings.Join({
                ... // 88 identical bytes
                " Flux\n---\nHelmRelease:    podinfo\nNamespace:      podinfo-8\nRevi",
                "sion:       6.0.0\nStatus:         Last reconciled at 2021-07-16 ",
            -   "15:42:20 +0000 UTC",
            +   "09:42:20 -0600 MDT",
                "\nMessage:        Release reconciliation succeeded\n---\nHelmChart:",
                "      podinfo-podinfo\nNamespace:      flux-system-9\nChart:      ",
                "    podinfo\nVersion:        6.0.0\nRevision:       6.0.0\nStatus: ",
                "        Last reconciled at 2021-07-16 ",
            -   "15:32:09 +0000 UTC",
            +   "09:32:09 -0600 MDT",
                "\nMessage:        Fetched revision: 6.0.0\n---\nHelmRepository: pod",
                "info\nNamespace:      flux-system-9\nURL:            https://stefa",
                "nprodan.github.io/podinfo\nRevision:       8411f23d07d3701f0e96e7",
                "d9e503b7936d7e1d56\nStatus:         Last reconciled at 2021-07-",
            -   "1",
                "1",
            -   " 00:25:46 +0000 UTC",
            +   "0 18:25:46 -0600 MDT",
                "\nMessage:        Fetched revision: 8411f23d07d3701f0e96e7d9e503b",
                "7936d7e1d56\n",
              }, "")
```

This commit fixes the issue by converting the golden test times to local
time before comparing. The utility function toLocalTime() is added to
trace_test.go, and then it is used to provide localized times as
template parameters to the golden files.

Signed-off-by: Andrew Jenkins <andrew@aspenmesh.io>
2022-02-16 09:36:00 -07:00
Stefan Prodan
412db70773 Merge pull request #2444 from fluxcd/update-components
Update toolkit components
2022-02-16 15:20:38 +02:00
fluxcdbot
a1bb6babed Update toolkit components
- helm-controller to v0.17.0
  https://github.com/fluxcd/helm-controller/blob/v0.17.0/CHANGELOG.md
- kustomize-controller to v0.21.0
  https://github.com/fluxcd/kustomize-controller/blob/v0.21.0/CHANGELOG.md
- notification-controller to v0.22.0
  https://github.com/fluxcd/notification-controller/blob/v0.22.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-02-16 12:57:45 +00:00
Stefan Prodan
568c536c3c Merge pull request #2443 from SomtochiAma/log-bug
Validate that object name adheres to RFC 1123 for `flux create` commands
2022-02-16 14:57:00 +02:00
Somtochi Onyekwere
d7129d6b55 Remove validation from sub-commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-16 11:04:05 +01:00
Somtochi Onyekwere
4a893b13f8 validate that object name adheres to RFC 1123 for flux create commands
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-16 10:51:03 +01:00
Stefan Prodan
8c2983c958 Merge pull request #2439 from SomtochiAma/log-bug
Use text/template library instead of html/template for logs
2022-02-15 09:30:58 +02:00
Somtochi Onyekwere
a30ffdb176 Use text/template
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-14 23:59:20 +01:00
Stefan Prodan
7a306e69ab Merge pull request #2426 from foot/support-dot-prefixed-paths
Add support for Kustomizations with dot-prefixed paths
2022-02-14 12:32:25 +02:00
Simon Howe
23c4c2f1aa Adds test for parent directory
Signed-off-by: Simon Howe <footless@gmail.com>
2022-02-14 10:51:20 +01:00
Simon Howe
aac07f03d8 Adds test for using dot to represent pwd
Signed-off-by: Simon Howe <footless@gmail.com>
2022-02-14 10:48:58 +01:00
Simon Howe
f4418920fb Adds support for dot-prefixed paths in git
- in `flux bootstrap` and `flux create kustomization` etc.
- E.g. for example `--path=.flux` should work now
- Previous behaviour is to strip off any leading "." and leave you with
  "./flux" in the kustomizations / folder structure generated by `flux
  bootstrap`

Signed-off-by: Simon Howe <footless@gmail.com>
2022-02-14 09:10:18 +01:00
Stefan Prodan
7752206152 Merge pull request #2427 from souleb/issue-2411
Bootstrap bitbucket-server: Make sure we retrieve the right project
2022-02-12 15:40:29 +02:00
Soule BA
c950f8f817 Make sure bootstrap bitbucket-server retrieve the right project
When fetching a project by name, a list is returned. If implented, this
will make sure we return the right project from the list.

Signed-off-by: Soule BA <soule@weave.works>
2022-02-12 13:31:11 +01:00
Stefan Prodan
9276345fe7 Merge pull request #2425 from souleb/adding-a-simple-spinner
Add a simple spinner when running flux diff kustomization
2022-02-12 14:25:51 +02:00
Soule BA
01f910e257 Add a simple spinner when running flux diff kustomization
If implemented, users will see a spinner run while the diff is on-going.

Signed-off-by: Soule BA <soule@weave.works>
2022-02-11 18:11:28 +01:00
137 changed files with 1671 additions and 856 deletions

View File

@@ -42,8 +42,7 @@ jobs:
if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then
go mod edit -require="github.com/fluxcd/$1/api@${LATEST_VERSION}" go mod edit -require="github.com/fluxcd/$1/api@${LATEST_VERSION}"
rm go.sum make tidy
go mod tidy
changed=true changed=true
fi fi

View File

@@ -96,6 +96,25 @@ Then you can run the end-to-end tests with:
make e2e make e2e
``` ```
When the output of the Flux CLI changes, to automatically update the golden
files used in the test, pass `-update` flag to the test as:
```bash
make e2e TEST_ARGS="-update"
```
Since not all packages use golden files for testing, `-update` argument must be
passed only for the packages that use golden files. Use the variables
`TEST_PKG_PATH` for unit tests and `E2E_TEST_PKG_PATH` for e2e tests, to set the
path of the target test package:
```bash
# Unit test
make test TEST_PKG_PATH="./cmd/flux" TEST_ARGS="-update"
# e2e test
make e2e E2E_TEST_PKG_PATH="./cmd/flux" TEST_ARGS="-update"
```
Teardown the e2e environment with: Teardown the e2e environment with:
```bash ```bash

View File

@@ -16,8 +16,8 @@ rwildcard=$(foreach d,$(wildcard $(addsuffix *,$(1))),$(call rwildcard,$(d)/,$(2
all: test build all: test build
tidy: tidy:
go mod tidy go mod tidy -compat=1.17
cd tests/azure && go mod tidy cd tests/azure && go mod tidy -compat=1.17
fmt: fmt:
go fmt ./... go fmt ./...
@@ -35,11 +35,13 @@ cleanup-kind:
rm $(TEST_KUBECONFIG) rm $(TEST_KUBECONFIG)
KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)" KUBEBUILDER_ASSETS?="$(shell $(ENVTEST) --arch=$(ENVTEST_ARCH) use -i $(ENVTEST_KUBERNETES_VERSION) --bin-dir=$(ENVTEST_ASSETS_DIR) -p path)"
TEST_PKG_PATH="./..."
test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet install-envtest test: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet install-envtest
KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test ./... -coverprofile cover.out --tags=unit KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test $(TEST_PKG_PATH) -coverprofile cover.out --tags=unit $(TEST_ARGS)
E2E_TEST_PKG_PATH="./cmd/flux/..."
e2e: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet e2e: $(EMBEDDED_MANIFESTS_TARGET) tidy fmt vet
TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test ./cmd/flux/... -coverprofile e2e.cover.out --tags=e2e -v -failfast TEST_KUBECONFIG=$(TEST_KUBECONFIG) go test $(E2E_TEST_PKG_PATH) -coverprofile e2e.cover.out --tags=e2e -v -failfast $(TEST_ARGS)
test-with-kind: install-envtest test-with-kind: install-envtest
make setup-kind make setup-kind

View File

@@ -25,8 +25,9 @@ import (
// notificationv1.Alert // notificationv1.Alert
var alertType = apiType{ var alertType = apiType{
kind: notificationv1.AlertKind, kind: notificationv1.AlertKind,
humanKind: "alert", humanKind: "alert",
groupVersion: notificationv1.GroupVersion,
} }
type alertAdapter struct { type alertAdapter struct {

View File

@@ -25,8 +25,9 @@ import (
// notificationv1.Provider // notificationv1.Provider
var alertProviderType = apiType{ var alertProviderType = apiType{
kind: notificationv1.ProviderKind, kind: notificationv1.ProviderKind,
humanKind: "alert provider", humanKind: "alert provider",
groupVersion: notificationv1.GroupVersion,
} }
type alertProviderAdapter struct { type alertProviderAdapter struct {

View File

@@ -88,7 +88,7 @@ func init() {
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components, bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values") "list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil, bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts comma-separated values") "list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd", bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
"container registry where the toolkit images are published") "container registry where the toolkit images are published")

View File

@@ -19,6 +19,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"regexp"
"strings" "strings"
"time" "time"
@@ -51,6 +52,18 @@ func init() {
createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout") createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout")
createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil, createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil,
"set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)") "set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)")
createCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("name is required")
}
name := args[0]
if !validateObjectName(name) {
return fmt.Errorf("name '%s' is invalid, it should adhere to standard defined in RFC 1123, the name can only contain alphanumeric characters or '-'", name)
}
return nil
}
rootCmd.AddCommand(createCmd) rootCmd.AddCommand(createCmd)
} }
@@ -150,3 +163,8 @@ func parseLabels() (map[string]string, error) {
return result, nil return result, nil
} }
func validateObjectName(name string) bool {
r := regexp.MustCompile("^[a-z0-9]([a-z0-9\\-]){0,61}[a-z0-9]$")
return r.MatchString(name)
}

View File

@@ -63,9 +63,6 @@ func init() {
} }
func createAlertCmdRun(cmd *cobra.Command, args []string) error { func createAlertCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Alert name is required")
}
name := args[0] name := args[0]
if alertArgs.providerRef == "" { if alertArgs.providerRef == "" {

View File

@@ -73,9 +73,6 @@ func init() {
} }
func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error { func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Provider name is required")
}
name := args[0] name := args[0]
if alertProviderArgs.alertType == "" { if alertProviderArgs.alertType == "" {

View File

@@ -139,9 +139,6 @@ func init() {
} }
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error { func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRelease name is required")
}
name := args[0] name := args[0]
if helmReleaseArgs.chart == "" { if helmReleaseArgs.chart == "" {

View File

@@ -84,9 +84,6 @@ func (obj imagePolicyAdapter) getObservedGeneration() int64 {
} }
func createImagePolicyRun(cmd *cobra.Command, args []string) error { func createImagePolicyRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImagePolicy name is required")
}
objectName := args[0] objectName := args[0]
if imagePolicyArgs.imageRef == "" { if imagePolicyArgs.imageRef == "" {

View File

@@ -83,9 +83,6 @@ func init() {
} }
func createImageRepositoryRun(cmd *cobra.Command, args []string) error { func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImageRepository name is required")
}
objectName := args[0] objectName := args[0]
if imageRepoArgs.image == "" { if imageRepoArgs.image == "" {

View File

@@ -23,7 +23,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1" autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var createImageUpdateCmd = &cobra.Command{ var createImageUpdateCmd = &cobra.Command{
@@ -94,9 +94,6 @@ func init() {
} }
func createImageUpdateRun(cmd *cobra.Command, args []string) error { func createImageUpdateRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImageUpdateAutomation name is required")
}
objectName := args[0] objectName := args[0]
if imageUpdateArgs.gitRepoName == "" { if imageUpdateArgs.gitRepoName == "" {

View File

@@ -119,9 +119,6 @@ func NewKustomizationFlags() kustomizationFlags {
} }
func createKsCmdRun(cmd *cobra.Command, args []string) error { func createKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Kustomization name is required")
}
name := args[0] name := args[0]
if kustomizationArgs.path == "" { if kustomizationArgs.path == "" {

View File

@@ -67,9 +67,6 @@ func init() {
} }
func createReceiverCmdRun(cmd *cobra.Command, args []string) error { func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Receiver name is required")
}
name := args[0] name := args[0]
if receiverArgs.receiverType == "" { if receiverArgs.receiverType == "" {

View File

@@ -112,9 +112,6 @@ func NewSecretGitFlags() secretGitFlags {
} }
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error { func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0] name := args[0]
if secretGitArgs.url == "" { if secretGitArgs.url == "" {
return fmt.Errorf("url is required") return fmt.Errorf("url is required")

View File

@@ -13,7 +13,7 @@ func TestCreateGitSecret(t *testing.T) {
{ {
name: "no args", name: "no args",
args: "create secret git", args: "create secret git",
assert: assertError("secret name is required"), assert: assertError("name is required"),
}, },
{ {
name: "basic secret", name: "basic secret",

View File

@@ -18,7 +18,6 @@ package main
import ( import (
"context" "context"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
@@ -68,9 +67,6 @@ func init() {
} }
func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error { func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0] name := args[0]
labels, err := parseLabels() labels, err := parseLabels()

View File

@@ -12,7 +12,7 @@ func TestCreateHelmSecret(t *testing.T) {
}{ }{
{ {
args: "create secret helm", args: "create secret helm",
assert: assertError("secret name is required"), assert: assertError("name is required"),
}, },
{ {
args: "create secret helm helm-secret --username=my-username --password=my-password --namespace=my-namespace --export", args: "create secret helm helm-secret --username=my-username --password=my-password --namespace=my-namespace --export",

View File

@@ -18,7 +18,6 @@ package main
import ( import (
"context" "context"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@@ -67,9 +66,6 @@ func init() {
} }
func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error { func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("secret name is required")
}
name := args[0] name := args[0]
labels, err := parseLabels() labels, err := parseLabels()

View File

@@ -12,7 +12,7 @@ func TestCreateTlsSecretNoArgs(t *testing.T) {
}{ }{
{ {
args: "create secret tls", args: "create secret tls",
assert: assertError("secret name is required"), assert: assertError("name is required"),
}, },
{ {
args: "create secret tls certs --namespace=my-namespace --cert-file=./testdata/create_secret/tls/test-cert.pem --key-file=./testdata/create_secret/tls/test-key.pem --export", args: "create secret tls certs --namespace=my-namespace --cert-file=./testdata/create_secret/tls/test-cert.pem --key-file=./testdata/create_secret/tls/test-key.pem --export",

View File

@@ -30,7 +30,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" "github.com/fluxcd/pkg/runtime/conditions"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/internal/flags" "github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
@@ -93,9 +95,6 @@ func NewSourceBucketFlags() sourceBucketFlags {
} }
func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error { func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("Bucket source name is required")
}
name := args[0] name := args[0]
if sourceBucketArgs.name == "" { if sourceBucketArgs.name == "" {
@@ -238,3 +237,30 @@ func upsertBucket(ctx context.Context, kubeClient client.Client,
logger.Successf("Bucket source updated") logger.Successf("Bucket source updated")
return namespacedName, nil return namespacedName, nil
} }
func isBucketReady(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
}
if c := conditions.Get(bucket, meta.ReadyCondition); c != nil {
// Confirm the Ready condition we are observing is for the
// current generation
if c.ObservedGeneration != bucket.GetGeneration() {
return false, nil
}
// Further check the Status
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

View File

@@ -23,19 +23,21 @@ import (
"net/url" "net/url"
"os" "os"
"github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/internal/flags" "github.com/fluxcd/flux2/internal/flags"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret" "github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
@@ -150,9 +152,6 @@ func newSourceGitFlags() sourceGitFlags {
} }
func createSourceGitCmdRun(cmd *cobra.Command, args []string) error { func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("GitRepository source name is required")
}
name := args[0] name := args[0]
if sourceGitArgs.url == "" { if sourceGitArgs.url == "" {
@@ -172,7 +171,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
if sourceGitArgs.caFile != "" && u.Scheme == "ssh" { if sourceGitArgs.caFile != "" && u.Scheme == "ssh" {
return fmt.Errorf("specifing a CA file is not supported for Git over SSH") return fmt.Errorf("specifying a CA file is not supported for Git over SSH")
} }
if sourceGitArgs.recurseSubmodules && sourceGitArgs.gitImplementation == sourcev1.LibGit2Implementation { if sourceGitArgs.recurseSubmodules && sourceGitArgs.gitImplementation == sourcev1.LibGit2Implementation {
@@ -358,7 +357,14 @@ func isGitRepositoryReady(ctx context.Context, kubeClient client.Client,
return false, err return false, err
} }
if c := apimeta.FindStatusCondition(gitRepository.Status.Conditions, meta.ReadyCondition); c != nil { if c := conditions.Get(gitRepository, meta.ReadyCondition); c != nil {
// Confirm the Ready condition we are observing is for the
// current generation
if c.ObservedGeneration != gitRepository.GetGeneration() {
return false, nil
}
// Further check the Status
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -21,15 +21,17 @@ package main
import ( import (
"context" "context"
"testing"
"time"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"testing"
"time"
) )
var pollInterval = 50 * time.Millisecond var pollInterval = 50 * time.Millisecond
@@ -96,14 +98,21 @@ func TestCreateSourceGit(t *testing.T) {
{ {
"NoArgs", "NoArgs",
"create source git", "create source git",
assertError("GitRepository source name is required"), assertError("name is required"),
nil, nil,
}, { }, {
"Succeeded", "Succeeded",
command, command,
assertGoldenFile("testdata/create_source_git/success.golden"), assertGoldenFile("testdata/create_source_git/success.golden"),
func(repo *sourcev1.GitRepository) { func(repo *sourcev1.GitRepository) {
meta.SetResourceCondition(repo, meta.ReadyCondition, metav1.ConditionTrue, sourcev1.GitOperationSucceedReason, "succeeded message") newCondition := metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionTrue,
Reason: sourcev1.GitOperationSucceedReason,
Message: "succeeded message",
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
repo.Status.Artifact = &sourcev1.Artifact{ repo.Status.Artifact = &sourcev1.Artifact{
Path: "some-path", Path: "some-path",
Revision: "v1", Revision: "v1",
@@ -114,7 +123,14 @@ func TestCreateSourceGit(t *testing.T) {
command, command,
assertError("failed message"), assertError("failed message"),
func(repo *sourcev1.GitRepository) { func(repo *sourcev1.GitRepository) {
meta.SetResourceCondition(repo, meta.ReadyCondition, metav1.ConditionFalse, sourcev1.URLInvalidReason, "failed message") newCondition := metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionFalse,
Reason: sourcev1.URLInvalidReason,
Message: "failed message",
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
}, },
}, { }, {
"NoArtifact", "NoArtifact",
@@ -122,7 +138,14 @@ func TestCreateSourceGit(t *testing.T) {
assertError("GitRepository source reconciliation completed but no artifact was found"), assertError("GitRepository source reconciliation completed but no artifact was found"),
func(repo *sourcev1.GitRepository) { func(repo *sourcev1.GitRepository) {
// Updated with no artifact // Updated with no artifact
meta.SetResourceCondition(repo, meta.ReadyCondition, metav1.ConditionTrue, sourcev1.GitOperationSucceedReason, "succeeded message") newCondition := metav1.Condition{
Type: meta.ReadyCondition,
Status: metav1.ConditionTrue,
Reason: sourcev1.GitOperationSucceedReason,
Message: "succeeded message",
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
}, },
}, },
} }

View File

@@ -23,17 +23,17 @@ import (
"os" "os"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret" "github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
@@ -91,9 +91,6 @@ func init() {
} }
func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error { func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("HelmRepository source name is required")
}
name := args[0] name := args[0]
if sourceHelmArgs.url == "" { if sourceHelmArgs.url == "" {
@@ -245,12 +242,14 @@ func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client,
return false, err return false, err
} }
// Confirm the state we are observing is for the current generation if c := conditions.Get(helmRepository, meta.ReadyCondition); c != nil {
if helmRepository.Generation != helmRepository.Status.ObservedGeneration { // Confirm the Ready condition we are observing is for the
return false, nil // current generation
} if c.ObservedGeneration != helmRepository.GetGeneration() {
return false, nil
}
if c := apimeta.FindStatusCondition(helmRepository.Status.Conditions, meta.ReadyCondition); c != nil { // Further check the Status
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -70,9 +70,6 @@ func init() {
} }
func createTenantCmdRun(cmd *cobra.Command, args []string) error { func createTenantCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("tenant name is required")
}
tenant := args[0] tenant := args[0]
if err := validation.IsQualifiedName(tenant); len(err) > 0 { if err := validation.IsQualifiedName(tenant); len(err) > 0 {
return fmt.Errorf("invalid tenant name '%s': %v", tenant, err) return fmt.Errorf("invalid tenant name '%s': %v", tenant, err)

55
cmd/flux/create_test.go Normal file
View File

@@ -0,0 +1,55 @@
package main
import (
"testing"
"k8s.io/apimachinery/pkg/util/rand"
)
func Test_validateObjectName(t *testing.T) {
tests := []struct {
name string
valid bool
}{
{
name: "flux-system",
valid: true,
},
{
name: "-flux-system",
valid: false,
},
{
name: "-flux-system-",
valid: false,
},
{
name: "third.first",
valid: false,
},
{
name: "THirdfirst",
valid: false,
},
{
name: "THirdfirst",
valid: false,
},
{
name: rand.String(63),
valid: true,
},
{
name: rand.String(64),
valid: false,
},
}
for _, tt := range tests {
valid := validateObjectName(tt.name)
if valid != tt.valid {
t.Errorf("expected name %q to return %t for validateObjectName func but got %t",
tt.name, tt.valid, valid)
}
}
}

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var deleteSourceBucketCmd = &cobra.Command{ var deleteSourceBucketCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var deleteSourceGitCmd = &cobra.Command{ var deleteSourceGitCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var deleteSourceHelmCmd = &cobra.Command{ var deleteSourceHelmCmd = &cobra.Command{

View File

@@ -40,13 +40,15 @@ flux diff kustomization my-app --path ./path/to/local/manifests`,
} }
type diffKsFlags struct { type diffKsFlags struct {
path string path string
progressBar bool
} }
var diffKsArgs diffKsFlags var diffKsArgs diffKsFlags
func init() { func init() {
diffKsCmd.Flags().StringVar(&diffKsArgs.path, "path", "", "Path to a local directory that matches the specified Kustomization.spec.path.)") diffKsCmd.Flags().StringVar(&diffKsArgs.path, "path", "", "Path to a local directory that matches the specified Kustomization.spec.path.)")
diffKsCmd.Flags().BoolVar(&diffKsArgs.progressBar, "progress-bar", true, "Boolean to set the progress bar. The default value is true.")
diffCmd.AddCommand(diffKsCmd) diffCmd.AddCommand(diffKsCmd)
} }
@@ -64,7 +66,14 @@ func diffKsCmdRun(cmd *cobra.Command, args []string) error {
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)} return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)}
} }
builder, err := build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout)) var builder *build.Builder
var err error
if diffKsArgs.progressBar {
builder, err = build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout), build.WithProgressBar())
} else {
builder, err = build.NewBuilder(kubeconfigArgs, name, diffKsArgs.path, build.WithTimeout(rootArgs.timeout))
}
if err != nil { if err != nil {
return &RequestError{StatusCode: 2, Err: err} return &RequestError{StatusCode: 2, Err: err}
} }

View File

@@ -45,51 +45,51 @@ func TestDiffKustomization(t *testing.T) {
}, },
{ {
name: "diff nothing deployed", name: "diff nothing deployed",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "", objectFile: "",
assert: assertGoldenFile("./testdata/diff-kustomization/nothing-is-deployed.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/nothing-is-deployed.golden"),
}, },
{ {
name: "diff with a deployment object", name: "diff with a deployment object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/deployment.yaml", objectFile: "./testdata/diff-kustomization/deployment.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-deployment.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-deployment.golden"),
}, },
{ {
name: "diff with a drifted service object", name: "diff with a drifted service object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/service.yaml", objectFile: "./testdata/diff-kustomization/service.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-service.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-service.golden"),
}, },
{ {
name: "diff with a drifted secret object", name: "diff with a drifted secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/secret.yaml", objectFile: "./testdata/diff-kustomization/secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-secret.golden"),
}, },
{ {
name: "diff with a drifted key in sops secret object", name: "diff with a drifted key in sops secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/key-sops-secret.yaml", objectFile: "./testdata/diff-kustomization/key-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-key-sops-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-key-sops-secret.golden"),
}, },
{ {
name: "diff with a drifted value in sops secret object", name: "diff with a drifted value in sops secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml", objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"),
}, },
{ {
name: "diff with a sops dockerconfigjson secret object", name: "diff with a sops dockerconfigjson secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml", objectFile: "./testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden"),
}, },
{ {
name: "diff with a sops stringdata secret object", name: "diff with a sops stringdata secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo", args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/stringdata-sops-secret.yaml", objectFile: "./testdata/diff-kustomization/stringdata-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-stringdata-sops-secret.golden"), assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-stringdata-sops-secret.golden"),
}, },
} }
@@ -137,5 +137,9 @@ func createObjectFromFile(objectFile string, templateValues map[string]string, t
t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err) t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err)
} }
if err := ssa.SetNativeKindsDefaults(clientObjects); err != nil {
t.Fatalf("Error setting native kinds defaults for '%s': %v", objectFile, err)
}
return clientObjects return clientObjects
} }

View File

@@ -21,7 +21,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var exportSourceBucketCmd = &cobra.Command{ var exportSourceBucketCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var exportSourceGitCmd = &cobra.Command{ var exportSourceGitCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var exportSourceHelmCmd = &cobra.Command{ var exportSourceHelmCmd = &cobra.Command{

View File

@@ -33,6 +33,7 @@ import (
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/flux2/pkg/printers"
) )
type deriveType func(runtime.Object) (summarisable, error) type deriveType func(runtime.Object) (summarisable, error)
@@ -177,7 +178,10 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
return err return err
} }
utils.PrintTable(cmd.OutOrStdout(), header, rows) err = printers.TablePrinter(header).Print(cmd.OutOrStdout(), rows)
if err != nil {
return err
}
if getAll { if getAll {
fmt.Println() fmt.Println()
@@ -242,10 +246,16 @@ func watchUntil(ctx context.Context, w watch.Interface, get *getCommand) (bool,
return false, err return false, err
} }
if firstIteration { if firstIteration {
utils.PrintTable(os.Stdout, header, rows) err = printers.TablePrinter(header).Print(os.Stdout, rows)
if err != nil {
return false, err
}
firstIteration = false firstIteration = false
} else { } else {
utils.PrintTable(os.Stdout, []string{}, rows) err = printers.TablePrinter([]string{}).Print(os.Stdout, rows)
if err != nil {
return false, err
}
} }
return false, nil return false, nil

View File

@@ -77,11 +77,11 @@ func init() {
func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s alertListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend))) return append(nameColumns(&item, includeNamespace, includeKind), strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (s alertListAdapter) headers(includeNamespace bool) []string { func (s alertListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Suspended"} headers := []string{"Name", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -75,11 +75,11 @@ func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool, incl
revision := item.Status.LastAppliedRevision revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (a helmReleaseListAdapter) headers(includeNamespace bool) []string { func (a helmReleaseListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -74,11 +74,11 @@ func init() {
func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), status, msg, item.Status.LatestImage) return append(nameColumns(&item, includeNamespace, includeKind), item.Status.LatestImage, status, msg)
} }
func (s imagePolicyListAdapter) headers(includeNamespace bool) []string { func (s imagePolicyListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Latest image"} headers := []string{"Name", "Latest image", "Ready", "Message"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -82,11 +82,11 @@ func (s imageRepositoryListAdapter) summariseItem(i int, includeNamespace bool,
lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339) lastScan = item.Status.LastScanResult.ScanTime.Time.Format(time.RFC3339)
} }
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend))) lastScan, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string { func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Last scan", "Suspended"} headers := []string{"Name", "Last scan", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -81,11 +81,11 @@ func (s imageUpdateAutomationListAdapter) summariseItem(i int, includeNamespace
if item.Status.LastAutomationRunTime != nil { if item.Status.LastAutomationRunTime != nil {
lastRun = item.Status.LastAutomationRunTime.Time.Format(time.RFC3339) lastRun = item.Status.LastAutomationRunTime.Time.Format(time.RFC3339)
} }
return append(nameColumns(&item, includeNamespace, includeKind), status, msg, lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend))) return append(nameColumns(&item, includeNamespace, includeKind), lastRun, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string { func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Last run", "Suspended"} headers := []string{"Name", "Last run", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -85,11 +85,11 @@ func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool, in
msg = shortenCommitSha(msg) msg = shortenCommitSha(msg)
} }
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (a kustomizationListAdapter) headers(includeNamespace bool) []string { func (a kustomizationListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -74,11 +74,11 @@ func init() {
func (s receiverListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s receiverListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), status, msg, strings.Title(strconv.FormatBool(item.Spec.Suspend))) return append(nameColumns(&item, includeNamespace, includeKind), strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (s receiverListAdapter) headers(includeNamespace bool) []string { func (s receiverListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Suspended"} headers := []string{"Name", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var getSourceAllCmd = &cobra.Command{ var getSourceAllCmd = &cobra.Command{

View File

@@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var getSourceBucketCmd = &cobra.Command{ var getSourceBucketCmd = &cobra.Command{
@@ -81,11 +81,11 @@ func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool, includeK
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (a bucketListAdapter) headers(includeNamespace bool) []string { func (a bucketListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var getSourceHelmChartCmd = &cobra.Command{ var getSourceHelmChartCmd = &cobra.Command{
@@ -81,11 +81,11 @@ func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool, inclu
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (a helmChartListAdapter) headers(includeNamespace bool) []string { func (a helmChartListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -25,7 +25,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var getSourceGitCmd = &cobra.Command{ var getSourceGitCmd = &cobra.Command{
@@ -86,11 +86,11 @@ func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool, i
msg = shortenCommitSha(msg) msg = shortenCommitSha(msg)
} }
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string { func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var getSourceHelmCmd = &cobra.Command{ var getSourceHelmCmd = &cobra.Command{
@@ -81,11 +81,11 @@ func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool,
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), return append(nameColumns(&item, includeNamespace, includeKind),
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend))) revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)), status, msg)
} }
func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string { func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"} headers := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
if includeNamespace { if includeNamespace {
headers = append([]string{"Namespace"}, headers...) headers = append([]string{"Namespace"}, headers...)
} }

View File

@@ -25,8 +25,9 @@ import (
// helmv2.HelmRelease // helmv2.HelmRelease
var helmReleaseType = apiType{ var helmReleaseType = apiType{
kind: helmv2.HelmReleaseKind, kind: helmv2.HelmReleaseKind,
humanKind: "helmreleases", humanKind: "helmrelease",
groupVersion: helmv2.GroupVersion,
} }
type helmReleaseAdapter struct { type helmReleaseAdapter struct {

View File

@@ -30,8 +30,9 @@ import (
// imagev1.ImageRepository // imagev1.ImageRepository
var imageRepositoryType = apiType{ var imageRepositoryType = apiType{
kind: imagev1.ImageRepositoryKind, kind: imagev1.ImageRepositoryKind,
humanKind: "image repository", humanKind: "image repository",
groupVersion: imagev1.GroupVersion,
} }
type imageRepositoryAdapter struct { type imageRepositoryAdapter struct {
@@ -63,8 +64,9 @@ func (a imageRepositoryListAdapter) len() int {
// imagev1.ImagePolicy // imagev1.ImagePolicy
var imagePolicyType = apiType{ var imagePolicyType = apiType{
kind: imagev1.ImagePolicyKind, kind: imagev1.ImagePolicyKind,
humanKind: "image policy", humanKind: "image policy",
groupVersion: imagev1.GroupVersion,
} }
type imagePolicyAdapter struct { type imagePolicyAdapter struct {
@@ -92,8 +94,9 @@ func (a imagePolicyListAdapter) len() int {
// autov1.ImageUpdateAutomation // autov1.ImageUpdateAutomation
var imageUpdateAutomationType = apiType{ var imageUpdateAutomationType = apiType{
kind: autov1.ImageUpdateAutomationKind, kind: autov1.ImageUpdateAutomationKind,
humanKind: "image update automation", humanKind: "image update automation",
groupVersion: autov1.GroupVersion,
} }
type imageUpdateAutomationAdapter struct { type imageUpdateAutomationAdapter struct {

View File

@@ -37,10 +37,13 @@ var installCmd = &cobra.Command{
Long: `The install command deploys Flux in the specified namespace. Long: `The install command deploys Flux in the specified namespace.
If a previous version is installed, then an in-place upgrade will be performed.`, If a previous version is installed, then an in-place upgrade will be performed.`,
Example: ` # Install the latest version in the flux-system namespace Example: ` # Install the latest version in the flux-system namespace
flux install --version=latest --namespace=flux-system flux install --namespace=flux-system
# Install a specific version and a series of components # Install a specific series of components
flux install --version=v0.0.7 --components="source-controller,kustomize-controller" flux install --components="source-controller,kustomize-controller"
# Install all components including the image automation ones
flux install --components-extra="image-reflector-controller,image-automation-controller"
# Install Flux onto tainted Kubernetes nodes # Install Flux onto tainted Kubernetes nodes
flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux flux install --toleration-keys=node.kubernetes.io/dedicated-to-flux
@@ -84,7 +87,7 @@ func init() {
installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components, installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values") "list of components, accepts comma-separated values")
installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil, installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts comma-separated values") "list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'")
installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory") installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry, installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published") "container registry where the toolkit images are published")

View File

@@ -25,8 +25,9 @@ import (
// kustomizev1.Kustomization // kustomizev1.Kustomization
var kustomizationType = apiType{ var kustomizationType = apiType{
kind: kustomizev1.KustomizationKind, kind: kustomizev1.KustomizationKind,
humanKind: "kustomizations", humanKind: "kustomization",
groupVersion: kustomizev1.GroupVersion,
} }
type kustomizationAdapter struct { type kustomizationAdapter struct {

View File

@@ -21,12 +21,12 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"html/template"
"io" "io"
"os" "os"
"sort" "sort"
"strings" "strings"
"sync" "sync"
"text/template"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"

View File

@@ -20,6 +20,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"flag"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -42,6 +43,9 @@ import (
var nextNamespaceId int64 var nextNamespaceId int64
// update allows golden files to be updated based on the current output.
var update = flag.Bool("update", false, "update golden files")
// Return a unique namespace with the specified prefix, for tests to create // Return a unique namespace with the specified prefix, for tests to create
// objects that won't collide with each other. // objects that won't collide with each other.
func allocateNamespace(prefix string) string { func allocateNamespace(prefix string) string {
@@ -298,6 +302,18 @@ func assertGoldenTemplateFile(goldenFile string, templateValues map[string]strin
expectedOutput = string(goldenFileContents) expectedOutput = string(goldenFileContents)
} }
if assertErr := assertGoldenValue(expectedOutput)(output, err); assertErr != nil { if assertErr := assertGoldenValue(expectedOutput)(output, err); assertErr != nil {
// Update the golden files if comparison fails and the update flag is set.
if *update && output != "" {
// Skip update if there are template values.
if len(templateValues) > 0 {
fmt.Println("NOTE: -update flag passed but golden template files can't be updated, please update it manually")
} else {
if err := os.WriteFile(goldenFile, []byte(output), 0644); err != nil {
return fmt.Errorf("failed to update golden file '%s': %v", goldenFile, err)
}
return nil
}
}
return fmt.Errorf("Mismatch from golden file '%s': %v", goldenFile, assertErr) return fmt.Errorf("Mismatch from golden file '%s': %v", goldenFile, assertErr)
} }
return nil return nil

View File

@@ -28,6 +28,7 @@ import (
// implementation can pick whichever it wants to use. // implementation can pick whichever it wants to use.
type apiType struct { type apiType struct {
kind, humanKind string kind, humanKind string
groupVersion schema.GroupVersion
} }
// adapter is an interface for a wrapper or alias from which we can // adapter is an interface for a wrapper or alias from which we can

View File

@@ -25,8 +25,9 @@ import (
// notificationv1.Receiver // notificationv1.Receiver
var receiverType = apiType{ var receiverType = apiType{
kind: notificationv1.ReceiverKind, kind: notificationv1.ReceiverKind,
humanKind: "receiver", humanKind: "receiver",
groupVersion: notificationv1.GroupVersion,
} }
type receiverAdapter struct { type receiverAdapter struct {

View File

@@ -24,6 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry" "k8s.io/client-go/util/retry"
@@ -59,13 +60,22 @@ type reconcilable interface {
GetAnnotations() map[string]string GetAnnotations() map[string]string
SetAnnotations(map[string]string) SetAnnotations(map[string]string)
// this is usually implemented by GOTK types, since it's used for meta.SetResourceCondition
GetStatusConditions() *[]metav1.Condition
lastHandledReconcileRequest() string // what was the last handled reconcile request? lastHandledReconcileRequest() string // what was the last handled reconcile request?
successMessage() string // what do you want to tell people when successfully reconciled? successMessage() string // what do you want to tell people when successfully reconciled?
} }
func reconcilableConditions(object reconcilable) []metav1.Condition {
if s, ok := object.(meta.ObjectWithConditions); ok {
return s.GetConditions()
}
if s, ok := object.(oldConditions); ok {
return *s.GetStatusConditions()
}
return []metav1.Condition{}
}
func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error { func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
if len(args) < 1 { if len(args) < 1 {
return fmt.Errorf("%s name is required", reconcile.kind) return fmt.Errorf("%s name is required", reconcile.kind)
@@ -95,7 +105,8 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
} }
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace) logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace)
if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil { if err := requestReconciliation(ctx, kubeClient, namespacedName,
reconcile.groupVersion.WithKind(reconcile.kind)); err != nil {
return err return err
} }
logger.Successf("%s annotated", reconcile.kind) logger.Successf("%s annotated", reconcile.kind)
@@ -116,7 +127,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil { reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil {
return err return err
} }
readyCond := apimeta.FindStatusCondition(*reconcile.object.GetStatusConditions(), meta.ReadyCondition) readyCond := apimeta.FindStatusCondition(reconcilableConditions(reconcile.object), meta.ReadyCondition)
if readyCond == nil { if readyCond == nil {
return fmt.Errorf("status can't be determined") return fmt.Errorf("status can't be determined")
} }
@@ -135,28 +146,32 @@ func reconciliationHandled(ctx context.Context, kubeClient client.Client,
if err != nil { if err != nil {
return false, err return false, err
} }
isProgressing := apimeta.IsStatusConditionPresentAndEqual(*obj.GetStatusConditions(), isProgressing := apimeta.IsStatusConditionPresentAndEqual(reconcilableConditions(obj),
meta.ReadyCondition, metav1.ConditionUnknown) meta.ReadyCondition, metav1.ConditionUnknown)
return obj.lastHandledReconcileRequest() != lastHandledReconcileAt && !isProgressing, nil return obj.lastHandledReconcileRequest() != lastHandledReconcileAt && !isProgressing, nil
} }
} }
func requestReconciliation(ctx context.Context, kubeClient client.Client, func requestReconciliation(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, obj reconcilable) error { namespacedName types.NamespacedName, gvk schema.GroupVersionKind) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) { return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
if err := kubeClient.Get(ctx, namespacedName, obj.asClientObject()); err != nil { object := &metav1.PartialObjectMetadata{}
object.SetGroupVersionKind(gvk)
object.SetName(namespacedName.Name)
object.SetNamespace(namespacedName.Namespace)
if err := kubeClient.Get(ctx, namespacedName, object); err != nil {
return err return err
} }
patch := client.MergeFrom(obj.deepCopyClientObject()) patch := client.MergeFrom(object.DeepCopy())
if ann := obj.GetAnnotations(); ann == nil { if ann := object.GetAnnotations(); ann == nil {
obj.SetAnnotations(map[string]string{ object.SetAnnotations(map[string]string{
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano), meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
}) })
} else { } else {
ann[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano) ann[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
obj.SetAnnotations(ann) object.SetAnnotations(ann)
} }
return kubeClient.Patch(ctx, obj.asClientObject(), patch) return kubeClient.Patch(ctx, object, patch)
}) })
} }
@@ -168,7 +183,7 @@ func isReconcileReady(ctx context.Context, kubeClient client.Client,
return false, err return false, err
} }
if c := apimeta.FindStatusCondition(*obj.GetStatusConditions(), meta.ReadyCondition); c != nil { if c := apimeta.FindStatusCondition(reconcilableConditions(obj), meta.ReadyCondition); c != nil {
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -21,7 +21,7 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var reconcileHrCmd = &cobra.Command{ var reconcileHrCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var reconcileKsCmd = &cobra.Command{ var reconcileKsCmd = &cobra.Command{

View File

@@ -17,18 +17,11 @@ limitations under the License.
package main package main
import ( import (
"context"
"fmt" "fmt"
"github.com/spf13/cobra" "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"
"github.com/fluxcd/pkg/apis/meta" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
) )
var reconcileSourceBucketCmd = &cobra.Command{ var reconcileSourceBucketCmd = &cobra.Command{
@@ -48,31 +41,6 @@ func init() {
reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd) reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd)
} }
func isBucketReady(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) lastHandledReconcileRequest() string { func (obj bucketAdapter) lastHandledReconcileRequest() string {
return obj.Status.GetLastHandledReconcileRequest() return obj.Status.GetLastHandledReconcileRequest()
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var reconcileSourceGitCmd = &cobra.Command{ var reconcileSourceGitCmd = &cobra.Command{

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var reconcileSourceHelmCmd = &cobra.Command{ var reconcileSourceHelmCmd = &cobra.Command{

View File

@@ -10,9 +10,8 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
"github.com/fluxcd/pkg/apis/meta"
) )
type reconcileWithSource interface { type reconcileWithSource interface {
@@ -71,7 +70,8 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest() lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace) logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, *kubeconfigArgs.Namespace)
if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil { if err := requestReconciliation(ctx, kubeClient, namespacedName,
reconcile.groupVersion.WithKind(reconcile.kind)); err != nil {
return err return err
} }
logger.Successf("%s annotated", reconcile.kind) logger.Successf("%s annotated", reconcile.kind)
@@ -82,7 +82,7 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
return err return err
} }
readyCond := apimeta.FindStatusCondition(*reconcile.object.GetStatusConditions(), meta.ReadyCondition) readyCond := apimeta.FindStatusCondition(reconcilableConditions(reconcile.object), meta.ReadyCondition)
if readyCond == nil { if readyCond == nil {
return fmt.Errorf("status can't be determined") return fmt.Errorf("status can't be determined")
} }

View File

@@ -35,7 +35,8 @@ var resumeCmd = &cobra.Command{
} }
type ResumeFlags struct { type ResumeFlags struct {
all bool all bool
wait bool
} }
var resumeArgs ResumeFlags var resumeArgs ResumeFlags
@@ -43,6 +44,8 @@ var resumeArgs ResumeFlags
func init() { func init() {
resumeCmd.PersistentFlags().BoolVarP(&resumeArgs.all, "all", "", false, resumeCmd.PersistentFlags().BoolVarP(&resumeArgs.all, "all", "", false,
"resume all resources in that namespace") "resume all resources in that namespace")
resumeCmd.PersistentFlags().BoolVarP(&resumeArgs.wait, "wait", "", false,
"waits for one resource to reconcile before moving to the next one")
rootCmd.AddCommand(resumeCmd) rootCmd.AddCommand(resumeCmd)
} }
@@ -107,19 +110,21 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
logger.Successf("%s resumed", resume.humanKind) logger.Successf("%s resumed", resume.humanKind)
namespacedName := types.NamespacedName{ if resumeArgs.wait || !resumeArgs.all {
Name: resume.list.resumeItem(i).asClientObject().GetName(), namespacedName := types.NamespacedName{
Namespace: *kubeconfigArgs.Namespace, Name: resume.list.resumeItem(i).asClientObject().GetName(),
} Namespace: *kubeconfigArgs.Namespace,
}
logger.Waitingf("waiting for %s reconciliation", resume.kind) logger.Waitingf("waiting for %s reconciliation", resume.kind)
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout, if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
isReady(ctx, kubeClient, namespacedName, resume.list.resumeItem(i))); err != nil { isReady(ctx, kubeClient, namespacedName, resume.list.resumeItem(i))); err != nil {
logger.Failuref(err.Error()) logger.Failuref(err.Error())
continue continue
}
logger.Successf("%s reconciliation completed", resume.kind)
logger.Successf(resume.list.resumeItem(i).successMessage())
} }
logger.Successf("%s reconciliation completed", resume.kind)
logger.Successf(resume.list.resumeItem(i).successMessage())
} }
return nil return nil

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var resumeSourceBucketCmd = &cobra.Command{ var resumeSourceBucketCmd = &cobra.Command{
@@ -31,7 +31,8 @@ var resumeSourceBucketCmd = &cobra.Command{
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)), ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)),
RunE: resumeCommand{ RunE: resumeCommand{
apiType: bucketType, apiType: bucketType,
object: &bucketAdapter{&sourcev1.Bucket{}}, object: bucketAdapter{&sourcev1.Bucket{}},
list: bucketListAdapter{&sourcev1.BucketList{}},
}.run, }.run,
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var resumeSourceHelmChartCmd = &cobra.Command{ var resumeSourceHelmChartCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var resumeSourceGitCmd = &cobra.Command{ var resumeSourceGitCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var resumeSourceHelmCmd = &cobra.Command{ var resumeSourceHelmCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
// These are general-purpose adapters for attaching methods to, for // These are general-purpose adapters for attaching methods to, for
@@ -29,8 +29,9 @@ import (
// sourcev1.Bucket // sourcev1.Bucket
var bucketType = apiType{ var bucketType = apiType{
kind: sourcev1.BucketKind, kind: sourcev1.BucketKind,
humanKind: "source bucket", humanKind: "source bucket",
groupVersion: sourcev1.GroupVersion,
} }
type bucketAdapter struct { type bucketAdapter struct {
@@ -62,8 +63,9 @@ func (a bucketListAdapter) len() int {
// sourcev1.HelmChart // sourcev1.HelmChart
var helmChartType = apiType{ var helmChartType = apiType{
kind: sourcev1.HelmChartKind, kind: sourcev1.HelmChartKind,
humanKind: "source chart", humanKind: "source chart",
groupVersion: sourcev1.GroupVersion,
} }
type helmChartAdapter struct { type helmChartAdapter struct {
@@ -95,8 +97,9 @@ func (a helmChartListAdapter) len() int {
// sourcev1.GitRepository // sourcev1.GitRepository
var gitRepositoryType = apiType{ var gitRepositoryType = apiType{
kind: sourcev1.GitRepositoryKind, kind: sourcev1.GitRepositoryKind,
humanKind: "source git", humanKind: "source git",
groupVersion: sourcev1.GroupVersion,
} }
type gitRepositoryAdapter struct { type gitRepositoryAdapter struct {
@@ -128,8 +131,9 @@ func (a gitRepositoryListAdapter) len() int {
// sourcev1.HelmRepository // sourcev1.HelmRepository
var helmRepositoryType = apiType{ var helmRepositoryType = apiType{
kind: sourcev1.HelmRepositoryKind, kind: sourcev1.HelmRepositoryKind,
humanKind: "source helm", humanKind: "source helm",
groupVersion: sourcev1.GroupVersion,
} }
type helmRepositoryAdapter struct { type helmRepositoryAdapter struct {

View File

@@ -20,6 +20,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/fluxcd/pkg/apis/meta"
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@@ -27,8 +28,6 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/cli-utils/pkg/object" "sigs.k8s.io/cli-utils/pkg/object"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta"
) )
// statusable is used to see if a resource is considered ready in the usual way // statusable is used to see if a resource is considered ready in the usual way
@@ -37,10 +36,26 @@ type statusable interface {
// this is implemented by ObjectMeta // this is implemented by ObjectMeta
GetGeneration() int64 GetGeneration() int64
getObservedGeneration() int64 getObservedGeneration() int64
}
// oldConditions represents the deprecated API which is sunsetting.
type oldConditions interface {
// this is usually implemented by GOTK API objects because it's used by pkg/apis/meta // this is usually implemented by GOTK API objects because it's used by pkg/apis/meta
GetStatusConditions() *[]metav1.Condition GetStatusConditions() *[]metav1.Condition
} }
func statusableConditions(object statusable) []metav1.Condition {
if s, ok := object.(meta.ObjectWithConditions); ok {
return s.GetConditions()
}
if s, ok := object.(oldConditions); ok {
return *s.GetStatusConditions()
}
return []metav1.Condition{}
}
func isReady(ctx context.Context, kubeClient client.Client, func isReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, object statusable) wait.ConditionFunc { namespacedName types.NamespacedName, object statusable) wait.ConditionFunc {
return func() (bool, error) { return func() (bool, error) {
@@ -54,7 +69,7 @@ func isReady(ctx context.Context, kubeClient client.Client,
return false, nil return false, nil
} }
if c := apimeta.FindStatusCondition(*object.GetStatusConditions(), meta.ReadyCondition); c != nil { if c := apimeta.FindStatusCondition(statusableConditions(object), meta.ReadyCondition); c != nil {
switch c.Status { switch c.Status {
case metav1.ConditionTrue: case metav1.ConditionTrue:
return true, nil return true, nil

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var suspendSourceBucketCmd = &cobra.Command{ var suspendSourceBucketCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var suspendSourceHelmChartCmd = &cobra.Command{ var suspendSourceHelmChartCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var suspendSourceGitCmd = &cobra.Command{ var suspendSourceGitCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var suspendSourceHelmCmd = &cobra.Command{ var suspendSourceHelmCmd = &cobra.Command{

View File

@@ -143,8 +143,8 @@ metadata:
name: secret-basic-auth-stringdata name: secret-basic-auth-stringdata
namespace: default namespace: default
stringData: stringData:
password: KipTT1BTKio= password: '**SOPS**'
username: KipTT1BTKio= username: '**SOPS**'
type: kubernetes.io/basic-auth type: kubernetes.io/basic-auth
--- ---
apiVersion: v1 apiVersion: v1

View File

@@ -2,5 +2,11 @@
► HorizontalPodAutoscaler/default/podinfo created ► HorizontalPodAutoscaler/default/podinfo created
► Service/default/podinfo created ► Service/default/podinfo created
► Secret/default/docker-secret created ► Secret/default/docker-secret created
► Secret/default/secret-basic-auth-stringdata drifted
data
- one map entry removed: + one map entry added:
username1: "*****" username: "*****"
► Secret/default/podinfo-token-77t89m9b67 created ► Secret/default/podinfo-token-77t89m9b67 created
► Secret/default/db-user-pass-bkbd782d2c created ► Secret/default/db-user-pass-bkbd782d2c created

View File

@@ -8,5 +8,5 @@ metadata:
namespace: default namespace: default
stringData: stringData:
password: KipTT1BTKio= password: KipTT1BTKio=
username: KipTT1BTKio= username1: KipTT1BTKio=
type: kubernetes.io/basic-auth type: kubernetes.io/basic-auth

View File

@@ -1,5 +1,5 @@
--- ---
apiVersion: source.toolkit.fluxcd.io/v1beta1 apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: Bucket kind: Bucket
metadata: metadata:
name: flux-system name: flux-system

View File

@@ -1,5 +1,5 @@
--- ---
apiVersion: source.toolkit.fluxcd.io/v1beta1 apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository kind: GitRepository
metadata: metadata:
name: flux-system name: flux-system

View File

@@ -1,5 +1,5 @@
--- ---
apiVersion: source.toolkit.fluxcd.io/v1beta1 apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository kind: HelmRepository
metadata: metadata:
name: flux-system name: flux-system

View File

@@ -1,2 +1,2 @@
► deleting helmreleases thrfg in {{ .ns }} namespace ► deleting helmrelease thrfg in {{ .ns }} namespace
✔ helmreleases deleted ✔ helmrelease deleted

View File

@@ -1,2 +1,2 @@
NAME READY MESSAGE REVISION SUSPENDED NAME REVISION SUSPENDED READY MESSAGE
thrfg True Release reconciliation succeeded 6.0.0 False thrfg 6.0.0 False True Release reconciliation succeeded

View File

@@ -1,5 +1,5 @@
► resuming helmreleases thrfg in {{ .ns }} namespace ► resuming helmrelease thrfg in {{ .ns }} namespace
✔ helmreleases resumed ✔ helmrelease resumed
◎ waiting for HelmRelease reconciliation ◎ waiting for HelmRelease reconciliation
✔ HelmRelease reconciliation completed ✔ HelmRelease reconciliation completed
✔ applied revision 6.0.0 ✔ applied revision 6.0.0

View File

@@ -1,2 +1,2 @@
► suspending helmreleases thrfg in {{ .ns }} namespace ► suspending helmrelease thrfg in {{ .ns }} namespace
✔ helmreleases suspended ✔ helmrelease suspended

View File

@@ -1,2 +1,2 @@
NAME READY MESSAGE LATEST IMAGE NAME LATEST IMAGE READY MESSAGE
podinfo-regex True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.0 ghcr.io/stefanprodan/podinfo:5.0.0 podinfo-regex ghcr.io/stefanprodan/podinfo:5.0.0 True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.0

View File

@@ -1,2 +1,2 @@
NAME READY MESSAGE LATEST IMAGE NAME LATEST IMAGE READY MESSAGE
podinfo-semver True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.3 ghcr.io/stefanprodan/podinfo:5.0.3 podinfo-semver ghcr.io/stefanprodan/podinfo:5.0.3 True Latest image tag for 'ghcr.io/stefanprodan/podinfo' resolved to: 5.0.3

View File

@@ -1,2 +1,2 @@
► deleting kustomizations tkfg in {{ .ns }} namespace ► deleting kustomization tkfg in {{ .ns }} namespace
✔ kustomizations deleted ✔ kustomization deleted

View File

@@ -1,2 +1,2 @@
NAME READY MESSAGE REVISION SUSPENDED NAME REVISION SUSPENDED READY MESSAGE
tkfg True Applied revision: 6.0.0/627d5c4 6.0.0/627d5c4 False tkfg 6.0.0/627d5c4 False True Applied revision: 6.0.0/627d5c4

View File

@@ -1,5 +1,5 @@
► resuming kustomizations tkfg in {{ .ns }} namespace ► resuming kustomization tkfg in {{ .ns }} namespace
✔ kustomizations resumed ✔ kustomization resumed
◎ waiting for Kustomization reconciliation ◎ waiting for Kustomization reconciliation
✔ Kustomization reconciliation completed ✔ Kustomization reconciliation completed
✔ applied revision 6.0.0/627d5c4bb67b77185f37e31d734b085019ff2951 ✔ applied revision 6.0.0/627d5c4bb67b77185f37e31d734b085019ff2951

View File

@@ -1,2 +1,2 @@
► suspending kustomizations tkfg in {{ .ns }} namespace ► suspending kustomization tkfg in {{ .ns }} namespace
✔ kustomizations suspended ✔ kustomization suspended

View File

@@ -6,7 +6,7 @@ Status: Managed by Flux
HelmRelease: podinfo HelmRelease: podinfo
Namespace: {{ .ns }} Namespace: {{ .ns }}
Revision: 6.0.0 Revision: 6.0.0
Status: Last reconciled at 2021-07-16 15:42:20 +0000 UTC Status: Last reconciled at {{ .helmReleaseLastReconcile }}
Message: Release reconciliation succeeded Message: Release reconciliation succeeded
--- ---
HelmChart: podinfo-podinfo HelmChart: podinfo-podinfo
@@ -14,12 +14,12 @@ Namespace: {{ .fluxns }}
Chart: podinfo Chart: podinfo
Version: 6.0.0 Version: 6.0.0
Revision: 6.0.0 Revision: 6.0.0
Status: Last reconciled at 2021-07-16 15:32:09 +0000 UTC Status: Last reconciled at {{ .helmChartLastReconcile }}
Message: Fetched revision: 6.0.0 Message: Fetched revision: 6.0.0
--- ---
HelmRepository: podinfo HelmRepository: podinfo
Namespace: {{ .fluxns }} Namespace: {{ .fluxns }}
URL: https://stefanprodan.github.io/podinfo URL: https://stefanprodan.github.io/podinfo
Revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56 Revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
Status: Last reconciled at 2021-07-11 00:25:46 +0000 UTC Status: Last reconciled at {{ .helmRepositoryLastReconcile }}
Message: Fetched revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56 Message: Fetched revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56

View File

@@ -7,7 +7,7 @@ Kustomization: infrastructure
Namespace: {{ .fluxns }} Namespace: {{ .fluxns }}
Path: ./infrastructure Path: ./infrastructure
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC Status: Last reconciled at {{ .kustomizationLastReconcile }}
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
--- ---
GitRepository: flux-system GitRepository: flux-system
@@ -15,5 +15,5 @@ Namespace: {{ .fluxns }}
URL: ssh://git@github.com/example/repo URL: ssh://git@github.com/example/repo
Branch: main Branch: main
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
Status: Last reconciled at 2021-07-20 00:48:16 +0000 UTC Status: Last reconciled at {{ .gitRepositoryLastReconcile }}
Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f

View File

@@ -37,7 +37,7 @@ import (
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
fluxmeta "github.com/fluxcd/pkg/apis/meta" fluxmeta "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var traceCmd = &cobra.Command{ var traceCmd = &cobra.Command{

View File

@@ -5,6 +5,7 @@ package main
import ( import (
"testing" "testing"
"time"
) )
func TestTraceNoArgs(t *testing.T) { func TestTraceNoArgs(t *testing.T) {
@@ -15,36 +16,54 @@ func TestTraceNoArgs(t *testing.T) {
cmd.runTestCmd(t) cmd.runTestCmd(t)
} }
func toLocalTime(t *testing.T, in string) string {
ts, err := time.Parse(time.RFC3339, in)
if err != nil {
t.Fatalf("Error converting golden test time '%s': %v", in, err)
}
return ts.Local().String()
}
func TestTrace(t *testing.T) { func TestTrace(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
args string args string
objectFile string objectFile string
goldenFile string goldenFile string
tmpl map[string]string
}{ }{
{ {
"Deployment", "Deployment",
"trace podinfo --kind deployment --api-version=apps/v1", "trace podinfo --kind deployment --api-version=apps/v1",
"testdata/trace/deployment.yaml", "testdata/trace/deployment.yaml",
"testdata/trace/deployment.golden", "testdata/trace/deployment.golden",
map[string]string{
"ns": allocateNamespace("podinfo"),
"fluxns": allocateNamespace("flux-system"),
"helmReleaseLastReconcile": toLocalTime(t, "2021-07-16T15:42:20Z"),
"helmChartLastReconcile": toLocalTime(t, "2021-07-16T15:32:09Z"),
"helmRepositoryLastReconcile": toLocalTime(t, "2021-07-11T00:25:46Z"),
},
}, },
{ {
"HelmRelease", "HelmRelease",
"trace podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1", "trace podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
"testdata/trace/helmrelease.yaml", "testdata/trace/helmrelease.yaml",
"testdata/trace/helmrelease.golden", "testdata/trace/helmrelease.golden",
map[string]string{
"ns": allocateNamespace("podinfo"),
"fluxns": allocateNamespace("flux-system"),
"kustomizationLastReconcile": toLocalTime(t, "2021-08-01T04:52:56Z"),
"gitRepositoryLastReconcile": toLocalTime(t, "2021-07-20T00:48:16Z"),
},
}, },
} }
for _, tc := range cases { for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
tmpl := map[string]string{ testEnv.CreateObjectFile(tc.objectFile, tc.tmpl, t)
"ns": allocateNamespace("podinfo"),
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile(tc.objectFile, tmpl, t)
cmd := cmdTestCase{ cmd := cmdTestCase{
args: tc.args + " -n=" + tmpl["ns"], args: tc.args + " -n=" + tc.tmpl["ns"],
assert: assertGoldenTemplateFile(tc.goldenFile, tmpl), assert: assertGoldenTemplateFile(tc.goldenFile, tc.tmpl),
} }
cmd.runTestCmd(t) cmd.runTestCmd(t)
}) })

View File

@@ -34,7 +34,7 @@ import (
"github.com/fluxcd/flux2/pkg/manifestgen" "github.com/fluxcd/flux2/pkg/manifestgen"
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1" helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var uninstallCmd = &cobra.Command{ var uninstallCmd = &cobra.Command{

83
docs/internal/diagrams.md Normal file
View File

@@ -0,0 +1,83 @@
# Flux Diagrams
## Cluster sync from Git
```mermaid
sequenceDiagram
actor me
participant git as Git<br><br>repository
participant sc as Flux<br><br>source-controller
participant kc as Flux<br><br>kustomize-controller
participant kube as Kubernetes<br><br>api-server
participant nc as Flux<br><br>notification-controller
me->>git: 1. git push
sc->>git: 2. git pull
sc->>sc: 3. build artifact for revision
sc->>kube: 4. update status for revision
sc-->>nc: 5. emit events
kube->>kc: 6. notify about new revision
kc->>sc: 7. fetch artifact for revision
kc->>kc: 8. build manifests to objects
kc-->>kc: 9. decrypt secrets
kc->>kube: 10. validate objects
kc->>kube: 11. apply objects
kc-->>kube: 12. delete objects
kc-->>kube: 13. wait for readiness
kc->>kube: 14. update status for revision
kc-->>nc: 15. emit events
nc-->>me: 16. send alerts for revision
```
## Helm release upgrade from Git
```mermaid
sequenceDiagram
actor me
participant git as Git<br><br>repository
participant sc as Flux<br><br>source-controller
participant hc as Flux<br><br>helm-controller
participant kube as Kubernetes<br><br>api-server
participant nc as Flux<br><br>notification-controller
me->>git: 1. git push
sc->>git: 2. git pull
sc->>sc: 3. build chart for revision
sc->>kube: 4. update chart status
sc-->>nc: 5. emit events
kube->>hc: 6. notify about new revision
hc->>sc: 7. fetch chart
hc->>kube: 8. get values
hc->>hc: 9. render and customize manifests
hc-->>kube: 10. apply CRDs
hc->>kube: 11. upgrade release
hc-->>kube: 12. run tests
hc-->>kube: 13. wait for readiness
hc->>kube: 14. update status
hc-->>nc: 15. emit events
nc-->>me: 16. send alerts
```
## Image update to Git
```mermaid
sequenceDiagram
actor me
participant oci as Image<br><br>repository
participant irc as Flux<br><br>image-reflector-controller
participant iac as Flux<br><br>image-automation-controller
participant kube as Kubernetes<br><br>api-server
participant nc as Flux<br><br>notification-controller
participant git as Git<br><br>repository
me->>oci: 1. docker push
irc->>oci: 2. list tags
irc->>irc: 3. match tags to policies
irc->>kube: 4. update status
irc-->>nc: 5. emit events
kube->>iac: 6. notify about new tags
iac->>git: 7. git clone
iac->>iac: 8. patch manifests with new tags
iac->>git: 9. git push
iac->>kube: 10. update status
iac-->>nc: 11. emit events
nc-->>me: 12. send alerts
```

118
go.mod
View File

@@ -3,55 +3,54 @@ module github.com/fluxcd/flux2
go 1.17 go 1.17
require ( require (
github.com/Masterminds/semver/v3 v3.1.0 github.com/Masterminds/semver/v3 v3.1.1
github.com/ProtonMail/go-crypto v0.0.0-20211221144345-a4f6767435ab github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f
github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin v0.2.3
github.com/fluxcd/go-git-providers v0.5.3 github.com/fluxcd/go-git-providers v0.5.4
github.com/fluxcd/helm-controller/api v0.16.0 github.com/fluxcd/helm-controller/api v0.18.1
github.com/fluxcd/image-automation-controller/api v0.20.0 github.com/fluxcd/image-automation-controller/api v0.21.1
github.com/fluxcd/image-reflector-controller/api v0.16.0 github.com/fluxcd/image-reflector-controller/api v0.17.1
github.com/fluxcd/kustomize-controller/api v0.20.2 github.com/fluxcd/kustomize-controller/api v0.22.0
github.com/fluxcd/notification-controller/api v0.21.0 github.com/fluxcd/notification-controller/api v0.23.1
github.com/fluxcd/pkg/apis/kustomize v0.3.1 // indirect github.com/fluxcd/pkg/apis/meta v0.12.1
github.com/fluxcd/pkg/apis/meta v0.10.2 github.com/fluxcd/pkg/kustomize v0.0.3
github.com/fluxcd/pkg/kustomize v0.0.2 github.com/fluxcd/pkg/runtime v0.13.2
github.com/fluxcd/pkg/runtime v0.12.4 github.com/fluxcd/pkg/ssa v0.15.1
github.com/fluxcd/pkg/ssa v0.13.0 github.com/fluxcd/pkg/ssh v0.3.2
github.com/fluxcd/pkg/ssh v0.3.1 github.com/fluxcd/pkg/untar v0.1.0
github.com/fluxcd/pkg/untar v0.0.5 github.com/fluxcd/pkg/version v0.1.0
github.com/fluxcd/pkg/version v0.0.1 github.com/fluxcd/source-controller/api v0.22.2
github.com/fluxcd/source-controller/api v0.21.2
github.com/go-git/go-git/v5 v5.4.2 github.com/go-git/go-git/v5 v5.4.2
github.com/gonvenience/bunt v1.3.2 github.com/gonvenience/bunt v1.3.3
github.com/gonvenience/ytbx v1.4.2 github.com/gonvenience/ytbx v1.4.4
github.com/google/go-cmp v0.5.6 github.com/google/go-cmp v0.5.7
github.com/google/go-containerregistry v0.2.0 github.com/google/go-containerregistry v0.8.0
github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/homeport/dyff v1.5.1
github.com/homeport/dyff v1.4.6
github.com/lucasb-eyer/go-colorful v1.2.0 github.com/lucasb-eyer/go-colorful v1.2.0
github.com/manifoldco/promptui v0.9.0 github.com/manifoldco/promptui v0.9.0
github.com/mattn/go-shellwords v1.0.12 github.com/mattn/go-shellwords v1.0.12
github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter v0.0.5
github.com/spf13/cobra v1.2.1 github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 github.com/theckman/yacspin v0.13.12
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
k8s.io/api v0.23.1 k8s.io/api v0.23.4
k8s.io/apiextensions-apiserver v0.23.1 k8s.io/apiextensions-apiserver v0.23.4
k8s.io/apimachinery v0.23.1 k8s.io/apimachinery v0.23.4
k8s.io/cli-runtime v0.23.1 k8s.io/cli-runtime v0.23.4
k8s.io/client-go v0.23.1 k8s.io/client-go v0.23.4
k8s.io/kubectl v0.23.1 k8s.io/kubectl v0.23.4
sigs.k8s.io/cli-utils v0.27.0 sigs.k8s.io/cli-utils v0.29.3
sigs.k8s.io/controller-runtime v0.11.0 sigs.k8s.io/controller-runtime v0.11.1
sigs.k8s.io/kustomize/api v0.11.2 sigs.k8s.io/kustomize/api v0.11.2
sigs.k8s.io/kustomize/kyaml v0.13.3 sigs.k8s.io/kustomize/kyaml v0.13.3
sigs.k8s.io/yaml v1.3.0 sigs.k8s.io/yaml v1.3.0
) )
require ( require (
cloud.google.com/go v0.81.0 // indirect cloud.google.com/go v0.99.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.18 // indirect github.com/Azure/go-autorest/autorest v0.11.18 // indirect
@@ -59,21 +58,23 @@ require (
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/BurntSushi/toml v0.4.1 // indirect github.com/BurntSushi/toml v1.0.0 // indirect
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 // indirect github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 // indirect
github.com/emirpasic/gods v1.12.0 // indirect github.com/emirpasic/gods v1.12.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect
github.com/fluxcd/pkg/apis/kustomize v0.3.2 // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/fvbommel/sortorder v1.0.1 // indirect github.com/fvbommel/sortorder v1.0.1 // indirect
github.com/go-errors/errors v1.0.1 // indirect github.com/go-errors/errors v1.0.1 // indirect
@@ -85,10 +86,10 @@ require (
github.com/go-openapi/swag v0.19.14 // indirect github.com/go-openapi/swag v0.19.14 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/gonvenience/neat v1.3.7 // indirect github.com/gonvenience/neat v1.3.9 // indirect
github.com/gonvenience/term v1.0.1 // indirect github.com/gonvenience/term v1.0.2 // indirect
github.com/gonvenience/text v1.0.6 // indirect github.com/gonvenience/text v1.0.7 // indirect
github.com/gonvenience/wrap v1.1.0 // indirect github.com/gonvenience/wrap v1.1.1 // indirect
github.com/google/btree v1.0.1 // indirect github.com/google/btree v1.0.1 // indirect
github.com/google/go-github/v41 v41.0.0 // indirect github.com/google/go-github/v41 v41.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
@@ -98,7 +99,8 @@ require (
github.com/googleapis/gnostic v0.5.5 // indirect github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
@@ -108,8 +110,9 @@ require (
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.6 // indirect github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 // indirect github.com/mattn/go-ciede2000 v0.0.0-20170301095244-782e8c62fec3 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.7 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect
@@ -119,24 +122,25 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/onsi/gomega v1.18.1 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday v1.5.2 // indirect github.com/russross/blackfriday v1.5.2 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/stretchr/testify v1.7.1 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/texttheater/golang-levenshtein v1.0.1 // indirect github.com/texttheater/golang-levenshtein v1.0.1 // indirect
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 // indirect github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 // indirect
github.com/xanzy/go-gitlab v0.54.3 // indirect github.com/xanzy/go-gitlab v0.54.3 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
@@ -145,14 +149,10 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/component-base v0.23.1 // indirect k8s.io/component-base v0.23.4 // indirect
k8s.io/klog/v2 v2.30.0 // indirect k8s.io/klog/v2 v2.50.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
) )
// Fix for CVE-2020-29652: https://github.com/golang/crypto/commit/8b5274cf687fd9316b4108863654cc57385531e8
// Fix for CVE-2021-43565: https://github.com/golang/crypto/commit/5770296d904e90f15f38f77dfc2e43fdf5efc083
replace golang.org/x/crypto => golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3

930
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,7 @@ import (
"strings" "strings"
"time" "time"
gogit "github.com/go-git/go-git/v5"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
@@ -287,10 +288,28 @@ func (b *PlainGitBootstrapper) ReconcileSyncConfig(ctx context.Context, options
if err != nil && err != git.ErrNoStagedFiles { if err != nil && err != git.ErrNoStagedFiles {
return fmt.Errorf("failed to commit sync manifests: %w", err) return fmt.Errorf("failed to commit sync manifests: %w", err)
} }
if err == nil { if err == nil {
b.logger.Successf("committed sync manifests to %q (%q)", b.branch, commit) b.logger.Successf("committed sync manifests to %q (%q)", b.branch, commit)
b.logger.Actionf("pushing sync manifests to %q", b.url) b.logger.Actionf("pushing sync manifests to %q", b.url)
if err = b.git.Push(ctx, b.caBundle); err != nil { err = b.git.Push(ctx, b.caBundle)
if err != nil {
if strings.HasPrefix(err.Error(), gogit.ErrNonFastForwardUpdate.Error()) {
b.logger.Waitingf("git conflict detected, retrying with a fresh clone")
if err := os.RemoveAll(b.git.Path()); err != nil {
return fmt.Errorf("failed to remove tmp dir: %w", err)
}
if err := os.Mkdir(b.git.Path(), 0o700); err != nil {
return fmt.Errorf("failed to recreate tmp dir: %w", err)
}
if err = retry(1, 2*time.Second, func() (err error) {
_, err = b.git.Clone(ctx, b.url, b.branch, b.caBundle)
return
}); err != nil {
return fmt.Errorf("failed to clone repository: %w", err)
}
return b.ReconcileSyncConfig(ctx, options)
}
return fmt.Errorf("failed to push sync manifests: %w", err) return fmt.Errorf("failed to push sync manifests: %w", err)
} }
} else { } else {

View File

@@ -28,6 +28,7 @@ import (
"github.com/fluxcd/flux2/internal/utils" "github.com/fluxcd/flux2/internal/utils"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
"github.com/fluxcd/pkg/kustomize" "github.com/fluxcd/pkg/kustomize"
"github.com/theckman/yacspin"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@@ -66,6 +67,7 @@ type Builder struct {
action kustomize.Action action kustomize.Action
kustomization *kustomizev1.Kustomization kustomization *kustomizev1.Kustomization
timeout time.Duration timeout time.Duration
spinner *yacspin.Spinner
} }
type BuilderOptionFunc func(b *Builder) error type BuilderOptionFunc func(b *Builder) error
@@ -77,6 +79,28 @@ func WithTimeout(timeout time.Duration) BuilderOptionFunc {
} }
} }
func WithProgressBar() BuilderOptionFunc {
return func(b *Builder) error {
// Add a spiner
cfg := yacspin.Config{
Frequency: 100 * time.Millisecond,
CharSet: yacspin.CharSets[59],
Suffix: "Kustomization diffing...",
SuffixAutoColon: true,
Message: "running dry-run",
StopCharacter: "✓",
StopColors: []string{"fgGreen"},
}
spinner, err := yacspin.New(cfg)
if err != nil {
return fmt.Errorf("failed to create spinner: %w", err)
}
b.spinner = spinner
return nil
}
}
// NewBuilder returns a new Builder // NewBuilder returns a new Builder
// to dp : create functional options // to dp : create functional options
func NewBuilder(rcg *genericclioptions.ConfigFlags, name, resources string, opts ...BuilderOptionFunc) (*Builder, error) { func NewBuilder(rcg *genericclioptions.ConfigFlags, name, resources string, opts ...BuilderOptionFunc) (*Builder, error) {
@@ -288,12 +312,12 @@ func maskSopsData(res *resource.Resource) error {
if v, ok := secretType.(string); ok && v == dockercfgSecretType { if v, ok := secretType.(string); ok && v == dockercfgSecretType {
// if the secret is a json docker config secret, we need to mask the data with a json object // if the secret is a json docker config secret, we need to mask the data with a json object
err := maskDockerconfigjsonSopsData(dataMap) err := maskDockerconfigjsonSopsData(dataMap, true)
if err != nil { if err != nil {
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err) return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
} }
err = maskDockerconfigjsonSopsData(stringDataMap) err = maskDockerconfigjsonSopsData(stringDataMap, false)
if err != nil { if err != nil {
return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err) return fmt.Errorf("failed to mask secret %s sops data: %w", res.GetName(), err)
} }
@@ -304,7 +328,7 @@ func maskSopsData(res *resource.Resource) error {
} }
for k := range stringDataMap { for k := range stringDataMap {
stringDataMap[k] = sopsMess stringDataMap[k] = mask
} }
} }
} else { } else {
@@ -346,7 +370,7 @@ func getStringDataMap(rn *resource.Resource) map[string]string {
return result return result
} }
func maskDockerconfigjsonSopsData(dataMap map[string]string) error { func maskDockerconfigjsonSopsData(dataMap map[string]string, encode bool) error {
sopsMess := struct { sopsMess := struct {
Mask string `json:"mask"` Mask string `json:"mask"`
}{ }{
@@ -358,8 +382,15 @@ func maskDockerconfigjsonSopsData(dataMap map[string]string) error {
return err return err
} }
if encode {
for k := range dataMap {
dataMap[k] = base64.StdEncoding.EncodeToString(maskJson)
}
return nil
}
for k := range dataMap { for k := range dataMap {
dataMap[k] = base64.StdEncoding.EncodeToString(maskJson) dataMap[k] = string(maskJson)
} }
return nil return nil

Some files were not shown because too many files have changed in this diff Show More