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

Compare commits

...

140 Commits

Author SHA1 Message Date
fluxcdbot
1ad9255b09 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 21:21:03 +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
Stefan Prodan
de5f00016b Merge pull request #2418 from fluxcd/fix-bootstrap
Fix bootstrap: Reset schema cache after applying CRDs
2022-02-10 18:44:53 +02:00
Stefan Prodan
877729aca3 Fix bootstrap: Reset schema cache after applying CRDs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-10 18:09:06 +02:00
Stefan Prodan
f65d87b191 Merge pull request #2416 from fluxcd/update-components
Update kustomize-controller to v0.20.2
2022-02-10 16:55:01 +02:00
fluxcdbot
3b1d706b05 Update toolkit components
- kustomize-controller to v0.20.2
  https://github.com/fluxcd/kustomize-controller/blob/v0.20.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-02-10 10:45:36 +00:00
Stefan Prodan
b0552fa0de Merge pull request #2415 from fluxcd/iac-namespace-arg
Add GitRepository namespace arg to `flux create image update`
2022-02-10 12:44:58 +02:00
Stefan Prodan
cbca583f4b Add GitRepository namespace arg to flux create image update
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-10 10:52:51 +02:00
Stefan Prodan
a0520de7aa Merge pull request #2397 from fluxcd/ssa-v0.13.0
Fix bootstrap CRD wait race condition
2022-02-07 14:59:05 +02:00
Stefan Prodan
4602b72778 Fix bootstrap CRD wait race condition
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-07 14:28:56 +02:00
Stefan Prodan
e69a6ed91a Merge pull request #2398 from fluxcd/update-components
Update toolkit components
2022-02-07 14:28:20 +02:00
Stefan Prodan
9d6a037935 Update dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-07 14:09:23 +02:00
fluxcdbot
41df03f600 Update toolkit components
- kustomize-controller to v0.20.1
  https://github.com/fluxcd/kustomize-controller/blob/v0.20.1/CHANGELOG.md
- source-controller to v0.21.2
  https://github.com/fluxcd/source-controller/blob/v0.21.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-02-07 11:45:14 +00:00
Stefan Prodan
ca92464ef6 Merge pull request #2392 from souleb/issue-2387
Mask dockerconfigjson secret types and support StringData secrets
2022-02-07 11:18:11 +02:00
Soule BA
2e9fd33ce5 Mask dockerconfigjson secret types and support StringData secrets
If implemented, flux diff kustomization will managed correctly sops
managed dockerconfigjson secrets.
Sops encrypted secret with stringData maps are supported too.

Signed-off-by: Soule BA <soule@weave.works>
2022-02-07 09:45:38 +01:00
Stefan Prodan
cf3f729f98 Merge pull request #2389 from souleb/fix-deleted-mess-diff
Fix wrong deletion message on flux diff
2022-02-07 10:09:51 +02:00
Soule BA
8b444283e6 Fix wrong deletion message on flux diff
If implemented, when an error happens when dry-running an object, we
return early. This match pkg ssa implementation

Signed-off-by: Soule BA <soule@weave.works>
2022-02-07 00:06:33 +01:00
Stefan Prodan
4b4e6b1be3 Merge pull request #2382 from SomtochiAma/commit-sha
Use `client.Patch` for suspend/resume operations
2022-02-04 13:39:52 +02:00
Somtochi Onyekwere
d3d271defe use client.Patch for suspend/resume operations
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-02-04 12:06:39 +01:00
Stefan Prodan
9bddabf4ff Merge pull request #2380 from souleb/fix-panic-orgref-var
Fix panic on bootstrap when orgRef is not retrieved
2022-02-04 10:29:26 +02:00
Soule BA
959ea6875a Fix panic on bootstrap when orgRef is not retrieved
If implemented, not retrieving an orgRef will always return an error

Signed-off-by: Soule BA <soule@weave.works>
2022-02-04 09:08:38 +01:00
Stefan Prodan
7b7eb011b0 Merge pull request #2377 from souleb/issue-2363
Fix `flux build/diff` when parsing SOPS encrypted secrets
2022-02-04 10:06:14 +02:00
Soule BA
997e6be3a2 Make sure to trim all sops data
If implemented this fixes #2363 and make sure we can build with sops
encrypted data

Signed-off-by: Soule BA <soule@weave.works>
2022-02-04 08:38:29 +01:00
Stefan Prodan
51af4bbf52 Merge pull request #2364 from robwittman/rwittman/add-github-gpg-signing
Add GPG signing to Github/Gitlab/Bitbucket bootstrap
2022-02-04 09:26:50 +02:00
Robert Wittman
e33198e750 Replace github boostrap GPG options
Signed-off-by: Robert Wittman <robkwittman@gmail.com>
2022-02-03 11:09:10 -05:00
Robert Wittman
e3f5a8fee3 Add GPG options to Gitlab and BitBucket bootstraps
Signed-off-by: Robert Wittman <robkwittman@gmail.com>
2022-02-03 11:07:55 -05:00
Robert Wittman
f8b58f8be9 Add GPG signing to Github bootstrap
Signed-off-by: Robert Wittman <robkwittman@gmail.com>
2022-02-03 11:03:35 -05:00
Stefan Prodan
55542a8086 Merge pull request #2376 from fluxcd/fix-azure-test
e2e: Fix Azure image update automation test
2022-02-03 17:04:01 +02:00
Stefan Prodan
70c8c0445c e2e: Fix Azure image update automation test
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-03 16:38:25 +02:00
Stefan Prodan
29c0bb4ce2 Merge pull request #2375 from souleb/issue-2365
Add contextual error code for flux diff kustomization
2022-02-03 16:35:45 +02:00
Soule BA
b86b195450 Add contextual error code for flux diff kustomization
If implemented, calling the diff command on kustomization will return 0,
1(if changes are identified), >1 for errors.

Signed-off-by: Soule BA <soule@weave.works>
2022-02-03 13:41:57 +01:00
Hidde Beydals
edf15894f8 Merge pull request #2368 from fluxcd/update-e2e-pkgs 2022-02-02 11:41:07 +01:00
Stefan Prodan
74878a9aef Update dependencies
Use Azure e2e dependencies and bump fluxcd/pkg/ssa to v0.12.0

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-02 11:50:39 +02:00
Stefan Prodan
82824b4fc6 Merge pull request #2345 from fluxcd/update-components
Update toolkit components
2022-02-01 12:39:35 +02:00
Stefan Prodan
141d71c39d Use CrossNamespaceSourceReference for image automations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-02-01 12:12:59 +02:00
fluxcdbot
e9d6f271b5 Update toolkit components
- helm-controller to v0.16.0
  https://github.com/fluxcd/helm-controller/blob/v0.16.0/CHANGELOG.md
- kustomize-controller to v0.20.0
  https://github.com/fluxcd/kustomize-controller/blob/v0.20.0/CHANGELOG.md
- source-controller to v0.21.1
  https://github.com/fluxcd/source-controller/blob/v0.21.1/CHANGELOG.md
- notification-controller to v0.21.0
  https://github.com/fluxcd/notification-controller/blob/v0.21.0/CHANGELOG.md
- image-reflector-controller to v0.16.0
  https://github.com/fluxcd/image-reflector-controller/blob/v0.16.0/CHANGELOG.md
- image-automation-controller to v0.20.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.20.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-02-01 09:48:15 +00:00
Stefan Prodan
8d4dee2aee Merge pull request #2356 from fluxcd/fix-diff-test-kubernetes-1.23.3
Adapt diff test to match Kubernetes 1.23.3 API response
2022-01-31 11:36:07 +02:00
Stefan Prodan
246af92386 Adapt diff test to match Kubernetes 1.23.3 API response
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-28 20:37:16 +02:00
Stefan Prodan
7c9957a18f Merge pull request #2348 from pjbgf/add-pkg-config
Add pkg-config to arm runners
2022-01-27 15:48:48 +02:00
Paulo Gomes
9e7018383a Add pkg-config to arm runners
Signed-off-by: Paulo Gomes <paulo.gomes@weave.works>
2022-01-27 13:28:46 +00:00
Stefan Prodan
920d6e5404 Merge pull request #2347 from stealthybox/fix-2346-usage-output
Fix output usage for `flux get <sources|images>`
2022-01-27 09:58:56 +02:00
leigh capili
57962347f2 Output Usage for flux get <sources|images>
Signed-off-by: leigh capili <leigh@null.net>
2022-01-26 16:03:22 -07:00
Stefan Prodan
6f053c45df Merge pull request #2343 from fluxcd/check-kubernetes-1.20.6
Set minimum supported version to Kubernetes 1.20.6
2022-01-26 12:22:13 +02:00
Stefan Prodan
f154326391 Set minimum supported version to Kubernetes 1.20.6
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-26 11:21:32 +02:00
Stefan Prodan
776a7fc9c0 Merge pull request #2342 from fluxcd/flux-cli-non-root
Run the CLI as non-root
2022-01-26 10:39:10 +02:00
Stefan Prodan
08412b72bc Run the CLI as non-root
Run the Flux CLI inside the container under the nobody user and group.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-26 09:51:50 +02:00
Stefan Prodan
030e166f43 Merge pull request #2336 from souleb/upgrade-go-git-provider
Upgrade go-git-providers to v0.5.3
2022-01-25 12:14:50 +02:00
Soule BA
d92dfc56b8 Upgrade go-git-providers to v0.5.3
Fixes bug reported on #2332

Signed-off-by: Soule BA <soule@weave.works>
2022-01-25 10:28:14 +01:00
Stefan Prodan
365d2d102d Merge pull request #2316 from pjbgf/warn-pod-security
[security] Enable pod security warnings for flux-system
2022-01-21 13:53:11 +02:00
Paulo Gomes
f7853c4ddf Enable pod security warnings for flux-system
Signed-off-by: Paulo Gomes <paulo.gomes@weave.works>
2022-01-21 11:23:56 +00:00
Hidde Beydals
0a6d5d9267 Merge pull request #2317 from souleb/update-diff-license-header 2022-01-20 17:42:51 +01:00
Soule BA
10b761e4e7 Add license Header to internal/build files
This adds an up to date license header to the files.

Signed-off-by: Soule BA <soule@weave.works>
2022-01-20 16:58:12 +01:00
Stefan Prodan
c6f2b410bc Merge pull request #2167 from souleb/flux-build-kustomization
Preview local changes with flux build/diff kustomization
2022-01-20 14:50:02 +02:00
Soule BA
306f8f5715 Add graceful shutdown when interrupted
If implemented this permit restoring a clean state in case of signal
interruption.

Signed-off-by: Soule BA <soule@weave.works>
2022-01-20 13:21:07 +01:00
Soule BA
f7d9ee90cd Add e2e tests for build/diff kustomization
Signed-off-by: Soule BA <soule@weave.works>
2022-01-20 11:51:57 +01:00
Soule BA
9376c9a946 Add a diff kustomization feature
If implemented it will permit queriying the Kubernetes API to fetch the specified
Flux Kustomization, then uses the specified path to build the overlay.
It will then ssa-dry-run apply and output the diff using homeport/dyff

Signed-off-by: Soule BA <soule@weave.works>
2022-01-20 11:51:56 +01:00
Soule BA
70fb87bc93 Add a build kustomization feature
If implemented it will permit queriying the Kubernetes API to fetch the specified
Flux Kustomization, then uses the specified path to build
the overlay.

Signed-off-by: Soule BA <soule@weave.works>
2022-01-20 11:51:56 +01:00
Stefan Prodan
63e54f3575 Merge pull request #2297 from SomtochiAma/commit-sha
Shorten Git SHA commit in `flux get` commands output
2022-01-20 12:36:18 +02:00
Somtochi Onyekwere
1e2a497108 Shorten sha commit
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
2022-01-20 11:13:25 +01:00
Stefan Prodan
5d95a6e750 Merge pull request #2305 from fluxcd/kubectl-1.23.1
Update kubectl to 1.23.1 in flux-cli container image
2022-01-18 19:01:09 +02:00
Stefan Prodan
af00610a61 Update kubectl to 1.23.1 in flux-cli container image
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-18 18:34:16 +02:00
Stefan Prodan
809cb79828 Merge pull request #2304 from fluxcd/fix-release-notes-gen
ci: Fix release notes generator
2022-01-18 18:33:23 +02:00
Stefan Prodan
e44a58cba0 ci: Fix release notes generator
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-18 18:13:59 +02:00
Stefan Prodan
10046187a6 Merge pull request #2301 from fluxcd/cosign
Sign the release artifacts checksums and images
2022-01-18 14:56:47 +02:00
Stefan Prodan
a402461f9c Sign the release artifacts checksums and images
- add the Flux manifests and API schemas to checksums
- sign the checksum.txt with Cosign and GitHub OIDC
- sign the flux-cli container images with Cosign and GitHub OIDC

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-18 14:31:37 +02:00
Stefan Prodan
8a6771c9a9 Merge pull request #2300 from fluxcd/ci-fixes
Fix Azure e2e tests and GoReleaser buildx directive
2022-01-17 11:03:05 +02:00
Stefan Prodan
7173bd5945 Fix GoReleaser buildx directive
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-17 10:37:31 +02:00
Stefan Prodan
8e09ade41c Fix Azure e2e tests
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-17 10:36:03 +02:00
Stefan Prodan
6ceb8d8338 Merge pull request #2295 from fluxcd/sbom-spdx
Publish Flux Software Bill of Materials (SBOM)
2022-01-17 10:33:02 +02:00
Stefan Prodan
11296cd94f Publish Flux Software Bill of Materials (SBOM) in SPDX format
- generate SBOM for Flux Go modules with Syft
- publish the SBOM SPDX JSON files to GitHub releases with GoReleaser

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-14 16:36:49 +02:00
Aurel Canciu
677dca0bc4 Merge pull request #2296 from fluxcd/fix-pkgbuild-envtest
Fix Archlinux PKGBUILD check() run on ARM
2022-01-14 13:55:26 +01:00
Aurel Canciu
8e7b957164 Fix Archlinux PKGBUILD check() run on ARM
The check() run started to fail after #2288 since ENVTEST_ARCH was not
set correctly on ARM/ARM64. This should fix the problem for the flux-go
and flux-scm AUR packages.

Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2022-01-14 13:20:19 +01:00
Stefan Prodan
8f93e2a9d4 Merge pull request #2294 from fluxcd/ci-del-repo
Improve the bootstrap e2e test workflow
2022-01-14 11:48:22 +02:00
Stefan Prodan
62755b4b75 Wait 60s for image automation before failing the test
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-14 10:30:36 +02:00
Stefan Prodan
dcfb745b1f Improve the bootstrap e2e cleanup
Delete the repository regardless of the bootstrap test exit code.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-13 20:44:02 +02:00
Stefan Prodan
f38b83231c Merge pull request #2291 from fluxcd/update-components
Update kustomize-controller to v0.19.1
2022-01-13 20:33:47 +02:00
fluxcdbot
269f5e2575 Update toolkit components
- kustomize-controller to v0.19.1
  https://github.com/fluxcd/kustomize-controller/blob/v0.19.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-01-13 18:17:27 +00:00
Stefan Prodan
893596383a Merge pull request #2290 from fluxcd/ssa-v0.10.0
Update dependencies
2022-01-13 19:56:47 +02:00
Stefan Prodan
8c67708829 Update dependencies
- sigs.k8s.io/cli-utils v0.27.0
- github.com/fluxcd/pkg/ssa v0.10.0

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-13 19:37:14 +02:00
Stefan Prodan
c1528503b6 Merge pull request #2141 from schrej/feature/trace-simpler-arguments
Simplify arguments of flux trace command
2022-01-13 19:36:56 +02:00
Jakob Schrettenbrunner
d3c56eb3d3 trace: fix lint warning
Signed-off-by: Jakob Schrettenbrunner <jakob.schrettenbrunner@telekom.de>
2022-01-13 15:52:47 +01:00
Jakob Schrettenbrunner
b10eee87ee Simplify arguments of flux trace command
It now accepts arguments in the forms <resource>/<name>
and <resource> <name> instead of requiring api version and
kind as flags.

Signed-off-by: Jakob Schrettenbrunner <jakob.schrettenbrunner@telekom.de>
2022-01-13 15:52:47 +01:00
Hidde Beydals
83de469967 Merge pull request #2267 from tomalexander/add_git_build_dep 2022-01-13 15:22:23 +01:00
Tom Alexander
192978125f build/aur: fix the make target for the manifests
Signed-off-by: Tom Alexander <tom@fizz.buzz>
2022-01-13 14:58:46 +01:00
Tom Alexander
b4b3551e39 build/aur: add Git as flux-scm build dependency
Without git installed, makepkg fails to fetch the source. This breaks
the build for people who build their aur packages inside temporary
containers (for example aurutils with the -c flag).

Signed-off-by: Tom Alexander <tom@fizz.buzz>
2022-01-13 14:58:33 +01:00
Stefan Prodan
7f580e89d0 Merge pull request #2288 from aryan9600/aryan9600/setup-testenv
Fix makefile envtest setup and usage
2022-01-13 13:10:17 +02:00
Sanskar Jaiswal
81a087095a fix makefile envtest setup and usage
Refactor logic to install helper tools into one function in the
Makefile. Add support for envtest to help install tools like kubectl,
etcd which helps users run tests more conveniently.

Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
2022-01-13 16:09:11 +05:30
Hidde Beydals
bcabde3bdb Merge pull request #2231 from achetronic/fix-bootstrap-https-port-overwrite 2022-01-13 11:02:22 +01:00
Alby Hernández
c190d80d4a Avoid overwriting the host port on http requests
Remove the overwrite of the repositoryURL.Host variable to include Git
servers deployed on non-standard https ports

Co-authored-by: Sebastián Vargas <develolux@gmail.com>

Signed-off-by: Alby Hernández <me@achetronic.com>
Signed-off-by: Alby Hernández <alby.hernandez@system73.com>
2022-01-13 10:32:10 +01:00
Stefan Prodan
11081e8cb2 Merge pull request #2285 from souleb/issue-2284
Update go-git-provider to fix GitLab bootstrap regression bug
2022-01-12 18:19:23 +02:00
Soule BA
c5890f08ef reverting go-git-provider to fix #2284
Signed-off-by: Soule BA <soule@weave.works>
2022-01-12 16:51:35 +01:00
Stefan Prodan
926d8a1c37 Merge pull request #2234 from souleb/issue-2207
Use provided SSH hostname to sync with SSH
2022-01-12 13:18:52 +02:00
Soule BA
da6dfd5a1b Use provided ssh hostname to sync with ssh
Signed-off-by: Soule BA <soule@weave.works>
2022-01-12 11:52:17 +01:00
Stefan Prodan
4318152141 Merge pull request #2281 from Skarlso/add_bindir_to_action
Add optional bindir input to Flux GitHub Action
2022-01-12 12:03:04 +02:00
Gergely Brautigam
759145704f Update the action to include an optional bindir
Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
2022-01-12 10:38:19 +01:00
Stefan Prodan
5cab8f4b11 Merge pull request #2280 from fluxcd/go-git-providers-v0.5.1
Update Git providers
2022-01-12 11:11:36 +02:00
Stefan Prodan
a0ce4b23d2 Update Git providers
- go-git-providers v0.5.1
- go-github v41.0.0
- go-gitlab v0.54.3

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-12 10:34:58 +02:00
Hidde Beydals
6d88a0c3ac Merge pull request #2278 from fluxcd/update-components 2022-01-11 18:22:19 +01:00
fluxcdbot
db44bcd88e Update toolkit components
- notification-controller to v0.20.1
  https://github.com/fluxcd/notification-controller/blob/v0.20.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-01-11 14:36:35 +00:00
Hidde Beydals
585ae5090d Merge pull request #2272 from fluxcd/x-crypto-patch 2022-01-10 19:32:32 +01:00
Hidde Beydals
fe46793c40 Update golang.org/x/crypto to latest main
This includes the full commit tree to solve both CVE-2020-29652 and
CVE-2021-43565:
8b5274cf68...5770296d90

Signed-off-by: Hidde Beydals <hello@hidde.co>
2022-01-10 19:02:47 +01:00
Stefan Prodan
be146b1cc9 Merge pull request #2271 from fluxcd/update-components-pkg
Update toolkit components and packages
2022-01-10 19:16:21 +02:00
Aurel Canciu
e46c7bd519 Update golang.org/x/crypto to fix CVE-2020-29652
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2022-01-10 17:47:23 +01:00
Aurel Canciu
f3d143e5ee Update Go to v1.17
Signed-off-by: Aurel Canciu <aurelcanciu@gmail.com>
2022-01-10 16:30:38 +01:00
Stefan Prodan
fc059df8ff Update controller-runtime dependencies
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2022-01-10 16:54:53 +02:00
fluxcdbot
6c047d1e2a Update toolkit components
- helm-controller to v0.15.0
  https://github.com/fluxcd/helm-controller/blob/v0.15.0/CHANGELOG.md
- kustomize-controller to v0.19.0
  https://github.com/fluxcd/kustomize-controller/blob/v0.19.0/CHANGELOG.md
- source-controller to v0.20.1
  https://github.com/fluxcd/source-controller/blob/v0.20.1/CHANGELOG.md
- image-reflector-controller to v0.15.0
  https://github.com/fluxcd/image-reflector-controller/blob/v0.15.0/CHANGELOG.md
- image-automation-controller to v0.19.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.19.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2022-01-10 14:35:39 +00:00
Stefan Prodan
f6afe7f0ec Merge pull request #2144 from schrej/feature/cli-runtime
Use k8s.io/cli-runtime for kubernetes flags
2022-01-10 11:39:15 +02:00
Jakob Schrettenbrunner
ca7d2e783f Use k8s.io/cli-runtime for kubernetes flags
Signed-off-by: Jakob Schrettenbrunner <jakob.schrettenbrunner@telekom.de>
2022-01-07 16:01:24 +01:00
Max Jonas Werner
0b133ca9f2 Merge pull request #2212 from fluxcd/rfc-0001-extra
[RFC-0001] Memorandum on the authorization model
2021-12-21 13:01:56 +01:00
Michael Bridgen
ede6785e6b RFC on authorisation model
This gives a baseline for future changes, e.g., expanding where
namespace ACLs are used, switching access control to
untrusted-by-default.

The "Security considerations" section  was adapted from

    https://github.com/fluxcd/flux2/pull/2086

Signed-off-by: Michael Bridgen <michael@weave.works>
2021-12-17 19:17:25 +00:00
Stefan Prodan
6d9f39d8ea Merge pull request #2223 from fluxcd/arm64-helm
Add the Helm CLI to the GitHub ARM64 runners setup
2021-12-17 13:16:02 +02:00
Stefan Prodan
fb637ea955 Add the Helm CLI to the GitHub ARM64 runners setup
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2021-12-17 12:33:27 +02:00
173 changed files with 4525 additions and 1068 deletions

View File

@@ -12,7 +12,7 @@ provides=("flux-bin")
conflicts=("flux-bin") conflicts=("flux-bin")
replaces=("flux-cli") replaces=("flux-cli")
depends=("glibc") depends=("glibc")
makedepends=('go>=1.16', 'kustomize>=3.0') makedepends=('go>=1.17', 'kustomize>=3.0')
optdepends=('bash-completion: auto-completion for flux in Bash', optdepends=('bash-completion: auto-completion for flux in Bash',
'zsh-completions: auto-completion for flux in ZSH') 'zsh-completions: auto-completion for flux in ZSH')
source=( source=(
@@ -30,12 +30,20 @@ build() {
export CGO_CXXFLAGS="$CXXFLAGS" export CGO_CXXFLAGS="$CXXFLAGS"
export CGO_CPPFLAGS="$CPPFLAGS" export CGO_CPPFLAGS="$CPPFLAGS"
export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw" export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw"
./manifests/scripts/bundle.sh "${PWD}/manifests" "${PWD}/cmd/flux/manifests" make cmd/flux/.manifests.done
go build -ldflags "-linkmode=external -X main.VERSION=${pkgver}" -o ${_srcname} ./cmd/flux go build -ldflags "-linkmode=external -X main.VERSION=${pkgver}" -o ${_srcname} ./cmd/flux
} }
check() { check() {
cd "flux2-${pkgver}" cd "flux2-${pkgver}"
case $CARCH in
aarch64)
export ENVTEST_ARCH=arm64
;;
armv6h|armv7h)
export ENVTEST_ARCH=arm
;;
esac
make test make test
} }

View File

@@ -11,7 +11,7 @@ license=("APACHE")
provides=("flux-bin") provides=("flux-bin")
conflicts=("flux-bin") conflicts=("flux-bin")
depends=("glibc") depends=("glibc")
makedepends=('go>=1.16', 'kustomize>=3.0') makedepends=('go>=1.17', 'kustomize>=3.0', 'git')
optdepends=('bash-completion: auto-completion for flux in Bash', optdepends=('bash-completion: auto-completion for flux in Bash',
'zsh-completions: auto-completion for flux in ZSH') 'zsh-completions: auto-completion for flux in ZSH')
source=( source=(
@@ -32,12 +32,20 @@ build() {
export CGO_CXXFLAGS="$CXXFLAGS" export CGO_CXXFLAGS="$CXXFLAGS"
export CGO_CPPFLAGS="$CPPFLAGS" export CGO_CPPFLAGS="$CPPFLAGS"
export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw" export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw"
make cmd/flux/manifests make cmd/flux/.manifests.done
go build -ldflags "-linkmode=external -X main.VERSION=${pkgver}" -o ${_srcname} ./cmd/flux go build -ldflags "-linkmode=external -X main.VERSION=${pkgver}" -o ${_srcname} ./cmd/flux
} }
check() { check() {
cd "flux2" cd "flux2"
case $CARCH in
aarch64)
export ENVTEST_ARCH=arm64
;;
armv6h|armv7h)
export ENVTEST_ARCH=arm
;;
esac
make test make test
} }

View File

@@ -21,8 +21,9 @@ set -eu
KIND_VERSION=0.11.1 KIND_VERSION=0.11.1
KUBECTL_VERSION=1.21.2 KUBECTL_VERSION=1.21.2
KUSTOMIZE_VERSION=4.1.3 KUSTOMIZE_VERSION=4.1.3
HELM_VERSION=3.7.2
GITHUB_RUNNER_VERSION=2.285.1 GITHUB_RUNNER_VERSION=2.285.1
PACKAGES="apt-transport-https ca-certificates software-properties-common build-essential libssl-dev gnupg lsb-release jq" PACKAGES="apt-transport-https ca-certificates software-properties-common build-essential libssl-dev gnupg lsb-release jq pkg-config"
# install prerequisites # install prerequisites
apt-get update \ apt-get update \
@@ -52,6 +53,12 @@ curl -Lo ./kustomize.tar.gz https://github.com/kubernetes-sigs/kustomize/release
&& rm kustomize.tar.gz && rm kustomize.tar.gz
install -o root -g root -m 0755 kustomize /usr/local/bin/kustomize install -o root -g root -m 0755 kustomize /usr/local/bin/kustomize
# install helm
curl -Lo ./helm.tar.gz https://get.helm.sh/helm-v${HELM_VERSION}-linux-arm64.tar.gz \
&& tar -zxvf helm.tar.gz \
&& rm helm.tar.gz
install -o root -g root -m 0755 linux-arm64/helm /usr/local/bin/helm
# download runner # download runner
curl -o actions-runner-linux-arm64.tar.gz -L https://github.com/actions/runner/releases/download/v${GITHUB_RUNNER_VERSION}/actions-runner-linux-arm64-${GITHUB_RUNNER_VERSION}.tar.gz \ curl -o actions-runner-linux-arm64.tar.gz -L https://github.com/actions/runner/releases/download/v${GITHUB_RUNNER_VERSION}/actions-runner-linux-arm64-${GITHUB_RUNNER_VERSION}.tar.gz \
&& tar xzf actions-runner-linux-arm64.tar.gz \ && tar xzf actions-runner-linux-arm64.tar.gz \

View File

@@ -17,13 +17,13 @@ jobs:
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-go1.16-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-go1.17-${{ hashFiles('**/go.sum') }}
restore-keys: | restore-keys: |
${{ runner.os }}-go1.16- ${{ runner.os }}-go1.17-
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16.x go-version: 1.17.x
- name: Setup Kubernetes - name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0 uses: engineerd/setup-kind@v0.5.0
with: with:
@@ -103,13 +103,26 @@ jobs:
/tmp/flux reconcile image repository podinfo /tmp/flux reconcile image repository podinfo
/tmp/flux reconcile image update flux-system /tmp/flux reconcile image update flux-system
/tmp/flux get images all /tmp/flux get images all
/tmp/flux get images policy podinfo | grep "5.2.1"
/tmp/flux get image update flux-system | grep commit retries=10
count=0
ok=false
until ${ok}; do
/tmp/flux get image update flux-system | grep 'commit' && ok=true || ok=false
count=$(($count + 1))
if [[ ${count} -eq ${retries} ]]; then
echo "No more retries left"
exit 1
fi
sleep 6
/tmp/flux reconcile image update flux-system
done
env: env:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
GITHUB_REPO_NAME: ${{ steps.vars.outputs.test_repo_name }} GITHUB_REPO_NAME: ${{ steps.vars.outputs.test_repo_name }}
GITHUB_ORG_NAME: fluxcd-testing GITHUB_ORG_NAME: fluxcd-testing
- name: delete repository - name: delete repository
if: ${{ always() }}
run: | run: |
curl \ curl \
-X DELETE \ -X DELETE \

View File

@@ -16,7 +16,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16.x go-version: 1.17.x
- name: Prepare - name: Prepare
id: prep id: prep
run: | run: |

View File

@@ -17,13 +17,13 @@ jobs:
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-go1.16-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-go1.17-${{ hashFiles('**/go.sum') }}
restore-keys: | restore-keys: |
${{ runner.os }}-go1.16- ${{ runner.os }}-go1.17-
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16.x go-version: 1.17.x
- name: Install libgit2 - name: Install libgit2
run: | run: |
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138

View File

@@ -16,23 +16,19 @@ jobs:
uses: actions/cache@v1 uses: actions/cache@v1
with: with:
path: ~/go/pkg/mod path: ~/go/pkg/mod
key: ${{ runner.os }}-go1.16-${{ hashFiles('**/go.sum') }} key: ${{ runner.os }}-go1.17-${{ hashFiles('**/go.sum') }}
restore-keys: | restore-keys: |
${{ runner.os }}-go1.16- ${{ runner.os }}-go1.17-
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16.x go-version: 1.17.x
- name: Setup Kubernetes - name: Setup Kubernetes
uses: engineerd/setup-kind@v0.5.0 uses: engineerd/setup-kind@v0.5.0
with: with:
version: v0.11.1 version: v0.11.1
image: kindest/node:v1.19.11@sha256:07db187ae84b4b7de440a73886f008cf903fcf5764ba8106a9fd5243d6f32729 image: kindest/node:v1.20.7
config: .github/kind/config.yaml # disable KIND-net config: .github/kind/config.yaml # disable KIND-net
- name: Setup envtest
uses: fluxcd/pkg/actions/envtest@main
with:
version: "1.21.x"
- name: Setup Calico for network policy - name: Setup Calico for network policy
run: | run: |
kubectl apply -f https://docs.projectcalico.org/v3.20/manifests/calico.yaml kubectl apply -f https://docs.projectcalico.org/v3.20/manifests/calico.yaml

View File

@@ -4,6 +4,11 @@ on:
push: push:
tags: [ 'v*' ] tags: [ 'v*' ]
permissions:
contents: write # needed to write releases
id-token: write # needed for keyless signing
packages: write # needed for ghcr access
jobs: jobs:
goreleaser: goreleaser:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -15,16 +20,18 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16.x go-version: 1.17.x
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Setup Docker Buildx - name: Setup Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
with: - name: Setup Syft
buildkitd-flags: "--debug" uses: anchore/sbom-action/download-syft@v0
- name: Setup Cosign
uses: sigstore/cosign-installer@main
- name: Setup Kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v1
with: with:
@@ -36,18 +43,6 @@ jobs:
with: with:
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }} password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
- name: Download release notes utility
env:
GH_REL_URL: https://github.com/buchanae/github-release-notes/releases/download/0.2.0/github-release-notes-linux-amd64-0.2.0.tar.gz
run: cd /tmp && curl -sSL ${GH_REL_URL} | tar xz && sudo mv github-release-notes /usr/local/bin/
- name: Generate release notes
run: |
echo 'CHANGELOG' > /tmp/release.txt
github-release-notes -org fluxcd -repo toolkit -since-latest-release -include-author >> /tmp/release.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Kustomize
uses: fluxcd/pkg//actions/kustomize@main
- name: Generate manifests - name: Generate manifests
run: | run: |
make cmd/flux/.manifests.done make cmd/flux/.manifests.done
@@ -66,11 +61,22 @@ jobs:
- name: Archive the OpenAPI JSON schemas - name: Archive the OpenAPI JSON schemas
run: | run: |
tar -czvf ./output/crd-schemas.tar.gz -C schemas . tar -czvf ./output/crd-schemas.tar.gz -C schemas .
- name: Download release notes utility
env:
GH_REL_URL: https://github.com/buchanae/github-release-notes/releases/download/0.2.0/github-release-notes-linux-amd64-0.2.0.tar.gz
run: cd /tmp && curl -sSL ${GH_REL_URL} | tar xz && sudo mv github-release-notes /usr/local/bin/
- name: Generate release notes
run: |
NOTES="./output/notes.md"
echo '## CLI Changelog' > ${NOTES}
github-release-notes -org fluxcd -repo flux2 -since-latest-release -include-author >> ${NOTES}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1 uses: goreleaser/goreleaser-action@v1
with: with:
version: latest version: latest
args: release --release-notes=/tmp/release.txt --skip-validate args: release --release-notes=output/notes.md --skip-validate
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}

View File

@@ -16,7 +16,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16.x go-version: 1.17.x
- name: Update component versions - name: Update component versions
id: update id: update
run: | run: |

1
.gitignore vendored
View File

@@ -20,6 +20,7 @@ bin/
output/ output/
cmd/flux/manifests/ cmd/flux/manifests/
cmd/flux/.manifests.done cmd/flux/.manifests.done
testbin/
# Docs # Docs
site/ site/

View File

@@ -40,6 +40,36 @@ archives:
format: zip format: zip
files: files:
- none* - none*
source:
enabled: true
name_template: '{{ .ProjectName }}_{{ .Version }}_source_code'
sboms:
- id: source
artifacts: source
documents:
- "{{ .ProjectName }}_{{ .Version }}_sbom.spdx.json"
release:
extra_files:
- glob: output/crd-schemas.tar.gz
- glob: output/manifests.tar.gz
- glob: output/install.yaml
checksum:
extra_files:
- glob: output/crd-schemas.tar.gz
- glob: output/manifests.tar.gz
- glob: output/install.yaml
signs:
- cmd: cosign
env:
- COSIGN_EXPERIMENTAL=1
certificate: '${artifact}.pem'
args:
- sign-blob
- '--output-certificate=${certificate}'
- '--output-signature=${signature}'
- '${artifact}'
artifacts: checksum
output: true
brews: brews:
- name: flux - name: flux
tap: tap:
@@ -78,17 +108,12 @@ publishers:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }} - AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: | cmd: |
.github/aur/flux-go/publish.sh {{ .Version }} .github/aur/flux-go/publish.sh {{ .Version }}
release:
extra_files:
- glob: ./output/crd-schemas.tar.gz
- glob: ./output/manifests.tar.gz
- glob: ./output/install.yaml
dockers: dockers:
- image_templates: - image_templates:
- 'fluxcd/flux-cli:{{ .Tag }}-amd64' - 'fluxcd/flux-cli:{{ .Tag }}-amd64'
- 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-amd64' - 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-amd64'
dockerfile: Dockerfile dockerfile: Dockerfile
use_buildx: true use: buildx
goos: linux goos: linux
goarch: amd64 goarch: amd64
build_flag_templates: build_flag_templates:
@@ -104,7 +129,7 @@ dockers:
- 'fluxcd/flux-cli:{{ .Tag }}-arm64' - 'fluxcd/flux-cli:{{ .Tag }}-arm64'
- 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm64' - 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm64'
dockerfile: Dockerfile dockerfile: Dockerfile
use_buildx: true use: buildx
goos: linux goos: linux
goarch: arm64 goarch: arm64
build_flag_templates: build_flag_templates:
@@ -120,7 +145,7 @@ dockers:
- 'fluxcd/flux-cli:{{ .Tag }}-arm' - 'fluxcd/flux-cli:{{ .Tag }}-arm'
- 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm' - 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm'
dockerfile: Dockerfile dockerfile: Dockerfile
use_buildx: true use: buildx
goos: linux goos: linux
goarch: arm goarch: arm
goarm: 7 goarm: 7
@@ -144,3 +169,12 @@ docker_manifests:
- 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-amd64' - 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-amd64'
- 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm64' - 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm64'
- 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm' - 'ghcr.io/fluxcd/flux-cli:{{ .Tag }}-arm'
docker_signs:
- cmd: cosign
env:
- COSIGN_EXPERIMENTAL=1
args:
- sign
- '${artifact}'
artifacts: all
output: true

View File

@@ -67,9 +67,9 @@ for source changes.
Prerequisites: Prerequisites:
* go >= 1.16 * go >= 1.17
* kubectl >= 1.19 * kubectl >= 1.20
* kustomize >= 4.0 * kustomize >= 4.4
Install the [controller-runtime/envtest](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest) binaries with: Install the [controller-runtime/envtest](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest) binaries with:

View File

@@ -1,15 +1,15 @@
FROM alpine:3.14 as builder FROM alpine:3.15 as builder
RUN apk add --no-cache ca-certificates curl RUN apk add --no-cache ca-certificates curl
ARG ARCH=linux/amd64 ARG ARCH=linux/amd64
ARG KUBECTL_VER=1.22.2 ARG KUBECTL_VER=1.23.1
RUN curl -sL https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/${ARCH}/kubectl \ RUN curl -sL https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/${ARCH}/kubectl \
-o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl && \ -o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl && \
kubectl version --client=true kubectl version --client=true
FROM alpine:3.14 as flux-cli FROM alpine:3.15 as flux-cli
# Create minimal nsswitch.conf file to prioritize the usage of /etc/hosts over DNS queries. # Create minimal nsswitch.conf file to prioritize the usage of /etc/hosts over DNS queries.
# https://github.com/gliderlabs/docker-alpine/issues/367#issuecomment-354316460 # https://github.com/gliderlabs/docker-alpine/issues/367#issuecomment-354316460
@@ -20,4 +20,5 @@ RUN apk add --no-cache ca-certificates
COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/ COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/
COPY --chmod=755 flux /usr/local/bin/ COPY --chmod=755 flux /usr/local/bin/
USER 65534:65534
ENTRYPOINT [ "flux" ] ENTRYPOINT [ "flux" ]

View File

@@ -1,8 +1,8 @@
VERSION?=$(shell grep 'VERSION' cmd/flux/main.go | awk '{ print $$4 }' | head -n 1 | tr -d '"') VERSION?=$(shell grep 'VERSION' cmd/flux/main.go | awk '{ print $$4 }' | head -n 1 | tr -d '"')
EMBEDDED_MANIFESTS_TARGET=cmd/flux/.manifests.done EMBEDDED_MANIFESTS_TARGET=cmd/flux/.manifests.done
TEST_KUBECONFIG?=/tmp/flux-e2e-test-kubeconfig TEST_KUBECONFIG?=/tmp/flux-e2e-test-kubeconfig
ENVTEST_BIN_VERSION?=latest # Architecture to use envtest with
KUBEBUILDER_ASSETS?=$(shell $(SETUP_ENVTEST) use -i $(ENVTEST_BIN_VERSION) -p path) ENVTEST_ARCH ?= amd64
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN)) ifeq (,$(shell go env GOBIN))
@@ -17,6 +17,7 @@ all: test build
tidy: tidy:
go mod tidy go mod tidy
cd tests/azure && go mod tidy
fmt: fmt:
go fmt ./... go fmt ./...
@@ -33,6 +34,7 @@ cleanup-kind:
kind delete cluster --name=flux-e2e-test kind delete cluster --name=flux-e2e-test
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)"
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 ./... -coverprofile cover.out --tags=unit
@@ -58,27 +60,33 @@ install:
install-dev: install-dev:
CGO_ENABLED=0 go build -o /usr/local/bin ./cmd/flux CGO_ENABLED=0 go build -o /usr/local/bin ./cmd/flux
install-envtest: setup-envtest
$(SETUP_ENVTEST) use $(ENVTEST_BIN_VERSION)
setup-bootstrap-patch: setup-bootstrap-patch:
go run ./tests/bootstrap/main.go go run ./tests/bootstrap/main.go
setup-image-automation: setup-image-automation:
cd tests/image-automation && go run main.go cd tests/image-automation && go run main.go
# Find or download setup-envtest ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
setup-envtest: ENVTEST_KUBERNETES_VERSION?=latest
ifeq (, $(shell which setup-envtest)) install-envtest: setup-envtest
@{ \ mkdir -p ${ENVTEST_ASSETS_DIR}
set -e ;\ $(ENVTEST) use $(ENVTEST_KUBERNETES_VERSION) --arch=$(ENVTEST_ARCH) --bin-dir=$(ENVTEST_ASSETS_DIR)
SETUP_ENVTEST_TMP_DIR=$$(mktemp -d) ;\
cd $$SETUP_ENVTEST_TMP_DIR ;\ ENVTEST = $(shell pwd)/bin/setup-envtest
go mod init tmp ;\ .PHONY: envtest
go get sigs.k8s.io/controller-runtime/tools/setup-envtest@latest ;\ setup-envtest: ## Download envtest-setup locally if necessary.
rm -rf $$SETUP_ENVTEST_TMP_DIR ;\ $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest)
}
SETUP_ENVTEST=$(GOBIN)/setup-envtest # go-install-tool will 'go install' any package $2 and install it to $1.
else PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
SETUP_ENVTEST=$(shell which setup-envtest) define go-install-tool
endif @[ -f $(1) ] || { \
set -e ;\
TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\
go mod init tmp ;\
echo "Downloading $(2)" ;\
GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\
rm -rf $$TMP_DIR ;\
}
endef

View File

@@ -12,6 +12,9 @@ inputs:
description: "arch can be amd64, arm64 or arm" description: "arch can be amd64, arm64 or arm"
required: true required: true
default: "amd64" default: "amd64"
bindir:
description: "Optional location of the Flux binary. Will not use sudo if set. Updates System Path."
required: false
runs: runs:
using: composite using: composite
steps: steps:
@@ -29,10 +32,16 @@ runs:
curl -sL ${BIN_URL} -o /tmp/flux.tar.gz curl -sL ${BIN_URL} -o /tmp/flux.tar.gz
mkdir -p /tmp/flux mkdir -p /tmp/flux
tar -C /tmp/flux/ -zxvf /tmp/flux.tar.gz tar -C /tmp/flux/ -zxvf /tmp/flux.tar.gz
- name: "Add flux binary to /usr/local/bin" - name: "Copy Flux binary to execute location"
shell: bash shell: bash
run: | run: |
sudo cp /tmp/flux/flux /usr/local/bin BINDIR=${{ inputs.bindir }}
if [ -z $BINDIR ]; then
sudo cp /tmp/flux/flux /usr/local/bin
else
cp /tmp/flux/flux "${BINDIR}"
echo "${BINDIR}" >> $GITHUB_PATH
fi
- name: "Cleanup tmp" - name: "Cleanup tmp"
shell: bash shell: bash
run: | run: |

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

@@ -121,7 +121,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -179,7 +179,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
installOptions := install.Options{ installOptions := install.Options{
BaseURL: rootArgs.defaults.BaseURL, BaseURL: rootArgs.defaults.BaseURL,
Version: bootstrapArgs.version, Version: bootstrapArgs.version,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
@@ -200,7 +200,7 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
// Source generation and secret config // Source generation and secret config
secretOpts := sourcesecret.Options{ secretOpts := sourcesecret.Options{
Name: bootstrapArgs.secretName, Name: bootstrapArgs.secretName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
TargetPath: bServerArgs.path.String(), TargetPath: bServerArgs.path.String(),
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
@@ -232,8 +232,8 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
// Sync manifest config // Sync manifest config
syncOpts := sync.Options{ syncOpts := sync.Options{
Interval: bServerArgs.interval, Interval: bServerArgs.interval,
Name: rootArgs.namespace, Name: *kubeconfigArgs.Namespace,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Branch: bootstrapArgs.branch, Branch: bootstrapArgs.branch,
Secret: bootstrapArgs.secretName, Secret: bootstrapArgs.secretName,
TargetPath: bServerArgs.path.ToSlash(), TargetPath: bServerArgs.path.ToSlash(),
@@ -251,9 +251,10 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithProviderTeamPermissions(mapTeamSlice(bServerArgs.teams, bServerDefaultPermission)), bootstrap.WithProviderTeamPermissions(mapTeamSlice(bServerArgs.teams, bServerDefaultPermission)),
bootstrap.WithReadWriteKeyPermissions(bServerArgs.readWriteKey), bootstrap.WithReadWriteKeyPermissions(bServerArgs.readWriteKey),
bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
} }
if bootstrapArgs.sshHostname != "" { if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -101,7 +101,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -128,7 +128,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
installOptions := install.Options{ installOptions := install.Options{
BaseURL: rootArgs.defaults.BaseURL, BaseURL: rootArgs.defaults.BaseURL,
Version: bootstrapArgs.version, Version: bootstrapArgs.version,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
@@ -149,7 +149,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
// Source generation and secret config // Source generation and secret config
secretOpts := sourcesecret.Options{ secretOpts := sourcesecret.Options{
Name: bootstrapArgs.secretName, Name: bootstrapArgs.secretName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
TargetPath: gitArgs.path.String(), TargetPath: gitArgs.path.String(),
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
@@ -161,10 +161,15 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
secretOpts.CAFilePath = bootstrapArgs.caFile secretOpts.CAFilePath = bootstrapArgs.caFile
} }
// Remove port of the given host when not syncing over HTTP/S to not assume port for protocol
// This _might_ be overwritten later on by e.g. --ssh-hostname
if repositoryURL.Scheme != "https" && repositoryURL.Scheme != "http" {
repositoryURL.Host = repositoryURL.Hostname()
}
// Configure repository URL to match auth config for sync. // Configure repository URL to match auth config for sync.
repositoryURL.User = nil repositoryURL.User = nil
repositoryURL.Scheme = "https" repositoryURL.Scheme = "https"
repositoryURL.Host = repositoryURL.Hostname()
} else { } else {
secretOpts.PrivateKeyAlgorithm = sourcesecret.PrivateKeyAlgorithm(bootstrapArgs.keyAlgorithm) secretOpts.PrivateKeyAlgorithm = sourcesecret.PrivateKeyAlgorithm(bootstrapArgs.keyAlgorithm)
secretOpts.Password = gitArgs.password secretOpts.Password = gitArgs.password
@@ -194,8 +199,8 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
// Sync manifest config // Sync manifest config
syncOpts := sync.Options{ syncOpts := sync.Options{
Interval: gitArgs.interval, Interval: gitArgs.interval,
Name: rootArgs.namespace, Name: *kubeconfigArgs.Namespace,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
URL: repositoryURL.String(), URL: repositoryURL.String(),
Branch: bootstrapArgs.branch, Branch: bootstrapArgs.branch,
Secret: bootstrapArgs.secretName, Secret: bootstrapArgs.secretName,
@@ -220,7 +225,7 @@ func bootstrapGitCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithBranch(bootstrapArgs.branch), bootstrap.WithBranch(bootstrapArgs.branch),
bootstrap.WithAuthor(bootstrapArgs.authorName, bootstrapArgs.authorEmail), bootstrap.WithAuthor(bootstrapArgs.authorName, bootstrapArgs.authorEmail),
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithPostGenerateSecretFunc(promptPublicKey), bootstrap.WithPostGenerateSecretFunc(promptPublicKey),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),

View File

@@ -125,7 +125,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -175,7 +175,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
installOptions := install.Options{ installOptions := install.Options{
BaseURL: rootArgs.defaults.BaseURL, BaseURL: rootArgs.defaults.BaseURL,
Version: bootstrapArgs.version, Version: bootstrapArgs.version,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
@@ -196,7 +196,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// Source generation and secret config // Source generation and secret config
secretOpts := sourcesecret.Options{ secretOpts := sourcesecret.Options{
Name: bootstrapArgs.secretName, Name: bootstrapArgs.secretName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
TargetPath: githubArgs.path.ToSlash(), TargetPath: githubArgs.path.ToSlash(),
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
@@ -221,8 +221,8 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// Sync manifest config // Sync manifest config
syncOpts := sync.Options{ syncOpts := sync.Options{
Interval: githubArgs.interval, Interval: githubArgs.interval,
Name: rootArgs.namespace, Name: *kubeconfigArgs.Namespace,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Branch: bootstrapArgs.branch, Branch: bootstrapArgs.branch,
Secret: bootstrapArgs.secretName, Secret: bootstrapArgs.secretName,
TargetPath: githubArgs.path.ToSlash(), TargetPath: githubArgs.path.ToSlash(),
@@ -240,9 +240,10 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithProviderTeamPermissions(mapTeamSlice(githubArgs.teams, ghDefaultPermission)), bootstrap.WithProviderTeamPermissions(mapTeamSlice(githubArgs.teams, ghDefaultPermission)),
bootstrap.WithReadWriteKeyPermissions(githubArgs.readWriteKey), bootstrap.WithReadWriteKeyPermissions(githubArgs.readWriteKey),
bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
} }
if bootstrapArgs.sshHostname != "" { if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

View File

@@ -129,7 +129,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -186,7 +186,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
installOptions := install.Options{ installOptions := install.Options{
BaseURL: rootArgs.defaults.BaseURL, BaseURL: rootArgs.defaults.BaseURL,
Version: bootstrapArgs.version, Version: bootstrapArgs.version,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Components: bootstrapComponents(), Components: bootstrapComponents(),
Registry: bootstrapArgs.registry, Registry: bootstrapArgs.registry,
ImagePullSecret: bootstrapArgs.imagePullSecret, ImagePullSecret: bootstrapArgs.imagePullSecret,
@@ -207,7 +207,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// Source generation and secret config // Source generation and secret config
secretOpts := sourcesecret.Options{ secretOpts := sourcesecret.Options{
Name: bootstrapArgs.secretName, Name: bootstrapArgs.secretName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
TargetPath: gitlabArgs.path.String(), TargetPath: gitlabArgs.path.String(),
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
@@ -235,8 +235,8 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
// Sync manifest config // Sync manifest config
syncOpts := sync.Options{ syncOpts := sync.Options{
Interval: gitlabArgs.interval, Interval: gitlabArgs.interval,
Name: rootArgs.namespace, Name: *kubeconfigArgs.Namespace,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Branch: bootstrapArgs.branch, Branch: bootstrapArgs.branch,
Secret: bootstrapArgs.secretName, Secret: bootstrapArgs.secretName,
TargetPath: gitlabArgs.path.ToSlash(), TargetPath: gitlabArgs.path.ToSlash(),
@@ -254,9 +254,10 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix), bootstrap.WithCommitMessageAppendix(bootstrapArgs.commitMessageAppendix),
bootstrap.WithProviderTeamPermissions(mapTeamSlice(gitlabArgs.teams, glDefaultPermission)), bootstrap.WithProviderTeamPermissions(mapTeamSlice(gitlabArgs.teams, glDefaultPermission)),
bootstrap.WithReadWriteKeyPermissions(gitlabArgs.readWriteKey), bootstrap.WithReadWriteKeyPermissions(gitlabArgs.readWriteKey),
bootstrap.WithKubeconfig(rootArgs.kubeconfig, rootArgs.kubecontext), bootstrap.WithKubeconfig(kubeconfigArgs),
bootstrap.WithLogger(logger), bootstrap.WithLogger(logger),
bootstrap.WithCABundle(caBundle), bootstrap.WithCABundle(caBundle),
bootstrap.WithGitCommitSigning(bootstrapArgs.gpgKeyRingPath, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID),
} }
if bootstrapArgs.sshHostname != "" { if bootstrapArgs.sshHostname != "" {
bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname))

31
cmd/flux/build.go Normal file
View File

@@ -0,0 +1,31 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
)
var buildCmd = &cobra.Command{
Use: "build",
Short: "Build a flux resource",
Long: "The build command is used to build flux resources.",
}
func init() {
rootCmd.AddCommand(buildCmd)
}

View File

@@ -0,0 +1,100 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"os"
"os/signal"
"github.com/spf13/cobra"
"github.com/fluxcd/flux2/internal/build"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
var buildKsCmd = &cobra.Command{
Use: "kustomization",
Aliases: []string{"ks"},
Short: "Build Kustomization",
Long: `The build command queries the Kubernetes API and fetches the specified Flux Kustomization.
It then uses the fetched in cluster flux kustomization to perform needed transformation on the local kustomization.yaml
pointed at by --path. The local kustomization.yaml is generated if it does not exist. Finally it builds the overlays using the local kustomization.yaml, and write the resulting multi-doc YAML to stdout.`,
Example: `# Build the local manifests as they were built on the cluster
flux build kustomization my-app --path ./path/to/local/manifests`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: buildKsCmdRun,
}
type buildKsFlags struct {
path string
}
var buildKsArgs buildKsFlags
func init() {
buildKsCmd.Flags().StringVar(&buildKsArgs.path, "path", "", "Path to the manifests location.)")
buildCmd.AddCommand(buildKsCmd)
}
func buildKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("%s name is required", kustomizationType.humanKind)
}
name := args[0]
if buildKsArgs.path == "" {
return fmt.Errorf("invalid resource path %q", buildKsArgs.path)
}
if fs, err := os.Stat(buildKsArgs.path); err != nil || !fs.IsDir() {
return fmt.Errorf("invalid resource path %q", buildKsArgs.path)
}
builder, err := build.NewBuilder(kubeconfigArgs, name, buildKsArgs.path, build.WithTimeout(rootArgs.timeout))
if err != nil {
return err
}
// create a signal channel
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt)
errChan := make(chan error)
go func() {
manifests, err := builder.Build()
if err != nil {
errChan <- err
}
cmd.Print(string(manifests))
errChan <- nil
}()
select {
case <-sigc:
fmt.Println("Build cancelled... exiting.")
return builder.Cancel()
case err := <-errChan:
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,83 @@
//go:build unit
// +build unit
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"testing"
)
func setup(t *testing.T, tmpl map[string]string) {
t.Helper()
testEnv.CreateObjectFile("./testdata/build-kustomization/podinfo-source.yaml", tmpl, t)
testEnv.CreateObjectFile("./testdata/build-kustomization/podinfo-kustomization.yaml", tmpl, t)
}
func TestBuildKustomization(t *testing.T) {
tests := []struct {
name string
args string
resultFile string
assertFunc string
}{
{
name: "no args",
args: "build kustomization podinfo",
resultFile: "invalid resource path \"\"",
assertFunc: "assertError",
},
{
name: "build podinfo",
args: "build kustomization podinfo --path ./testdata/build-kustomization/podinfo",
resultFile: "./testdata/build-kustomization/podinfo-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
{
name: "build podinfo without service",
args: "build kustomization podinfo --path ./testdata/build-kustomization/delete-service",
resultFile: "./testdata/build-kustomization/podinfo-without-service-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
}
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
setup(t, tmpl)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var assert assertFunc
switch tt.assertFunc {
case "assertGoldenTemplateFile":
assert = assertGoldenTemplateFile(tt.resultFile, tmpl)
case "assertError":
assert = assertError(tt.resultFile)
}
cmd := cmdTestCase{
args: tt.args + " -n " + tmpl["fluxns"],
assert: assert,
}
cmd.runTestCmd(t)
})
}
}

View File

@@ -56,10 +56,7 @@ type checkFlags struct {
} }
var kubernetesConstraints = []string{ var kubernetesConstraints = []string{
">=1.19.0-0", ">=1.20.6-0",
">=1.16.11-0 <=1.16.15-0",
">=1.17.7-0 <=1.17.17-0",
">=1.18.4-0 <=1.18.20-0",
} }
var checkArgs checkFlags var checkArgs checkFlags
@@ -128,7 +125,7 @@ func fluxCheck() {
} }
func kubernetesCheck(constraints []string) bool { func kubernetesCheck(constraints []string) bool {
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) cfg, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
logger.Failuref("Kubernetes client initialization failed: %s", err.Error()) logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false return false
@@ -176,7 +173,7 @@ func componentsCheck() bool {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) kubeConfig, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return false return false
} }
@@ -186,7 +183,7 @@ func componentsCheck() bool {
return false return false
} }
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return false return false
} }
@@ -194,7 +191,7 @@ func componentsCheck() bool {
ok := true ok := true
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue} selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
var list v1.DeploymentList var list v1.DeploymentList
if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace), selector); err == nil { if err := kubeClient.List(ctx, &list, client.InNamespace(*kubeconfigArgs.Namespace), selector); err == nil {
for _, d := range list.Items { for _, d := range list.Items {
if ref, err := buildComponentObjectRefs(d.Name); err == nil { if ref, err := buildComponentObjectRefs(d.Name); err == nil {
if err := statusChecker.Assess(ref...); err != nil { if err := statusChecker.Assess(ref...); err != nil {

View File

@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e // +build e2e
/* /*
@@ -29,7 +30,7 @@ import (
) )
func TestCheckPre(t *testing.T) { func TestCheckPre(t *testing.T) {
jsonOutput, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, "version", "--output", "json") jsonOutput, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, "version", "--output", "json")
if err != nil { if err != nil {
t.Fatalf("Error running utils.ExecKubectlCommand: %v", err.Error()) t.Fatalf("Error running utils.ExecKubectlCommand: %v", err.Error())
} }

View File

@@ -25,10 +25,7 @@ import (
"k8s.io/apimachinery/pkg/api/meta" "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"
"k8s.io/client-go/discovery"
memory "k8s.io/client-go/discovery/cached"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
"k8s.io/client-go/restmapper"
) )
var completionCmd = &cobra.Command{ var completionCmd = &cobra.Command{
@@ -42,7 +39,7 @@ func init() {
} }
func contextsCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { func contextsCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
rawConfig, err := utils.ClientConfig(rootArgs.kubeconfig, rootArgs.kubecontext).RawConfig() rawConfig, err := kubeconfigArgs.ToRawKubeConfigLoader().RawConfig()
if err != nil { if err != nil {
return completionError(err) return completionError(err)
} }
@@ -63,16 +60,15 @@ func resourceNamesCompletionFunc(gvk schema.GroupVersionKind) func(cmd *cobra.Co
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) cfg, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return completionError(err) return completionError(err)
} }
dc, err := discovery.NewDiscoveryClientForConfig(cfg) mapper, err := kubeconfigArgs.ToRESTMapper()
if err != nil { if err != nil {
return completionError(err) return completionError(err)
} }
mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc))
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version) mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
@@ -86,7 +82,7 @@ func resourceNamesCompletionFunc(gvk schema.GroupVersionKind) func(cmd *cobra.Co
var dr dynamic.ResourceInterface var dr dynamic.ResourceInterface
if mapping.Scope.Name() == meta.RESTScopeNameNamespace { if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
dr = client.Resource(mapping.Resource).Namespace(rootArgs.namespace) dr = client.Resource(mapping.Resource).Namespace(*kubeconfigArgs.Namespace)
} else { } else {
dr = client.Resource(mapping.Resource) dr = client.Resource(mapping.Resource)
} }

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)
} }
@@ -104,7 +117,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) // NB globals kubeClient, err := utils.KubeClient(kubeconfigArgs) // NB globals
if err != nil { if err != nil {
return err return err
} }
@@ -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 == "" {
@@ -102,7 +99,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
alert := notificationv1.Alert{ alert := notificationv1.Alert{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: notificationv1.AlertSpec{ Spec: notificationv1.AlertSpec{
@@ -122,7 +119,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

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 == "" {
@@ -94,7 +91,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
provider := notificationv1.Provider{ provider := notificationv1.Provider{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: notificationv1.ProviderSpec{ Spec: notificationv1.ProviderSpec{
@@ -118,7 +115,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

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 == "" {
@@ -160,7 +157,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
helmRelease := helmv2.HelmRelease{ helmRelease := helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: helmv2.HelmReleaseSpec{ Spec: helmv2.HelmReleaseSpec{
@@ -250,7 +247,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

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 == "" {
@@ -101,7 +98,7 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
var policy = imagev1.ImagePolicy{ var policy = imagev1.ImagePolicy{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: objectName, Name: objectName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: labels, Labels: labels,
}, },
Spec: imagev1.ImagePolicySpec{ Spec: imagev1.ImagePolicySpec{

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 == "" {
@@ -104,7 +101,7 @@ func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
var repo = imagev1.ImageRepository{ var repo = imagev1.ImageRepository{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: objectName, Name: objectName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: labels, Labels: labels,
}, },
Spec: imagev1.ImageRepositorySpec{ Spec: imagev1.ImageRepositorySpec{

View File

@@ -49,25 +49,40 @@ mentioned in YAMLs in a git repository.`,
--push-branch=image-updates \ --push-branch=image-updates \
--author-name=flux \ --author-name=flux \
--author-email=flux@example.com \ --author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"`, --commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
# Configure image updates for a Git repository in a different namespace
flux create image update apps \
--namespace=apps \
--git-repo-ref=flux-system \
--git-repo-namespace=flux-system \
--git-repo-path="./clusters/my-cluster" \
--checkout-branch=main \
--push-branch=image-updates \
--author-name=flux \
--author-email=flux@example.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}"
`,
RunE: createImageUpdateRun, RunE: createImageUpdateRun,
} }
type imageUpdateFlags struct { type imageUpdateFlags struct {
gitRepoRef string gitRepoName string
gitRepoPath string gitRepoNamespace string
checkoutBranch string gitRepoPath string
pushBranch string checkoutBranch string
commitTemplate string pushBranch string
authorName string commitTemplate string
authorEmail string authorName string
authorEmail string
} }
var imageUpdateArgs = imageUpdateFlags{} var imageUpdateArgs = imageUpdateFlags{}
func init() { func init() {
flags := createImageUpdateCmd.Flags() flags := createImageUpdateCmd.Flags()
flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository") flags.StringVar(&imageUpdateArgs.gitRepoName, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream Git repository")
flags.StringVar(&imageUpdateArgs.gitRepoNamespace, "git-repo-namespace", "", "the namespace of the GitRepository resource, defaults to the ImageUpdateAutomation namespace")
flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root") flags.StringVar(&imageUpdateArgs.gitRepoPath, "git-repo-path", "", "path to the directory containing the manifests to be updated, defaults to the repository root")
flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout") flags.StringVar(&imageUpdateArgs.checkoutBranch, "checkout-branch", "", "the branch to checkout")
flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified") flags.StringVar(&imageUpdateArgs.pushBranch, "push-branch", "", "the branch to push commits to, defaults to the checkout branch if not specified")
@@ -79,12 +94,9 @@ 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.gitRepoRef == "" { if imageUpdateArgs.gitRepoName == "" {
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)") return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
} }
@@ -108,13 +120,14 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
var update = autov1.ImageUpdateAutomation{ var update = autov1.ImageUpdateAutomation{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: objectName, Name: objectName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: labels, Labels: labels,
}, },
Spec: autov1.ImageUpdateAutomationSpec{ Spec: autov1.ImageUpdateAutomationSpec{
SourceRef: autov1.SourceReference{ SourceRef: autov1.CrossNamespaceSourceReference{
Kind: sourcev1.GitRepositoryKind, Kind: sourcev1.GitRepositoryKind,
Name: imageUpdateArgs.gitRepoRef, Name: imageUpdateArgs.gitRepoName,
Namespace: imageUpdateArgs.gitRepoNamespace,
}, },
GitSpec: &autov1.GitSpec{ GitSpec: &autov1.GitSpec{

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 == "" {
@@ -143,7 +140,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
kustomization := kustomizev1.Kustomization{ kustomization := kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: kslabels, Labels: kslabels,
}, },
Spec: kustomizev1.KustomizationSpec{ Spec: kustomizev1.KustomizationSpec{
@@ -232,7 +229,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

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 == "" {
@@ -109,7 +106,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
receiver := notificationv1.Receiver{ receiver := notificationv1.Receiver{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: notificationv1.ReceiverSpec{ Spec: notificationv1.ReceiverSpec{
@@ -130,7 +127,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }

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")
@@ -132,7 +129,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
opts := sourcesecret.Options{ opts := sourcesecret.Options{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: labels, Labels: labels,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
@@ -176,14 +173,14 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
if err := upsertSecret(ctx, kubeClient, s); err != nil { if err := upsertSecret(ctx, kubeClient, s); err != nil {
return err return err
} }
logger.Actionf("git secret '%s' created in '%s' namespace", name, rootArgs.namespace) logger.Actionf("git secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
return nil return nil
} }

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()
@@ -80,7 +76,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
opts := sourcesecret.Options{ opts := sourcesecret.Options{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: labels, Labels: labels,
Username: secretHelmArgs.username, Username: secretHelmArgs.username,
Password: secretHelmArgs.password, Password: secretHelmArgs.password,
@@ -100,7 +96,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -112,6 +108,6 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
logger.Actionf("helm secret '%s' created in '%s' namespace", name, rootArgs.namespace) logger.Actionf("helm secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
return nil return nil
} }

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()
@@ -79,7 +75,7 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
opts := sourcesecret.Options{ opts := sourcesecret.Options{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: labels, Labels: labels,
CAFilePath: secretTLSArgs.caFile, CAFilePath: secretTLSArgs.caFile,
CertFilePath: secretTLSArgs.certFile, CertFilePath: secretTLSArgs.certFile,
@@ -97,7 +93,7 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -109,6 +105,6 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
logger.Actionf("tls secret '%s' created in '%s' namespace", name, rootArgs.namespace) logger.Actionf("tls secret '%s' created in '%s' namespace", name, *kubeconfigArgs.Namespace)
return nil return nil
} }

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

@@ -93,9 +93,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 == "" {
@@ -120,7 +117,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
bucket := &sourcev1.Bucket{ bucket := &sourcev1.Bucket{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: sourcev1.BucketSpec{ Spec: sourcev1.BucketSpec{
@@ -152,7 +149,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -165,7 +162,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
secret := corev1.Secret{ secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: secretName, Name: secretName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
StringData: map[string]string{}, StringData: map[string]string{},

View File

@@ -150,9 +150,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 == "" {
@@ -193,7 +190,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
gitRepository := sourcev1.GitRepository{ gitRepository := sourcev1.GitRepository{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: sourcev1.GitRepositorySpec{ Spec: sourcev1.GitRepositorySpec{
@@ -235,7 +232,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -244,7 +241,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if sourceGitArgs.secretRef == "" { if sourceGitArgs.secretRef == "" {
secretOpts := sourcesecret.Options{ secretOpts := sourcesecret.Options{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
switch u.Scheme { switch u.Scheme {

View File

@@ -1,3 +1,4 @@
//go:build unit
// +build unit // +build unit
/* /*
@@ -95,7 +96,7 @@ 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",

View File

@@ -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 == "" {
@@ -118,7 +115,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
helmRepository := &sourcev1.HelmRepository{ helmRepository := &sourcev1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: sourcev1.HelmRepositorySpec{ Spec: sourcev1.HelmRepositorySpec{
@@ -147,7 +144,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -157,7 +154,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
secretName := fmt.Sprintf("helm-%s", name) secretName := fmt.Sprintf("helm-%s", name)
secretOpts := sourcesecret.Options{ secretOpts := sourcesecret.Options{
Name: secretName, Name: secretName,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Username: sourceHelmArgs.username, Username: sourceHelmArgs.username,
Password: sourceHelmArgs.password, Password: sourceHelmArgs.password,
CertFilePath: sourceHelmArgs.certFile, CertFilePath: sourceHelmArgs.certFile,

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)
@@ -159,7 +156,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return 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

@@ -60,13 +60,13 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
@@ -85,7 +85,7 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
} }
} }
logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, rootArgs.namespace) logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, *kubeconfigArgs.Namespace)
err = kubeClient.Delete(ctx, del.object.asClientObject()) err = kubeClient.Delete(ctx, del.object.asClientObject())
if err != nil { if err != nil {
return err return err

31
cmd/flux/diff.go Normal file
View File

@@ -0,0 +1,31 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
)
var diffCmd = &cobra.Command{
Use: "diff",
Short: "Diff a flux resource",
Long: "The diff command is used to do a server-side dry-run on flux resources, then prints the diff.",
}
func init() {
rootCmd.AddCommand(diffCmd)
}

View File

@@ -0,0 +1,113 @@
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"os"
"os/signal"
"github.com/spf13/cobra"
"github.com/fluxcd/flux2/internal/build"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
)
var diffKsCmd = &cobra.Command{
Use: "kustomization",
Aliases: []string{"ks"},
Short: "Diff Kustomization",
Long: `The diff command does a build, then it performs a server-side dry-run and prints the diff.
Exit status: 0 No differences were found. 1 Differences were found. >1 diff failed with an error.`,
Example: `# Preview local changes as they were applied on the cluster
flux diff kustomization my-app --path ./path/to/local/manifests`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: diffKsCmdRun,
}
type diffKsFlags struct {
path string
progressBar bool
}
var diffKsArgs diffKsFlags
func init() {
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)
}
func diffKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("%s name is required", kustomizationType.humanKind)
}
name := args[0]
if diffKsArgs.path == "" {
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)}
}
if fs, err := os.Stat(diffKsArgs.path); err != nil || !fs.IsDir() {
return &RequestError{StatusCode: 2, Err: fmt.Errorf("invalid resource path %q", diffKsArgs.path)}
}
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 {
return &RequestError{StatusCode: 2, Err: err}
}
// create a signal channel
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt)
errChan := make(chan error)
go func() {
output, hasChanged, err := builder.Diff()
if err != nil {
errChan <- &RequestError{StatusCode: 2, Err: err}
}
cmd.Print(output)
if hasChanged {
errChan <- &RequestError{StatusCode: 1, Err: fmt.Errorf("identified at least one change, exiting with non-zero exit code")}
} else {
errChan <- nil
}
}()
select {
case <-sigc:
fmt.Println("Build cancelled... exiting.")
return builder.Cancel()
case err := <-errChan:
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,145 @@
//go:build unit
// +build unit
/*
Copyright 2021 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"os"
"strings"
"testing"
"github.com/fluxcd/flux2/internal/build"
"github.com/fluxcd/pkg/ssa"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func TestDiffKustomization(t *testing.T) {
tests := []struct {
name string
args string
objectFile string
assert assertFunc
}{
{
name: "no args",
args: "diff kustomization podinfo",
objectFile: "",
assert: assertError("invalid resource path \"\""),
},
{
name: "diff nothing deployed",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "",
assert: assertGoldenFile("./testdata/diff-kustomization/nothing-is-deployed.golden"),
},
{
name: "diff with a deployment object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/deployment.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-deployment.golden"),
},
{
name: "diff with a drifted service object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/service.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-service.golden"),
},
{
name: "diff with a drifted secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-secret.golden"),
},
{
name: "diff with a drifted key in sops secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/key-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-key-sops-secret.golden"),
},
{
name: "diff with a drifted value in sops secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/value-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-value-sops-secret.golden"),
},
{
name: "diff with a sops dockerconfigjson secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/dockerconfigjson-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-dockerconfigjson-sops-secret.golden"),
},
{
name: "diff with a sops stringdata secret object",
args: "diff kustomization podinfo --path ./testdata/build-kustomization/podinfo --progress-bar=false",
objectFile: "./testdata/diff-kustomization/stringdata-sops-secret.yaml",
assert: assertGoldenFile("./testdata/diff-kustomization/diff-with-drifted-stringdata-sops-secret.golden"),
},
}
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
b, _ := build.NewBuilder(kubeconfigArgs, "podinfo", "")
resourceManager, err := b.Manager()
if err != nil {
t.Fatal(err)
}
setup(t, tmpl)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.objectFile != "" {
resourceManager.ApplyAll(context.Background(), createObjectFromFile(tt.objectFile, tmpl, t), ssa.DefaultApplyOptions())
}
cmd := cmdTestCase{
args: tt.args + " -n " + tmpl["fluxns"],
assert: tt.assert,
}
cmd.runTestCmd(t)
if tt.objectFile != "" {
testEnv.DeleteObjectFile(tt.objectFile, tmpl, t)
}
})
}
}
func createObjectFromFile(objectFile string, templateValues map[string]string, t *testing.T) []*unstructured.Unstructured {
buf, err := os.ReadFile(objectFile)
if err != nil {
t.Fatalf("Error reading file '%s': %v", objectFile, err)
}
content, err := executeTemplate(string(buf), templateValues)
if err != nil {
t.Fatalf("Error evaluating template file '%s': '%v'", objectFile, err)
}
clientObjects, err := readYamlObjects(strings.NewReader(content))
if err != nil {
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
}

View File

@@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
@@ -73,19 +74,19 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
if exportArgs.all { if exportArgs.all {
err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace)) err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(*kubeconfigArgs.Namespace))
if err != nil { if err != nil {
return err return err
} }
if export.list.len() == 0 { if export.list.len() == 0 {
return fmt.Errorf("no objects found in %s namespace", rootArgs.namespace) return fmt.Errorf("no objects found in %s namespace", *kubeconfigArgs.Namespace)
} }
for i := 0; i < export.list.len(); i++ { for i := 0; i < export.list.len(); i++ {
@@ -96,7 +97,7 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
} else { } else {
name := args[0] name := args[0]
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject()) err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject())

View File

@@ -19,6 +19,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -58,19 +59,19 @@ func (export exportWithSecretCommand) run(cmd *cobra.Command, args []string) err
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
if exportArgs.all { if exportArgs.all {
err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace)) err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(*kubeconfigArgs.Namespace))
if err != nil { if err != nil {
return err return err
} }
if export.list.len() == 0 { if export.list.len() == 0 {
return fmt.Errorf("no objects found in %s namespace", rootArgs.namespace) return fmt.Errorf("no objects found in %s namespace", *kubeconfigArgs.Namespace)
} }
for i := 0; i < export.list.len(); i++ { for i := 0; i < export.list.len(); i++ {
@@ -88,7 +89,7 @@ func (export exportWithSecretCommand) run(cmd *cobra.Command, args []string) err
} else { } else {
name := args[0] name := args[0]
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject()) err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject())

View File

@@ -1,3 +1,4 @@
//go:build unit
// +build unit // +build unit
package main package main

View File

@@ -135,14 +135,14 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
var listOpts []client.ListOption var listOpts []client.ListOption
if !getArgs.allNamespaces { if !getArgs.allNamespaces {
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace)) listOpts = append(listOpts, client.InNamespace(*kubeconfigArgs.Namespace))
} }
if len(args) > 0 { if len(args) > 0 {
@@ -162,7 +162,7 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
if get.list.len() == 0 { if get.list.len() == 0 {
if !getAll { if !getAll {
logger.Failuref("no %s objects found in %s namespace", get.kind, rootArgs.namespace) logger.Failuref("no %s objects found in %s namespace", get.kind, *kubeconfigArgs.Namespace)
} }
return nil return nil
} }

View File

@@ -25,9 +25,6 @@ var getImageCmd = &cobra.Command{
Aliases: []string{"image"}, Aliases: []string{"image"},
Short: "Get image automation object status", Short: "Get image automation object status",
Long: "The get image sub-commands print the status of image automation objects.", Long: "The get image sub-commands print the status of image automation objects.",
RunE: func(cmd *cobra.Command, args []string) error {
return validateWatchOption(cmd, "images")
},
} }
func init() { func init() {

View File

@@ -18,10 +18,12 @@ package main
import ( import (
"fmt" "fmt"
"regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta2"
@@ -78,6 +80,10 @@ func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool, in
item := a.Items[i] item := a.Items[i]
revision := item.Status.LastAppliedRevision revision := item.Status.LastAppliedRevision
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
if status == string(metav1.ConditionTrue) {
revision = shortenCommitSha(revision)
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))) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }
@@ -94,3 +100,13 @@ func (a kustomizationListAdapter) statusSelectorMatches(i int, conditionType, co
item := a.Items[i] item := a.Items[i]
return statusMatches(conditionType, conditionStatus, item.Status.Conditions) return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
} }
func shortenCommitSha(msg string) string {
r := regexp.MustCompile("/([a-f0-9]{40})$")
sha := r.FindString(msg)
if sha != "" {
msg = strings.Replace(msg, sha, string([]rune(sha)[:8]), -1)
}
return msg
}

View File

@@ -25,10 +25,6 @@ var getSourceCmd = &cobra.Command{
Aliases: []string{"source"}, Aliases: []string{"source"},
Short: "Get source statuses", Short: "Get source statuses",
Long: "The get source sub-commands print the statuses of the sources.", Long: "The get source sub-commands print the statuses of the sources.",
RunE: func(cmd *cobra.Command, args []string) error {
return validateWatchOption(cmd, "sources")
},
} }
func init() { func init() {

View File

@@ -22,6 +22,7 @@ import (
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
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/v1beta1"
@@ -80,6 +81,10 @@ func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool, i
revision = item.GetArtifact().Revision revision = item.GetArtifact().Revision
} }
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
if status == string(metav1.ConditionTrue) {
revision = shortenCommitSha(revision)
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))) status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
} }

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

@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e // +build e2e
/* /*

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

@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e // +build e2e
package main package main

View File

@@ -131,7 +131,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
logger.Generatef("generating manifests") logger.Generatef("generating manifests")
} }
tmpDir, err := os.MkdirTemp("", rootArgs.namespace) tmpDir, err := os.MkdirTemp("", *kubeconfigArgs.Namespace)
if err != nil { if err != nil {
return err return err
} }
@@ -148,7 +148,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
opts := install.Options{ opts := install.Options{
BaseURL: installArgs.manifestsPath, BaseURL: installArgs.manifestsPath,
Version: installArgs.version, Version: installArgs.version,
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Components: components, Components: components,
Registry: installArgs.registry, Registry: installArgs.registry,
ImagePullSecret: installArgs.imagePullSecret, ImagePullSecret: installArgs.imagePullSecret,
@@ -156,7 +156,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
NetworkPolicy: installArgs.networkPolicy, NetworkPolicy: installArgs.networkPolicy,
LogLevel: installArgs.logLevel.String(), LogLevel: installArgs.logLevel.String(),
NotificationController: rootArgs.defaults.NotificationController, NotificationController: rootArgs.defaults.NotificationController,
ManifestFile: fmt.Sprintf("%s.yaml", rootArgs.namespace), ManifestFile: fmt.Sprintf("%s.yaml", *kubeconfigArgs.Namespace),
Timeout: rootArgs.timeout, Timeout: rootArgs.timeout,
ClusterDomain: installArgs.clusterDomain, ClusterDomain: installArgs.clusterDomain,
TolerationKeys: installArgs.tolerationKeys, TolerationKeys: installArgs.tolerationKeys,
@@ -183,21 +183,21 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
} }
logger.Successf("manifests build completed") logger.Successf("manifests build completed")
logger.Actionf("installing components in %s namespace", rootArgs.namespace) logger.Actionf("installing components in %s namespace", *kubeconfigArgs.Namespace)
if installArgs.dryRun { if installArgs.dryRun {
logger.Successf("install dry-run finished") logger.Successf("install dry-run finished")
return nil return nil
} }
applyOutput, err := utils.Apply(ctx, rootArgs.kubeconfig, rootArgs.kubecontext, filepath.Join(tmpDir, manifest.Path)) applyOutput, err := utils.Apply(ctx, kubeconfigArgs, filepath.Join(tmpDir, manifest.Path))
if err != nil { if err != nil {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }
fmt.Fprintln(os.Stderr, applyOutput) fmt.Fprintln(os.Stderr, applyOutput)
kubeConfig, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) kubeConfig, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }

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

@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e // +build e2e
/* /*

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"
@@ -99,7 +99,7 @@ func logsCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext) cfg, err := utils.KubeConfig(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
@@ -278,7 +278,7 @@ func filterPrintLog(t *template.Template, l *ControllerLogEntry) {
if logsArgs.logLevel != "" && logsArgs.logLevel != l.Level || if logsArgs.logLevel != "" && logsArgs.logLevel != l.Level ||
logsArgs.kind != "" && strings.ToLower(logsArgs.kind) != strings.ToLower(l.Kind) || logsArgs.kind != "" && strings.ToLower(logsArgs.kind) != strings.ToLower(l.Kind) ||
logsArgs.name != "" && strings.ToLower(logsArgs.name) != strings.ToLower(l.Name) || logsArgs.name != "" && strings.ToLower(logsArgs.name) != strings.ToLower(l.Name) ||
!logsArgs.allNamespaces && strings.ToLower(rootArgs.namespace) != strings.ToLower(l.Namespace) { !logsArgs.allNamespaces && strings.ToLower(*kubeconfigArgs.Namespace) != strings.ToLower(l.Namespace) {
return return
} }

View File

@@ -1,3 +1,4 @@
//go:build unit
// +build unit // +build unit
/* /*

View File

@@ -21,13 +21,13 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path/filepath"
"strings" "strings"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/term" "golang.org/x/term"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"
"github.com/fluxcd/flux2/pkg/manifestgen/install" "github.com/fluxcd/flux2/pkg/manifestgen/install"
@@ -99,29 +99,43 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.`,
var logger = stderrLogger{stderr: os.Stderr} var logger = stderrLogger{stderr: os.Stderr}
type rootFlags struct { type rootFlags struct {
kubeconfig string
kubecontext string
namespace string
timeout time.Duration timeout time.Duration
verbose bool verbose bool
pollInterval time.Duration pollInterval time.Duration
defaults install.Options defaults install.Options
} }
// RequestError is a custom error type that wraps an error returned by the flux api.
type RequestError struct {
StatusCode int
Err error
}
func (r *RequestError) Error() string {
return r.Err.Error()
}
var rootArgs = NewRootFlags() var rootArgs = NewRootFlags()
var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
func init() { func init() {
rootCmd.PersistentFlags().StringVarP(&rootArgs.namespace, "namespace", "n", rootArgs.defaults.Namespace,
"the namespace scope for this operation, can be set with FLUX_SYSTEM_NAMESPACE env var")
rootCmd.RegisterFlagCompletionFunc("namespace", resourceNamesCompletionFunc(corev1.SchemeGroupVersion.WithKind("Namespace")))
rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation") rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation")
rootCmd.PersistentFlags().BoolVar(&rootArgs.verbose, "verbose", false, "print generated objects") rootCmd.PersistentFlags().BoolVar(&rootArgs.verbose, "verbose", false, "print generated objects")
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", "",
"absolute path to the kubeconfig file")
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubecontext, "context", "", "", "kubernetes context to use") configureDefaultNamespace()
kubeconfigArgs.APIServer = nil // prevent AddFlags from configuring --server flag
kubeconfigArgs.Timeout = nil // prevent AddFlags from configuring --request-timeout flag, we have --timeout instead
kubeconfigArgs.AddFlags(rootCmd.PersistentFlags())
// Since some subcommands use the `-s` flag as a short version for `--silent`, we manually configure the server flag
// without the `-s` short version. While we're no longer on par with kubectl's flags, we maintain backwards compatibility
// on the CLI interface.
apiServer := ""
kubeconfigArgs.APIServer = &apiServer
rootCmd.PersistentFlags().StringVar(kubeconfigArgs.APIServer, "server", *kubeconfigArgs.APIServer, "The address and port of the Kubernetes API server")
rootCmd.RegisterFlagCompletionFunc("context", contextsCompletionFunc) rootCmd.RegisterFlagCompletionFunc("context", contextsCompletionFunc)
rootCmd.RegisterFlagCompletionFunc("namespace", resourceNamesCompletionFunc(corev1.SchemeGroupVersion.WithKind("Namespace")))
rootCmd.DisableAutoGenTag = true rootCmd.DisableAutoGenTag = true
rootCmd.SetOut(os.Stdout) rootCmd.SetOut(os.Stdout)
@@ -138,30 +152,28 @@ func NewRootFlags() rootFlags {
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
configureKubeconfig()
configureDefaultNamespace()
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
if err, ok := err.(*RequestError); ok {
if err.StatusCode == 1 {
logger.Warningf("%v", err)
} else {
logger.Failuref("%v", err)
}
os.Exit(err.StatusCode)
}
logger.Failuref("%v", err) logger.Failuref("%v", err)
os.Exit(1) os.Exit(1)
} }
} }
func configureKubeconfig() {
switch {
case len(rootArgs.kubeconfig) > 0:
case len(os.Getenv("KUBECONFIG")) > 0:
rootArgs.kubeconfig = os.Getenv("KUBECONFIG")
default:
if home := homeDir(); len(home) > 0 {
rootArgs.kubeconfig = filepath.Join(home, ".kube", "config")
}
}
}
func configureDefaultNamespace() { func configureDefaultNamespace() {
*kubeconfigArgs.Namespace = rootArgs.defaults.Namespace
fromEnv := os.Getenv("FLUX_SYSTEM_NAMESPACE") fromEnv := os.Getenv("FLUX_SYSTEM_NAMESPACE")
if fromEnv != "" && rootArgs.namespace == rootArgs.defaults.Namespace { if fromEnv != "" {
rootArgs.namespace = fromEnv kubeconfigArgs.Namespace = &fromEnv
} }
} }

View File

@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e // +build e2e
/* /*
@@ -35,7 +36,7 @@ func TestMain(m *testing.M) {
if err != nil { if err != nil {
panic(fmt.Errorf("error creating kube manager: '%w'", err)) panic(fmt.Errorf("error creating kube manager: '%w'", err))
} }
rootArgs.kubeconfig = testEnv.kubeConfigPath kubeconfigArgs.KubeConfig = &testEnv.kubeConfigPath
// Install Flux. // Install Flux.
output, err := executeCommand("install --components-extra=image-reflector-controller,image-automation-controller") output, err := executeCommand("install --components-extra=image-reflector-controller,image-automation-controller")
@@ -54,7 +55,7 @@ func TestMain(m *testing.M) {
// Delete namespace and wait for finalisation // Delete namespace and wait for finalisation
kubectlArgs := []string{"delete", "namespace", "flux-system"} kubectlArgs := []string{"delete", "namespace", "flux-system"}
_, err = utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...) _, err = utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, kubectlArgs...)
if err != nil { if err != nil {
panic(fmt.Errorf("delete namespace error:'%w'", err)) panic(fmt.Errorf("delete namespace error:'%w'", err))
} }
@@ -66,13 +67,13 @@ func TestMain(m *testing.M) {
func setupTestNamespace(namespace string) (func(), error) { func setupTestNamespace(namespace string) (func(), error) {
kubectlArgs := []string{"create", "namespace", namespace} kubectlArgs := []string{"create", "namespace", namespace}
_, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...) _, err := utils.ExecKubectlCommand(context.TODO(), utils.ModeStderrOS, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, kubectlArgs...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return func() { return func() {
kubectlArgs := []string{"delete", "namespace", namespace} kubectlArgs := []string{"delete", "namespace", namespace}
utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...) utils.ExecKubectlCommand(context.TODO(), utils.ModeCapture, *kubeconfigArgs.KubeConfig, *kubeconfigArgs.Context, kubectlArgs...)
}, nil }, nil
} }

View File

@@ -49,8 +49,8 @@ func allocateNamespace(prefix string) string {
return fmt.Sprintf("%s-%d", prefix, id) return fmt.Sprintf("%s-%d", prefix, id)
} }
func readYamlObjects(rdr io.Reader) ([]unstructured.Unstructured, error) { func readYamlObjects(rdr io.Reader) ([]*unstructured.Unstructured, error) {
objects := []unstructured.Unstructured{} objects := []*unstructured.Unstructured{}
reader := k8syaml.NewYAMLReader(bufio.NewReader(rdr)) reader := k8syaml.NewYAMLReader(bufio.NewReader(rdr))
for { for {
doc, err := reader.Read() doc, err := reader.Read()
@@ -65,7 +65,7 @@ func readYamlObjects(rdr io.Reader) ([]unstructured.Unstructured, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
objects = append(objects, *unstructuredObj) objects = append(objects, unstructuredObj)
} }
return objects, nil return objects, nil
} }
@@ -96,7 +96,7 @@ func (m *testEnvKubeManager) CreateObjectFile(objectFile string, templateValues
} }
} }
func (m *testEnvKubeManager) CreateObjects(clientObjects []unstructured.Unstructured, t *testing.T) error { func (m *testEnvKubeManager) CreateObjects(clientObjects []*unstructured.Unstructured, t *testing.T) error {
for _, obj := range clientObjects { for _, obj := range clientObjects {
// First create the object then set its status if present in the // First create the object then set its status if present in the
// yaml file. Make a copy first since creating an object may overwrite // yaml file. Make a copy first since creating an object may overwrite
@@ -107,7 +107,7 @@ func (m *testEnvKubeManager) CreateObjects(clientObjects []unstructured.Unstruct
return err return err
} }
obj.SetResourceVersion(createObj.GetResourceVersion()) obj.SetResourceVersion(createObj.GetResourceVersion())
err = m.client.Status().Update(context.Background(), &obj) err = m.client.Status().Update(context.Background(), obj)
if err != nil { if err != nil {
return err return err
} }
@@ -115,6 +115,36 @@ func (m *testEnvKubeManager) CreateObjects(clientObjects []unstructured.Unstruct
return nil return nil
} }
func (m *testEnvKubeManager) DeleteObjectFile(objectFile string, templateValues map[string]string, t *testing.T) {
buf, err := os.ReadFile(objectFile)
if err != nil {
t.Fatalf("Error reading file '%s': %v", objectFile, err)
}
content, err := executeTemplate(string(buf), templateValues)
if err != nil {
t.Fatalf("Error evaluating template file '%s': '%v'", objectFile, err)
}
clientObjects, err := readYamlObjects(strings.NewReader(content))
if err != nil {
t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err)
}
err = m.DeleteObjects(clientObjects, t)
if err != nil {
t.Logf("Error deleting test objects: '%v'", err)
}
}
func (m *testEnvKubeManager) DeleteObjects(clientObjects []*unstructured.Unstructured, t *testing.T) error {
for _, obj := range clientObjects {
err := m.client.Delete(context.Background(), obj)
if err != nil {
return err
}
}
return nil
}
func (m *testEnvKubeManager) Stop() error { func (m *testEnvKubeManager) Stop() error {
if m.testEnv == nil { if m.testEnv == nil {
return fmt.Errorf("do nothing because testEnv is nil") return fmt.Errorf("do nothing because testEnv is nil")
@@ -295,6 +325,12 @@ type cmdTestCase struct {
func (cmd *cmdTestCase) runTestCmd(t *testing.T) { func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
actual, testErr := executeCommand(cmd.args) actual, testErr := executeCommand(cmd.args)
// If the cmd error is a change, discard it
if isChangeError(testErr) {
testErr = nil
}
if assertErr := cmd.assert(actual, testErr); assertErr != nil { if assertErr := cmd.assert(actual, testErr); assertErr != nil {
t.Error(assertErr) t.Error(assertErr)
} }
@@ -336,3 +372,12 @@ func resetCmdArgs() {
getArgs = GetFlags{} getArgs = GetFlags{}
secretGitArgs = NewSecretGitFlags() secretGitArgs = NewSecretGitFlags()
} }
func isChangeError(err error) bool {
if reqErr, ok := err.(*RequestError); ok {
if strings.Contains(err.Error(), "identified at least one change, exiting with non-zero exit code") && reqErr.StatusCode == 1 {
return true
}
}
return false
}

View File

@@ -1,3 +1,4 @@
//go:build unit
// +build unit // +build unit
/* /*
@@ -42,7 +43,8 @@ func TestMain(m *testing.M) {
panic(fmt.Errorf("error creating kube manager: '%w'", err)) panic(fmt.Errorf("error creating kube manager: '%w'", err))
} }
testEnv = km testEnv = km
rootArgs.kubeconfig = testEnv.kubeConfigPath // rootArgs.kubeconfig = testEnv.kubeConfigPath
kubeconfigArgs.KubeConfig = &testEnv.kubeConfigPath
// Run tests // Run tests
code := m.Run() code := m.Run()

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"
@@ -75,13 +76,13 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
@@ -94,8 +95,9 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended") return fmt.Errorf("resource is suspended")
} }
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.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)
@@ -142,21 +144,25 @@ func reconciliationHandled(ctx context.Context, kubeClient client.Client,
} }
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)
}) })
} }

View File

@@ -54,17 +54,17 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
logger.Actionf("annotating Provider %s in %s namespace", name, rootArgs.namespace) logger.Actionf("annotating Provider %s in %s namespace", name, *kubeconfigArgs.Namespace)
var alertProvider notificationv1.Provider var alertProvider notificationv1.Provider
err = kubeClient.Get(ctx, namespacedName, &alertProvider) err = kubeClient.Get(ctx, namespacedName, &alertProvider)
if err != nil { if err != nil {

View File

@@ -54,13 +54,13 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
@@ -74,7 +74,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("resource is suspended") return fmt.Errorf("resource is suspended")
} }
logger.Actionf("annotating Receiver %s in %s namespace", name, rootArgs.namespace) logger.Actionf("annotating Receiver %s in %s namespace", name, *kubeconfigArgs.Namespace)
if receiver.Annotations == nil { if receiver.Annotations == nil {
receiver.Annotations = map[string]string{ receiver.Annotations = map[string]string{
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano), meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),

View File

@@ -36,13 +36,13 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: rootArgs.namespace, Namespace: *kubeconfigArgs.Namespace,
Name: name, Name: name,
} }
@@ -57,21 +57,22 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
if reconcile.object.reconcileSource() { if reconcile.object.reconcileSource() {
reconcileCmd, nsName := reconcile.object.getSource() reconcileCmd, nsName := reconcile.object.getSource()
nsCopy := rootArgs.namespace nsCopy := *kubeconfigArgs.Namespace
if nsName.Namespace != "" { if nsName.Namespace != "" {
rootArgs.namespace = nsName.Namespace *kubeconfigArgs.Namespace = nsName.Namespace
} }
err := reconcileCmd.run(nil, []string{nsName.Name}) err := reconcileCmd.run(nil, []string{nsName.Name})
if err != nil { if err != nil {
return err return err
} }
rootArgs.namespace = nsCopy *kubeconfigArgs.Namespace = nsCopy
} }
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest() lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.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)

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,11 +44,14 @@ 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)
} }
type resumable interface { type resumable interface {
adapter adapter
copyable
statusable statusable
setUnsuspended() setUnsuspended()
successMessage() string successMessage() string
@@ -72,13 +76,13 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
var listOpts []client.ListOption var listOpts []client.ListOption
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace)) listOpts = append(listOpts, client.InNamespace(*kubeconfigArgs.Namespace))
if len(args) > 0 { if len(args) > 0 {
listOpts = append(listOpts, client.MatchingFields{ listOpts = append(listOpts, client.MatchingFields{
"metadata.name": args[0], "metadata.name": args[0],
@@ -91,31 +95,36 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
} }
if resume.list.len() == 0 { if resume.list.len() == 0 {
logger.Failuref("no %s objects found in %s namespace", resume.kind, rootArgs.namespace) logger.Failuref("no %s objects found in %s namespace", resume.kind, *kubeconfigArgs.Namespace)
return nil return nil
} }
for i := 0; i < resume.list.len(); i++ { for i := 0; i < resume.list.len(); i++ {
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), rootArgs.namespace) logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, resume.list.resumeItem(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
resume.list.resumeItem(i).setUnsuspended() obj := resume.list.resumeItem(i)
if err := kubeClient.Update(ctx, resume.list.resumeItem(i).asClientObject()); err != nil { patch := client.MergeFrom(obj.deepCopyClientObject())
obj.setUnsuspended()
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
return err return err
} }
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: rootArgs.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

@@ -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

@@ -69,11 +69,11 @@ func isReady(ctx context.Context, kubeClient client.Client,
func buildComponentObjectRefs(components ...string) ([]object.ObjMetadata, error) { func buildComponentObjectRefs(components ...string) ([]object.ObjMetadata, error) {
var objRefs []object.ObjMetadata var objRefs []object.ObjMetadata
for _, deployment := range components { for _, deployment := range components {
objMeta, err := object.CreateObjMetadata(rootArgs.namespace, deployment, schema.GroupKind{Group: "apps", Kind: "Deployment"}) objRefs = append(objRefs, object.ObjMetadata{
if err != nil { Namespace: *kubeconfigArgs.Namespace,
return nil, err Name: deployment,
} GroupKind: schema.GroupKind{Group: "apps", Kind: "Deployment"},
objRefs = append(objRefs, objMeta) })
} }
return objRefs, nil return objRefs, nil
} }

View File

@@ -46,6 +46,7 @@ func init() {
type suspendable interface { type suspendable interface {
adapter adapter
copyable
isSuspended() bool isSuspended() bool
setSuspended() setSuspended()
} }
@@ -69,13 +70,13 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel() defer cancel()
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) kubeClient, err := utils.KubeClient(kubeconfigArgs)
if err != nil { if err != nil {
return err return err
} }
var listOpts []client.ListOption var listOpts []client.ListOption
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace)) listOpts = append(listOpts, client.InNamespace(*kubeconfigArgs.Namespace))
if len(args) > 0 { if len(args) > 0 {
listOpts = append(listOpts, client.MatchingFields{ listOpts = append(listOpts, client.MatchingFields{
"metadata.name": args[0], "metadata.name": args[0],
@@ -88,14 +89,17 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
} }
if suspend.list.len() == 0 { if suspend.list.len() == 0 {
logger.Failuref("no %s objects found in %s namespace", suspend.kind, rootArgs.namespace) logger.Failuref("no %s objects found in %s namespace", suspend.kind, *kubeconfigArgs.Namespace)
return nil return nil
} }
for i := 0; i < suspend.list.len(); i++ { for i := 0; i < suspend.list.len(); i++ {
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), rootArgs.namespace) logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, suspend.list.item(i).asClientObject().GetName(), *kubeconfigArgs.Namespace)
suspend.list.item(i).setSuspended()
if err := kubeClient.Update(ctx, suspend.list.item(i).asClientObject()); err != nil { obj := suspend.list.item(i)
patch := client.MergeFrom(obj.deepCopyClientObject())
obj.setSuspended()
if err := kubeClient.Patch(ctx, obj.asClientObject(), patch); err != nil {
return err return err
} }
logger.Successf("%s suspended", suspend.humanKind) logger.Successf("%s suspended", suspend.humanKind)

View File

@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: podinfo
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: podinfo
spec:
containers:
- name: podinfod
image: ghcr.io/stefanprodan/podinfo:6.0.3
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi

View File

@@ -0,0 +1,20 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: podinfo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
minReplicas: 2
maxReplicas: 4
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
# scale up if usage is above
# 99% of the requested CPU (100m)
averageUtilization: 99

View File

@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml
- ./hpa.yaml

View File

@@ -0,0 +1,15 @@
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
interval: 5m0s
path: ./kustomize
force: true
prune: true
sourceRef:
kind: GitRepository
name: podinfo
targetNamespace: default

View File

@@ -0,0 +1,173 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: default
spec:
minReadySeconds: 3
progressDeadlineSeconds: 60
revisionHistoryLimit: 5
selector:
matchLabels:
app: podinfo
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "9797"
prometheus.io/scrape: "true"
labels:
app: podinfo
spec:
containers:
- command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: '#34577c'
image: ghcr.io/stefanprodan/podinfo:6.0.10
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
name: podinfod
ports:
- containerPort: 9898
name: http
protocol: TCP
- containerPort: 9797
name: http-metrics
protocol: TCP
- containerPort: 9999
name: grpc
protocol: TCP
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi
---
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: default
spec:
maxReplicas: 4
metrics:
- resource:
name: cpu
target:
averageUtilization: 99
type: Utilization
type: Resource
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
---
apiVersion: v1
kind: Service
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: default
spec:
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- name: grpc
port: 9999
protocol: TCP
targetPort: grpc
selector:
app: podinfo
type: ClusterIP
---
apiVersion: v1
data:
.dockerconfigjson: eyJtYXNrIjoiKipTT1BTKioifQ==
kind: Secret
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: docker-secret
namespace: default
type: kubernetes.io/dockerconfigjson
---
apiVersion: v1
kind: Secret
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: secret-basic-auth-stringdata
namespace: default
stringData:
password: '**SOPS**'
username: '**SOPS**'
type: kubernetes.io/basic-auth
---
apiVersion: v1
data:
token: KipTT1BTKio=
kind: Secret
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo-token-77t89m9b67
namespace: default
type: Opaque
---
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: db-user-pass-bkbd782d2c
namespace: default
type: Opaque

View File

@@ -0,0 +1,16 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ .fluxns }}
---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
name: podinfo
namespace: {{ .fluxns }}
spec:
interval: 30s
ref:
branch: master
url: https://github.com/stefanprodan/podinfo

View File

@@ -0,0 +1,101 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: default
spec:
minReadySeconds: 3
progressDeadlineSeconds: 60
revisionHistoryLimit: 5
selector:
matchLabels:
app: podinfo
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
annotations:
prometheus.io/port: "9797"
prometheus.io/scrape: "true"
labels:
app: podinfo
spec:
containers:
- command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: '#34577c'
image: ghcr.io/stefanprodan/podinfo:6.0.3
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
name: podinfod
ports:
- containerPort: 9898
name: http
protocol: TCP
- containerPort: 9797
name: http-metrics
protocol: TCP
- containerPort: 9999
name: grpc
protocol: TCP
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi
---
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: default
spec:
maxReplicas: 4
metrics:
- resource:
name: cpu
target:
averageUtilization: 99
type: Utilization
type: Resource
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo

View File

@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: podinfo
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: podinfo
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: podinfo
spec:
containers:
- name: podinfod
image: ghcr.io/stefanprodan/podinfo:6.0.10
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi

View File

@@ -0,0 +1,27 @@
apiVersion: v1
data:
.dockerconfigjson: ENC[AES256_GCM,data:KHCFH3hNnc+PMfWLFEPjebf3W4z4WXbGFAANRZyZC+07z7wlrTALJM6rn8YslW4tMAWCoAYxblC5WRCszTy0h9rw0U/RGOv5H0qCgnNg/FILFUqhwo9pNfrUH+MEP4M9qxxbLKZwObpHUE7DUsKx1JYAxsI=,iv:q48lqUbUQD+0cbYcjNMZMJLRdGHi78ZmDhNAT2th9tg=,tag:QRI2SZZXQrAcdql3R5AH2g==,type:str]
kind: Secret
metadata:
name: docker-secret
type: kubernetes.io/dockerconfigjson
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3eU1CTEJhVXZ4eEVYYkVV
OU90TEcrR2pYckttN0pBanJoSUZWSW1RQXlRCkUydFJ3V1NZUTBuVFF0aC9GUEcw
bUdhNjJWTkoyL1FUVi9Dc1dxUDBkM0UKLS0tIE1sQXkwcWdGaEFuY0RHQTVXM0J6
dWpJcThEbW15V3dXYXpPZklBdW1Hd1kKoIAdmGNPrEctV8h1w8KuvQ5S+BGmgqN9
MgpNmUhJjWhgcQpb5BRYpQesBOgU5TBGK7j58A6DMDKlSiYZsdQchQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2022-02-03T16:03:17Z"
mac: ENC[AES256_GCM,data:AHdYSawajwgAFwlmDN1IPNmT9vWaYKzyVIra2d6sPcjTbZ8/p+VRSRpVm4XZFFsaNnW5AUJaouwXnKYDTmJDXKlr/rQcu9kXqsssQgdzcXaA6l5uJlgsnml8ba7J3OK+iEKMax23mwQEx2EUskCd9ENOwFDkunP02sxqDNOz20k=,iv:8F5OamHt3fAVorf6p+SoIrWoqkcATSGWVoM0EK87S4M=,tag:E1mxXnc7wWkEX5BxhpLtng==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.1

View File

@@ -0,0 +1,20 @@
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: podinfo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
minReplicas: 2
maxReplicas: 4
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
# scale up if usage is above
# 99% of the requested CPU (100m)
averageUtilization: 99

View File

@@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./deployment.yaml
- ./hpa.yaml
- ./service.yaml
- ./dockerconfigjson-sops-secret.yaml
- ./stringdata-secret.yaml
secretGenerator:
- files:
- token=token.encrypted
name: podinfo-token
- literals:
- username=admin
- password=1f2d1e2e67df
name: db-user-pass

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: podinfo
spec:
type: ClusterIP
selector:
app: podinfo
ports:
- name: http
port: 9898
protocol: TCP
targetPort: http
- port: 9999
targetPort: grpc
protocol: TCP
name: grpc

View File

@@ -0,0 +1,28 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth-stringdata
type: kubernetes.io/basic-auth
stringData:
username: ENC[AES256_GCM,data:uKiQR48=,iv:jh2lgyAVu7igJAgoJsnOGhjxFyvUAa9lvT21u3hhqpU=,tag:zXM2JEpk3ZEH7WfkcWXXkw==,type:str]
password: ENC[AES256_GCM,data:PyhZmNhy929JGQ==,iv:PBqPaJmSw21+kn4gIlg5VdjLNZyf613z5RUTCesBoVw=,tag:Hjc7DsuUrtsz7PYPdNkL3g==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJd0xxbDZhYjVoZzY4YWhK
d2NvMVgrSGRVUGhHRGg3R1FpVURnbmh1TDBzCjcwby85M3JaK09QVk0yZFNMb2NL
c2NQZW5hS1FhYlBHU0VoUzBVYzZYUUUKLS0tIEdaNEw2Y0VjVHpZc3pyYUtLVmJk
NmN3K2VLU0NiZ1d0VHBYbGlCM1lrNmMKeWz3yfFbMNE+ly21oLfc1XnDSPRmnlPP
wIs8lk/qrzVZ45C9GdWnnPeGZZiia46Yop9TxseUS8gCjJ6KCxJCAg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2022-02-06T12:51:07Z"
mac: ENC[AES256_GCM,data:jtdzwj19uxdxvnmXg1HkAkDA6XlKMJOYFy7uLI5t/t11LwGop5Yeo7a4nQEEELehRx9J7B6U6NiySxAxBxWx5uW5vI5c8+069VV6dkiCIefnYSzuoIhQafjlFl1/KvH7VEjIWfHYuXF09v9PEKXkxEHUYDpS3QqQ3ymHRRI08pU=, iv:xX3E7F+AM29Pm8G5oqxRfYu9E7tEBGIaHeCJYgrtFmc=,tag:MJPGusNvu05z939jg8PAwQ==,type:str]
pgp: []
encrypted_regex: ^(data|stringData)$
version: 3.7.1

View File

@@ -0,0 +1,20 @@
{
"data": "ENC[AES256_GCM,data:oBe5PlPmfQCUUc4sqKImjw==,iv:MLLEW15QC9kRdVVagJnzLCSk0xZGWIpAeTfHzyxT10g=,tag:K3GkBCGS+ut4Tpk6ndb0CA==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"azure_kv": null,
"hc_vault": null,
"age": [
{
"recipient": "age10la2ge0wtvx3qr7datqf7rs4yngxszdal927fs9rukamr8u2pshsvtz7ce",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+ IFgyNTUxOSA1L2RpZHRrK1FSVmYrd1Va\nY0hxWFQzSDBsT1k3WjNtYmU1QmliaDJycXlNCnF1YjdNOThVbVNvMG9rNS9ZUXZw\nMnV0bnRUMGNtejFPbzM4U2UzWkszeVkKLS0tIGJ6UGhxMUV3YmVJTHlJSUJpRVRZ\nVjd0RVRadU8wekxXTHIrYUplYkN2aEEK0I/ MCEtXRk+b/N2G1JF3vHQT24dShWYD\nw+JIUSA3aLf2sv0zr2MdUEdVWBJoM8nT4D4xVbBORD+669W+9nDeSw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2021-11-26T16:34:51Z",
"mac": "ENC[AES256_GCM,data:COGzf5YCHNNP6z4JaEKrjN3M8f5+Q1uKUKTMHwj388/ICmLyi2sSrTmj7PP+X7M9jTVwa8wVgYTpNLiVJx+LcxqvIXM0Tyo+/Cu1zrfao98aiACP8+TSEDiFQNtEus23H+d/X1hqMwRHDI3kQ+ 6scgEGnqY57r3RDSA3E8EhHr4=,iv:LxitVIYm8srZVqFueJh9loClA44Y2Z3XAVYmxesMmOg=,tag:Y8qFD8UGlDfwNSv7xlcn6A==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.7.1"
}
}

View File

@@ -1,3 +1,3 @@
► checking prerequisites ► checking prerequisites
✔ Kubernetes {{ .serverVersion }} >=1.19.0-0 ✔ Kubernetes {{ .serverVersion }} >=1.20.6-0
✔ prerequisites checks passed ✔ prerequisites checks passed

View File

@@ -0,0 +1,78 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
kustomize.toolkit.fluxcd.io/name: podinfo
kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo
namespace: default
spec:
minReadySeconds: 3
revisionHistoryLimit: 5
progressDeadlineSeconds: 60
strategy:
rollingUpdate:
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: podinfo
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9797"
labels:
app: podinfo
spec:
containers:
- name: podinfod
image: ghcr.io/stefanprodan/podinfo:6.0.10
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9898
protocol: TCP
- name: http-metrics
containerPort: 9797
protocol: TCP
- name: grpc
containerPort: 9999
protocol: TCP
command:
- ./podinfo
- --port=9898
- --port-metrics=9797
- --grpc-port=9999
- --grpc-service-name=podinfo
- --level=info
- --random-delay=false
- --random-error=false
env:
- name: PODINFO_UI_COLOR
value: "#34577c"
livenessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/healthz
initialDelaySeconds: 5
timeoutSeconds: 5
readinessProbe:
exec:
command:
- podcli
- check
- http
- localhost:9898/readyz
initialDelaySeconds: 5
timeoutSeconds: 5
resources:
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 100m
memory: 64Mi

View File

@@ -0,0 +1,6 @@
► HorizontalPodAutoscaler/default/podinfo created
► Service/default/podinfo created
► Secret/default/docker-secret created
► Secret/default/secret-basic-auth-stringdata created
► Secret/default/podinfo-token-77t89m9b67 created
► Secret/default/db-user-pass-bkbd782d2c created

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