1
0
mirror of synced 2026-03-01 11:16:56 +00:00

Compare commits

...

237 Commits

Author SHA1 Message Date
Matheus Pimenta
4a15fa6a02 Merge pull request #5579 from fluxcd/backport-5578-to-release/v2.7.x
[release/v2.7.x] Update toolkit components
2025-10-08 18:59:52 +01:00
fluxcdbot
6adffe74c4 Update toolkit components
- helm-controller to v1.4.2
  https://github.com/fluxcd/helm-controller/blob/v1.4.2/CHANGELOG.md
- kustomize-controller to v1.7.1
  https://github.com/fluxcd/kustomize-controller/blob/v1.7.1/CHANGELOG.md
- source-controller to v1.7.2
  https://github.com/fluxcd/source-controller/blob/v1.7.2/CHANGELOG.md
- notification-controller to v1.7.3
  https://github.com/fluxcd/notification-controller/blob/v1.7.3/CHANGELOG.md
- image-reflector-controller to v1.0.2
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.2/CHANGELOG.md
- image-automation-controller to v1.0.2
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.2/CHANGELOG.md
- source-watcher to v2.0.2
  https://github.com/fluxcd/source-watcher/blob/v2.0.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
(cherry picked from commit 058525fe37)
2025-10-08 17:53:43 +00:00
Matheus Pimenta
e8213d75a6 Merge pull request #5577 from fluxcd/backport-5576-to-release/v2.7.x
[release/v2.7.x] Update dependencies to Kubernetes v1.34.1 and Go 1.25.2
2025-10-08 17:41:42 +01:00
Stefan Prodan
ddd9ef9d13 Update dependencies to Kubernetes v1.34.1 and Go 1.25.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
(cherry picked from commit 767f235f94)
2025-10-08 16:26:27 +00:00
Stefan Prodan
f3cc58037a Merge pull request #5575 from fluxcd/backport-5574-to-release/v2.7.x
[release/v2.7.x] Fix manifest generation for `--storage-adv-addr` and `--events-addr` flags
2025-10-08 11:43:13 +03:00
Stefan Prodan
bb9b4e8533 Use RUNTIME_NAMESPACE when setting --events-addr
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
(cherry picked from commit f2ff083b8e)
2025-10-08 07:59:54 +00:00
Stefan Prodan
6bb4aeff95 Fix --storage-adv-addr for source-watcher
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
(cherry picked from commit 8c45f25f33)
2025-10-08 07:59:54 +00:00
Stefan Prodan
ca29bb1a41 Merge pull request #5571 from fluxcd/backport-5570-to-release/v2.7.x
[release/v2.7.x] Disable AUR publishing
2025-10-06 18:47:00 +03:00
Stefan Prodan
c707c3ae7b Disable AUR publishing
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
(cherry picked from commit 71a3dad213)
2025-10-06 15:46:17 +00:00
Matheus Pimenta
53552c8816 Merge pull request #5569 from fluxcd/backport-5568-to-release/v2.7.x
[release/v2.7.x] Update toolkit components
2025-10-06 12:56:14 +01:00
fluxcdbot
fb8f2508d1 Update toolkit components
- helm-controller to v1.4.1
  https://github.com/fluxcd/helm-controller/blob/v1.4.1/CHANGELOG.md
- source-controller to v1.7.1
  https://github.com/fluxcd/source-controller/blob/v1.7.1/CHANGELOG.md
- notification-controller to v1.7.2
  https://github.com/fluxcd/notification-controller/blob/v1.7.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
(cherry picked from commit 4f2d1c3a2a)
2025-10-06 11:55:26 +00:00
Matheus Pimenta
de92e95a50 Merge pull request #5564 from fluxcd/backport-5563-to-release/v2.7.x
[release/v2.7.x] Fix `flux migrate -f` not considering kind comments
2025-10-04 16:34:21 +01:00
Matheus Pimenta
b398208c7e Fix flux migrate -f not considering kind comments
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
(cherry picked from commit 7c5fb2297c)
2025-10-04 15:33:47 +00:00
Matheus Pimenta
8d0001f5b6 Merge pull request #5561 from fluxcd/backport-5560-to-release/v2.7.x
[release/v2.7.x] Fix `flux migrate -f` command to work with comments
2025-10-03 15:46:16 +01:00
Matheus Pimenta
a2ff6c601e Fix migrate -f command to work with comments
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
(cherry picked from commit 83213ce83f)
2025-10-03 14:45:24 +00:00
Stefan Prodan
4accd37c1a Merge pull request #5559 from fluxcd/backport-5558-to-release/v2.7.x
[release/v2.7.x] Improve `flux migrate` for live cluster migrations
2025-10-03 16:53:50 +03:00
Stefan Prodan
742baa62d1 Improve flux migrate for live cluster migrations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
(cherry picked from commit 0255957dd7)
2025-10-03 13:52:54 +00:00
Stefan Prodan
784a62c6a5 Merge pull request #5557 from fluxcd/backport-5554-to-release/v2.7.x
[release/v2.7.x] Extend `flux migrate` to work with local files
2025-10-03 11:56:56 +03:00
Matheus Pimenta
0bcccb2482 Extend flux migrate to work with local files
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
(cherry picked from commit a9b5be7ff4)
2025-10-03 08:50:00 +00:00
Matheus Pimenta
17dae751a2 Merge pull request #5553 from fluxcd/backport-5551-to-release/v2.7.x
[release/v2.7.x] Fix `flux push artifact` not working with `--provider`
2025-10-01 10:51:22 +01:00
Matheus Pimenta
93a87240b0 Fix flux push artifact not working with --provider
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
(cherry picked from commit 039d79b3c2)
2025-10-01 09:39:54 +00:00
Stefan Prodan
9c66b0d752 Merge pull request #5552 from fluxcd/backport-ci-prs
Backport CI fixes and updates
2025-10-01 11:47:26 +03:00
dependabot[bot]
9fc6853024 build(deps): bump the ci group across 1 directory with 3 updates
Bumps the ci group with 3 updates in the / directory: [docker/login-action](https://github.com/docker/login-action), [ossf/scorecard-action](https://github.com/ossf/scorecard-action) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `docker/login-action` from 3.5.0 to 3.6.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](184bdaa072...5e57cd1181)

Updates `ossf/scorecard-action` from 2.4.2 to 2.4.3
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](05b42c6244...4eaacf0543)

Updates `github/codeql-action` from 3.30.3 to 3.30.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](192325c861...3599b3baa1)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.30.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 09:35:06 +01:00
Stefan Prodan
22a8310b0a ci: Set GITHUB_TOKEN in the release-flux-manifests workflow
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-10-01 09:34:46 +01:00
Matheus Pimenta
f251e8e8a9 Merge pull request #5509 from RussellAult/action-without-api
`fluxcd/flux2/action`: Determine latest version without using GitHub API
2025-09-30 07:23:03 +01:00
RussellAult
44f0d50dbf fluxcd/flux2/action: Determine latest version without using GitHub API
Signed-off-by: RussellAult <RussellAult@users.noreply.github.com>
Co-authored-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-30 07:19:32 +01:00
Matheus Pimenta
4664d49e29 Merge pull request #5542 from fluxcd/update-components
Update image-automation-controller to v1.0.1
2025-09-28 21:12:32 +01:00
fluxcdbot
2997645ea3 Update toolkit components
- image-automation-controller to v1.0.1
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-09-28 19:59:27 +00:00
Matheus Pimenta
3247a46654 Merge pull request #5541 from fluxcd/debug-ks-history
Add `--show-history` flag to `debug kustomization`
2025-09-26 11:04:46 +01:00
Matheus Pimenta
b5ecb9bc56 Add --show-history flag to debug kustomization
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-26 10:01:31 +01:00
Stefan Prodan
550260638d Merge pull request #5540 from fluxcd/update-components
Update source-watcher to v2.0.1
2025-09-26 11:16:34 +03:00
fluxcdbot
b52d76d6e6 Update toolkit components
- source-watcher to v2.0.1
  https://github.com/fluxcd/source-watcher/blob/v2.0.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-09-26 07:56:24 +00:00
Matheus Pimenta
95b2d855cb Merge pull request #5539 from fluxcd/no-cron-for-update
ci: remove cron schedule from update
2025-09-25 16:59:54 +01:00
Matheus Pimenta
52e0c9815b ci: remove cron schedule from update
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-25 16:48:33 +01:00
Stefan Prodan
154069893b Merge pull request #5537 from fluxcd/update-components
Update toolkit components
2025-09-25 18:45:37 +03:00
Stefan Prodan
6185366b8a Migrate create commands to DependencyReference type
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-25 18:22:08 +03:00
fluxcdbot
f7665f4b47 Update toolkit components
- helm-controller to v1.4.0
  https://github.com/fluxcd/helm-controller/blob/v1.4.0/CHANGELOG.md
- kustomize-controller to v1.7.0
  https://github.com/fluxcd/kustomize-controller/blob/v1.7.0/CHANGELOG.md
- notification-controller to v1.7.1
  https://github.com/fluxcd/notification-controller/blob/v1.7.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-09-25 15:06:43 +00:00
Stefan Prodan
b20eb0ca22 Merge pull request #5534 from prasad89/issue#5526
Add support for custom storage namespace in HelmRelease creation
2025-09-24 21:45:08 +03:00
prasad89
8000a41015 Add support for custom storage namespace in HelmRelease creation
Signed-off-by: prasad89 <vdbhaleraovb@gmail.com>
2025-09-24 21:46:06 +05:30
Stefan Prodan
4601a304dd Merge pull request #5535 from fluxcd/dependabot/github_actions/ci-57db20d2cc
build(deps): bump the ci group with 6 updates
2025-09-24 12:49:56 +03:00
dependabot[bot]
2fc09963e8 build(deps): bump the ci group with 6 updates
Bumps the ci group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [fluxcd/gha-workflows](https://github.com/fluxcd/gha-workflows) | `0.3.0` | `0.4.0` |
| [actions/setup-go](https://github.com/actions/setup-go) | `5.5.0` | `6.0.0` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.20.0` | `1.22.0` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.29.11` | `3.30.3` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.20.5` | `0.20.6` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.9.2` | `3.10.0` |


Updates `fluxcd/gha-workflows` from 0.3.0 to 0.4.0
- [Release notes](https://github.com/fluxcd/gha-workflows/releases)
- [Commits](https://github.com/fluxcd/gha-workflows/compare/v0.3.0...v0.4.0)

Updates `actions/setup-go` from 5.5.0 to 6.0.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](d35c59abb0...4469467582)

Updates `fluxcd/pkg` from 1.20.0 to 1.22.0
- [Commits](7f090e9313...bf02f0a2d6)

Updates `github/codeql-action` from 3.29.11 to 3.30.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](3c3833e0f8...192325c861)

Updates `anchore/sbom-action` from 0.20.5 to 0.20.6
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](da167eac91...f8bdd1d8ac)

Updates `sigstore/cosign-installer` from 3.9.2 to 3.10.0
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](d58896d6a1...d7543c93d8)

---
updated-dependencies:
- dependency-name: fluxcd/gha-workflows
  dependency-version: 0.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: actions/setup-go
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.30.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-24 09:37:59 +00:00
Stefan Prodan
a2b4edc2f3 Merge pull request #5533 from fluxcd/conform-k8s-1.34.1
Set Kubernetes 1.32 as min supported version
2025-09-24 11:11:25 +03:00
Stefan Prodan
55bb3fe643 Set Kubernetes 1.32 as min supported version
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-24 10:39:53 +03:00
Stefan Prodan
7060770258 Merge pull request #5532 from fluxcd/trace-external-artifact
Add support for `ExternalArtifact` to `flux trace`
2025-09-23 16:18:20 +03:00
Stefan Prodan
c3eadad983 Add support for ExternalArtifact to flux trace
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-23 15:49:19 +03:00
Stefan Prodan
e56dfcacf2 Merge pull request #5531 from fluxcd/uninstall-artifact-generator
Remove `ArtifactGenerators` during uninstall
2025-09-23 15:10:44 +03:00
Stefan Prodan
56e73ae03c Remove ArtifactGenerators during uninstall
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-23 14:41:50 +03:00
Stefan Prodan
7a2f77ffe0 Merge pull request #5529 from fluxcd/fluxcd/gha-workflows
ci: Refactor CI with `fluxcd/gha-workflows`
2025-09-22 13:50:04 +02:00
Stefan Prodan
c1b2c7cae8 ci: Refactor CI with fluxcd/gha-workflows
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-22 14:01:38 +03:00
Stefan Prodan
79186a0055 Merge pull request #5528 from fluxcd/diff-force
Handle `force: enabled` annotation in `flux diff ks` command
2025-09-22 12:55:04 +02:00
Stefan Prodan
e7f1faea01 Handle force: enabled annotation in flux diff ks command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-22 13:11:43 +03:00
Matheus Pimenta
74edb12bd1 Merge pull request #5492 from lukas8219/5411-reconcile-suspend-resume-img-policy
Implement `flux [reconcile|suspend|resume] image policy` commands
2025-09-20 04:24:31 +01:00
lukas8219
48d509d838 Implement flux [reconcile|suspend|resume] image policy commands
Signed-off-by: lukas8219 <lucas.c4d@gmail.com>
2025-09-20 00:00:10 -03:00
Matheus Pimenta
948ed45f10 Merge pull request #5525 from fluxcd/update-components
Update image-reflector-controller to v1.0.1
2025-09-20 03:31:45 +01:00
fluxcdbot
6f47ae0f2f Update toolkit components
- image-reflector-controller to v1.0.1
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-09-20 02:18:40 +00:00
Matheus Pimenta
a1f366933b Merge pull request #5522 from fluxcd/update-components
Update image-automation-controller to v1.0.0
2025-09-16 13:29:55 +01:00
fluxcdbot
99b51ad525 Update toolkit components
- image-automation-controller to v1.0.0
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-16 12:08:15 +01:00
Stefan Prodan
b6e0e8fd63 Merge pull request #5521 from fluxcd/update-source-watcher
ci: Add source-watcher to the update workflow
2025-09-16 12:08:36 +03:00
Stefan Prodan
9056ec029c ci: Add source-watcher to the update workflow
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-16 11:57:01 +03:00
Stefan Prodan
9caea521ea Merge pull request #5520 from fluxcd/artifact-generator
Add read-only commands for `ArtifactGenerator` kind
2025-09-16 11:28:34 +03:00
Stefan Prodan
a317f7c445 Add support for events --for ArtifactGenerator/<name>
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-16 11:17:27 +03:00
Stefan Prodan
698a68424f Add tree artifact generator command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-16 11:00:17 +03:00
Stefan Prodan
5556a5cc9a Add get artifact generator command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-16 11:00:12 +03:00
Stefan Prodan
c416671ec4 Add export artifact generator command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-16 11:00:12 +03:00
Stefan Prodan
f719d2bf76 Use stdout when exporting objects
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-16 11:00:12 +03:00
Stefan Prodan
46aa068fda Merge pull request #5519 from fluxcd/source-watcher
Add the source-watcher controller to the Flux distribution
2025-09-16 00:28:02 +03:00
Stefan Prodan
3542d61afd Add source-watcher to the install and bootstrap commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-15 23:59:03 +03:00
Stefan Prodan
0a87ed5a42 Add source-watcher to manifests
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-15 21:22:04 +03:00
Matheus Pimenta
e4dcc4bd5f Merge pull request #5518 from fluxcd/update-components
Update source-controller to v1.7.0
2025-09-15 18:04:28 +01:00
fluxcdbot
b4bc0d4932 Update toolkit components
- source-controller to v1.7.0
  https://github.com/fluxcd/source-controller/blob/v1.7.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-15 17:33:20 +01:00
Stefan Prodan
6cc446af00 Merge pull request #5517 from fluxcd/update-components
Update image-reflector-controller to v1.0.0
2025-09-15 15:57:50 +03:00
Matheus Pimenta
8db628cc90 Update image-reflector-controller to v1 in integration tests
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-15 13:34:36 +01:00
Matheus Pimenta
e765897df7 Update image-reflector-controller API imports to v1
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-15 13:34:32 +01:00
fluxcdbot
210b2aa458 Update toolkit components
- image-reflector-controller to v1.0.0
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-09-15 11:34:09 +00:00
Matheus Pimenta
a8e0ea495d Merge pull request #5508 from fluxcd/azure-e2e
ci: Align azure e2e tests secret names with fluxcd/pkg
2025-09-08 20:31:07 +01:00
Matheus Pimenta
8fb1ccebfa ci: Align azure e2e tests secret names with fluxcd/pkg
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-08 19:58:51 +01:00
Matheus Pimenta
664423230d Merge pull request #5507 from fluxcd/skip-rc-upd
Skip release candidates on updates
2025-09-04 19:58:11 +01:00
Matheus Pimenta
0c8cfcdc85 Skip release candidates on updates
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-09-04 19:54:33 +01:00
Matheus Pimenta
89d4467a50 Merge pull request #5505 from hawkaii/history
Add `--show-history` flag to `debug  helmrelease`
2025-09-04 14:44:37 +01:00
Parthib Mukherjee
bef6f36755 Add --show-history flag to debug helmrelease
Signed-off-by: Parthib Mukherjee <parthibmukherjee@gmail.com>
2025-09-04 12:44:28 +00:00
Stefan Prodan
6125991b78 Merge pull request #5292 from fluxcd/rfc-external-artifact
[RFC-0012] External Artifact API
2025-09-03 18:40:04 +03:00
Stefan Prodan
64bfa02db4 Add Artifact access restrictions to recommendations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 13:57:38 +03:00
Stefan Prodan
1e662e5ed9 Assign 0012 to RFC
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 01:04:08 +03:00
Stefan Prodan
df57392f48 Add Feature Gate
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 01:00:47 +03:00
Stefan Prodan
19cd02e548 Add SDK for packaging and exposing artifacts
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 01:00:35 +03:00
Stefan Prodan
8bc7822fe5 Add security considerations and recommendations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 01:00:34 +03:00
Stefan Prodan
e97da26435 Add design details to ExternalArtifact RFC
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 01:00:34 +03:00
Stefan Prodan
1a89fa419e RFC External Artifact API
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-09-03 01:00:33 +03:00
Stefan Prodan
7c0e70b9cc Merge pull request #5321 from adri1197/rfcs-opentelemetry
[RFC-0011] OpenTelemetry Tracing
2025-09-03 00:58:36 +03:00
Adrian Fernandez De La Torre
ed9ee95dbe [RFC-0011] - OpenTelemetry Tracing
Signed-off-by: Adrian Fernandez De La Torre <adri1197@gmail.com>
2025-09-01 20:37:10 +02:00
Matheus Pimenta
63a38ab228 Merge pull request #5414 from mohiuddin-khan-shiam/main
fix(events): respect `--all-namespaces` flag
2025-09-01 09:09:53 +01:00
S. M. Mohiuddin Khan Shiam
c2a883e25a fix(events): respect --all-namespaces flag
The `flux events` command always applied a namespace filter, even when `--all-namespaces` was set.
This produced incomplete results and confused users expecting cluster-wide events.

Changes made:
* Build `clientListOpts` dynamically.
* Omit `client.InNamespace(...)` when `eventArgs.allNamespaces` is true, ensuring no namespace constraint.

Impact:
`flux events --all-namespaces` now returns events from every namespace, restoring expected functionality without affecting other options.

Signed-off-by: S. M. Mohiuddin Khan Shiam <147746955+mohiuddin-khan-shiam@users.noreply.github.com>
2025-09-01 08:55:15 +01:00
Stefan Prodan
24ae50cfd5 Merge pull request #5501 from fluxcd/auto-gomaxprocs
Allow the Go runtime to dynamically set `GOMAXPROCS`
2025-09-01 10:46:29 +03:00
Stefan Prodan
0573138e38 Allow the Go runtime to dynamically set GOMAXPROCS
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-31 22:07:38 +03:00
Stefan Prodan
2f14313646 Merge pull request #5500 from fluxcd/dependabot/github_actions/ci-fe119e88f8
build(deps): bump the ci group across 1 directory with 10 updates
2025-08-30 16:55:04 +03:00
dependabot[bot]
e135336aae build(deps): bump the ci group across 1 directory with 10 updates
Bumps the ci group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4.2.2` | `5.0.0` |
| [korthout/backport-action](https://github.com/korthout/backport-action) | `3.2.1` | `3.3.0` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.19.0` | `1.20.0` |
| [google-github-actions/auth](https://github.com/google-github-actions/auth) | `2.1.10` | `3.0.0` |
| [google-github-actions/setup-gcloud](https://github.com/google-github-actions/setup-gcloud) | `2.1.4` | `3.0.1` |
| [docker/login-action](https://github.com/docker/login-action) | `3.4.0` | `3.5.0` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.29.2` | `3.29.11` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.20.2` | `0.20.5` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.9.1` | `3.9.2` |
| [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) | `6.3.0` | `6.4.0` |



Updates `actions/checkout` from 4.2.2 to 5.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08c6903cd8)

Updates `korthout/backport-action` from 3.2.1 to 3.3.0
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](0193454f0c...ca4972adce)

Updates `fluxcd/pkg` from 1.19.0 to 1.20.0
- [Commits](9e79277372...7f090e9313)

Updates `google-github-actions/auth` from 2.1.10 to 3.0.0
- [Release notes](https://github.com/google-github-actions/auth/releases)
- [Changelog](https://github.com/google-github-actions/auth/blob/main/CHANGELOG.md)
- [Commits](ba79af0395...7c6bc770da)

Updates `google-github-actions/setup-gcloud` from 2.1.4 to 3.0.1
- [Release notes](https://github.com/google-github-actions/setup-gcloud/releases)
- [Changelog](https://github.com/google-github-actions/setup-gcloud/blob/main/CHANGELOG.md)
- [Commits](77e7a554d4...aa5489c893)

Updates `docker/login-action` from 3.4.0 to 3.5.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](74a5d14239...184bdaa072)

Updates `github/codeql-action` from 3.29.2 to 3.29.11
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](181d5eefc2...3c3833e0f8)

Updates `anchore/sbom-action` from 0.20.2 to 0.20.5
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](cee1b8e05a...da167eac91)

Updates `sigstore/cosign-installer` from 3.9.1 to 3.9.2
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](398d4b0eee...d58896d6a1)

Updates `goreleaser/goreleaser-action` from 6.3.0 to 6.4.0
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](9c156ee8a1...e435ccd777)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: korthout/backport-action
  dependency-version: 3.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: google-github-actions/auth
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: google-github-actions/setup-gcloud
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: docker/login-action
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.29.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: goreleaser/goreleaser-action
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-30 13:29:00 +00:00
Stefan Prodan
64eeda58e6 Merge pull request #5499 from fluxcd/k8s-1.34
Update to Kubernetes v1.34.0 and Go 1.25.0
2025-08-30 16:24:22 +03:00
Stefan Prodan
acdf523c54 Build with Go 1.25
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-30 15:35:53 +03:00
Stefan Prodan
e2abf8e358 Update flux-cli image to Alpine 3.22 and kubectl 1.34
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-30 15:11:43 +03:00
Stefan Prodan
d340f80d75 Update dependencies to Kubernetes v1.34.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-30 15:11:43 +03:00
Stefan Prodan
76d36cb429 Merge pull request #5497 from fluxcd/conform-k8s-1.34
Run conformance tests for Kubernetes 1.34.0
2025-08-29 13:10:58 +02:00
Stefan Prodan
a7fadcd344 Run conformance tests for Kubernetes 1.34.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-29 12:32:31 +02:00
Stefan Prodan
f19f8611f4 Merge pull request #5480 from fluxcd/rfc-0007-history
[RFC-0007] Implementation history update
2025-08-13 14:13:23 +03:00
Stefan Prodan
8cccb90f90 [RFC-0007] Implementation history update
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-13 13:25:41 +03:00
Stefan Prodan
1408bb8294 Merge pull request #5473 from fluxcd/cmd-migrate
Implement `flux migrate` command
2025-08-11 17:56:05 +03:00
Stefan Prodan
45837d2d1b Implement flux migrate command
The migrate command must be run before a Flux minor version upgrade.
The command migrates the Flux custom resources stored in Kubernetes etcd to their latest API version, ensuring the Flux components can continue to function correctly after the upgrade.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-08-08 13:23:00 +03:00
Matheus Pimenta
ccb9d12927 Merge pull request #5462 from cappyzawa/feat/runtime-secrets-migration
Migrate sourcesecret package to runtime/secrets APIs
2025-07-29 14:59:44 +01:00
cappyzawa
8b95a09319 Migrate sourcesecret package to runtime/secrets APIs
The sourcesecret package now uses pkg/runtime/secrets factory
functions instead of the previous monolithic approach. This
provides standardized secret generation with consistent
validation and error handling across all authentication types.

Signed-off-by: cappyzawa <cappyzawa@gmail.com>
2025-07-29 22:50:56 +09:00
Stefan Prodan
8176d88801 Merge pull request #5440 from pinkavaj/pi-labels
manifests: Add `app.kubernetes.io/part-of: flux` label to controller pods
2025-07-28 11:37:24 +03:00
Jiří Pinkava
2f850743fa Add labels to Pod templates
Ensure also pods contain the relevant labels inherited from pared
Deployment object, this makes it easier to select and filter the pods
using the labels eg. when scraping for metrics.

Signed-off-by: Jiří Pinkava <j-pi@seznam.cz>
2025-07-28 10:09:12 +02:00
Stefan Prodan
4e53b6cb8d Merge pull request #5460 from fluxcd/ci-token-update
ci: Use GITHUB_TOKEN for API calls in update workflow
2025-07-18 14:16:08 +03:00
Stefan Prodan
0bb2e3929f ci: Use GITHUB_TOKEN for API calls in update workflow
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-07-18 13:33:10 +03:00
Matheus Pimenta
82b38dfa68 Merge pull request #5455 from fluxcd/upgrade-deps
Upgrade fluxcd/pkg dependencies
2025-07-15 10:51:36 +01:00
Matheus Pimenta
b3b404ed30 Upgrade fluxcd/pkg dependencies
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-07-15 10:32:35 +01:00
Stefan Prodan
45990633e6 Merge pull request #5435 from fluxcd/dependabot/github_actions/ci-641206964f
build(deps): bump the ci group across 1 directory with 7 updates
2025-07-15 10:31:53 +03:00
dependabot[bot]
97937c55bf build(deps): bump the ci group across 1 directory with 7 updates
Bumps the ci group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [korthout/backport-action](https://github.com/korthout/backport-action) | `3.2.0` | `3.2.1` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.17.0` | `1.18.0` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3.10.0` | `3.11.1` |
| [ossf/scorecard-action](https://github.com/ossf/scorecard-action) | `2.4.1` | `2.4.2` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.28.17` | `3.29.2` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.19.0` | `0.20.1` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.8.2` | `3.9.1` |



Updates `korthout/backport-action` from 3.2.0 to 3.2.1
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](436145e922...0193454f0c)

Updates `fluxcd/pkg` from 1.17.0 to 1.18.0
- [Commits](7e9c75bbb6...3d6f759b76)

Updates `docker/setup-buildx-action` from 3.10.0 to 3.11.1
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](b5ca514318...e468171a9d)

Updates `ossf/scorecard-action` from 2.4.1 to 2.4.2
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](f49aabe0b5...05b42c6244)

Updates `github/codeql-action` from 3.28.17 to 3.29.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](60168efe1c...181d5eefc2)

Updates `anchore/sbom-action` from 0.19.0 to 0.20.1
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](9f73021414...9246b90769)

Updates `sigstore/cosign-installer` from 3.8.2 to 3.9.1
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](3454372f43...398d4b0eee)

---
updated-dependencies:
- dependency-name: korthout/backport-action
  dependency-version: 3.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: docker/setup-buildx-action
  dependency-version: 3.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.29.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-15 06:30:36 +00:00
Stefan Prodan
f79c44ee0a Merge pull request #5453 from fluxcd/k8s-1.33.2
Update dependencies to Kubernetes 1.33.2
2025-07-11 19:31:37 +03:00
Stefan Prodan
16eb212609 Update dependencies to Kubernetes 1.33.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-07-11 18:31:11 +03:00
Stefan Prodan
5da5186b3b Merge pull request #5451 from dgunzy/bump-kustomize-1.18.1
Fix `flux diff kustomization` ignore patterns
2025-07-11 18:05:29 +03:00
Daniel Guns
158618e632 Bump pkg/kustomize 1.18.1
Fixes #4921

Signed-off-by: Daniel Guns <danbguns@gmail.com>
2025-07-11 11:53:42 -03:00
Matheus Pimenta
81bd619abd Merge pull request #5452 from fluxcd/rfc-0010-kubeconfig
[RFC-0010] Add workload identity support for remote generic clusters
2025-07-11 11:42:10 +01:00
Matheus Pimenta
d2aa9fb996 [RFC-0010] Add workload identity support for remote generic clusters
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-07-11 11:40:45 +01:00
Stefan Prodan
315dad8682 Merge pull request #5449 from fluxcd/fix-push-insecure
Fix `flux push artifact` for insecure registries
2025-07-10 13:07:11 +03:00
Stefan Prodan
600ec37524 Fix flux push artifact for insecure registries
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-07-10 12:38:53 +03:00
Matheus Pimenta
1af7e08f07 Merge pull request #5443 from fluxcd/update-components
Update toolkit components
2025-07-08 10:23:45 +01:00
fluxcdbot
61a19cac84 Update toolkit components
- kustomize-controller to v1.6.1
  https://github.com/fluxcd/kustomize-controller/blob/v1.6.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-07-08 09:07:31 +00:00
Matheus Pimenta
fa8ef5b9d1 Merge pull request #5434 from fluxcd/rfc-0010-kubeconfig
[RFC-0010] Add workload identity support for remote clusters
2025-07-07 16:14:35 +01:00
Matheus Pimenta
eb5904fb9d [RFC-0010] Add workload identity support for remote clusters
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-06-30 17:02:53 +01:00
Matheus Pimenta
fda72a014c Merge pull request #5431 from dgunzy/bump-ssa-v0.49.0
Bump pkg/ssa to v0.49.0 for CABundle validation fix
2025-06-29 16:48:37 +01:00
Daniel Guns
f4d6934a6f Bump pkg/ssa to v0.49.0 for CABundle validation fix
Includes fix for #800: Remove CABundle from CRDs if cert is invalid

Signed-off-by: Daniel Guns <danbguns@gmail.com>
2025-06-29 12:38:45 -03:00
Stefan Prodan
545b338004 Merge pull request #5426 from fluxcd/update-components
Update toolkit components
2025-06-27 13:39:38 +03:00
Matheus Pimenta
a8425f50bd Fix: Prioritize sha2-512 and sha2-256 for ssh-rsa host keys
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-06-27 11:26:31 +01:00
fluxcdbot
24bf751d4d Update toolkit components
- source-controller to v1.6.2
  https://github.com/fluxcd/source-controller/blob/v1.6.2/CHANGELOG.md
- image-automation-controller to v0.41.2
  https://github.com/fluxcd/image-automation-controller/blob/v0.41.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-06-27 10:21:22 +00:00
Matheus Pimenta
cf157ad8a3 Merge pull request #5421 from dgunzy/promote-image-commands-stable
Promote image CLI commands to stable
2025-06-26 10:08:21 +01:00
Daniel Guns
5a4bc9410b Promote image CLI commands to stable
Remove experimental status from flux image commands in preparation
for GA release of image automation APIs.

Partial fix for #5411

Signed-off-by: Daniel Guns <danbguns@gmail.com>
2025-06-25 20:52:11 -03:00
Matheus Pimenta
de594183bd Merge pull request #5418 from cappyzawa/cleanup-auth-error-handling
refactor: cleanup GetArtifactRegistryCredentials error handling
2025-06-21 08:47:13 +01:00
cappyzawa
4c343893c5 refactor: cleanup GetArtifactRegistryCredentials error handling
Update fluxcd/pkg/auth to v0.18.0 and simplify error handling for
GetArtifactRegistryCredentials() following the improvements made in
the library.

Similar to fluxcd/image-reflector-controller#786, this removes
unnecessary nil checks as the function now returns errors directly
for unsupported providers.

- Replace authentication code in push_artifact.go with loginWithProvider()
- Remove unnecessary authenticator nil check in oci.go
- Remove unused imports (errors, auth packages)

Signed-off-by: cappyzawa <cappyzawa@gmail.com>
2025-06-21 14:11:18 +09:00
Matheus Pimenta
8ae0aaa46c Merge pull request #5409 from fluxcd/update-components
Update toolkit components
2025-06-13 18:13:38 +01:00
fluxcdbot
6b3a1134bd Update toolkit components
- source-controller to v1.6.1
  https://github.com/fluxcd/source-controller/blob/v1.6.1/CHANGELOG.md
- image-reflector-controller to v0.35.2
  https://github.com/fluxcd/image-reflector-controller/blob/v0.35.2/CHANGELOG.md
- image-automation-controller to v0.41.1
  https://github.com/fluxcd/image-automation-controller/blob/v0.41.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-06-13 16:59:37 +00:00
Stefan Prodan
40a9b495b2 Merge pull request #5402 from reiSh6phoo9o/feat/configurable_serviceaccountname
Make service-account name configurable in `flux create tenant`
2025-06-13 15:30:11 +03:00
Stefan Bickel
1d34e5355b Make golden tests pass
Signed-off-by: Stefan Bickel <stefan.bickel@cornelsen.de>
2025-06-13 13:25:26 +02:00
Stefan Bickel
00d0e1af25 Add tests and golden files for create tenant
Signed-off-by: Stefan Bickel <stefan.bickel@cornelsen.de>
2025-06-13 13:25:26 +02:00
Stefan Bickel
9f29702f54 Add cli arg --with-service-account
Signed-off-by: Stefan Bickel <stefan.bickel@cornelsen.de>
2025-06-13 13:25:26 +02:00
Stefan Prodan
7626cd0c86 Merge pull request #5407 from cappyzawa/refactor-deprecated-ssa-func
refactor: Use `normalize.UnstructuredList` instead of `ssa.SetNativeKindsDefaults`
2025-06-13 14:07:43 +03:00
cappyzawa
5291902fd7 Use normalize.UnstructuredList instead of ssa.SetNativeKindsDefaults
Signed-off-by: cappyzawa <cappyzawa@gmail.com>
2025-06-13 15:15:47 +09:00
Matheus Pimenta
1757d964c0 Merge pull request #5404 from fluxcd/fix-host-keys
Fix `knownhosts key mismatch` regression bug
2025-06-12 18:54:43 +01:00
Matheus Pimenta
999f61c02e Upgrade dependencies
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-06-12 18:12:50 +01:00
Matheus Pimenta
5eb43e4566 Merge pull request #5390 from fluxcd/azure-cli-auth
fix: Allow Azure CLI calls in `flux push artifact --provider azure` on DevOps runners
2025-06-09 15:59:31 +01:00
Matheus Pimenta
ec3804cc6f Introduce support for shelling out to Azure binaries in authentication
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-06-09 14:07:51 +01:00
Matheus Pimenta
4c3aed9faf Merge pull request #5389 from ba-work/add-sparse-checkout
Add sparse checkout to cli
2025-06-04 18:10:30 +01:00
Brock Alberry
06e3047a2f add sparse checkout to cli
Signed-off-by: Brock Alberry <brock.alberry@cse-cst.gc.ca>
2025-06-04 12:04:41 -04:00
Matheus Pimenta
99e6791f4b Merge pull request #5347 from fluxcd/remove-manifests
Remove credentials sync manifests
2025-06-04 15:57:59 +01:00
Matheus Pimenta
9cad95dda5 Remove credentials sync manifests
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-06-04 15:35:47 +01:00
Matheus Pimenta
76c584e751 Merge pull request #5388 from JIbald/typo
correct small typo
2025-06-04 11:43:07 +01:00
Johannes Ibald
cd4244ae65 correct small typo
Signed-off-by: Johannes Ibald <johannes.ibald@etes.de>
2025-06-04 11:21:11 +02:00
Stefan Prodan
1d6137d39d Merge pull request #5383 from fluxcd/test-image-automation-digest
Add digest pinning to image automation testing
2025-06-01 22:11:27 +03:00
Stefan Prodan
be8acc0cfb Add digest pinning to image automation testing
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-06-01 21:36:13 +03:00
Stefan Prodan
2f5f40d593 Merge pull request #5381 from fluxcd/update-components
Update image-reflector-controller to v0.35.1
2025-06-01 21:19:12 +03:00
fluxcdbot
4172a8a7f9 Update toolkit components
- image-reflector-controller to v0.35.1
  https://github.com/fluxcd/image-reflector-controller/blob/v0.35.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-06-01 18:05:34 +00:00
Stefan Prodan
4addf8a528 Merge pull request #5379 from fluxcd/backport-2.6-label
Add backport label for `v2.6.x`
2025-06-01 19:59:14 +03:00
Stefan Prodan
1df7697811 Add backport label for v2.6/x
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-06-01 15:36:59 +03:00
Matheus Pimenta
4c66d37545 Merge pull request #5370 from fluxcd/update-components
Update toolkit components
2025-05-28 15:02:14 +01:00
fluxcdbot
481c3c6e1e Update toolkit components
- helm-controller to v1.3.0
  https://github.com/fluxcd/helm-controller/blob/v1.3.0/CHANGELOG.md
- kustomize-controller to v1.6.0
  https://github.com/fluxcd/kustomize-controller/blob/v1.6.0/CHANGELOG.md
- image-automation-controller to v0.41.0
  https://github.com/fluxcd/image-automation-controller/blob/v0.41.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-05-28 13:47:47 +00:00
Stefan Prodan
1d1d96b489 Merge pull request #5373 from fluxcd/dependabot-up
Update dependabot config
2025-05-28 16:31:16 +03:00
Stefan Prodan
0b972771fd Update dependabot config
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-28 15:52:42 +03:00
Stefan Prodan
650732109e Merge pull request #5371 from fluxcd/oci-ga
Update CLI to OCIRepository v1 (GA)
2025-05-28 15:32:54 +03:00
Stefan Prodan
79fed691ca Update CLI to OCIRepository v1 (GA)
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-28 15:12:17 +03:00
Matheus Pimenta
b37ba736fa Merge pull request #5345 from fluxcd/store-digests
Add --interval and --reflect-digest flags to flux create image policy
2025-05-28 08:47:26 +01:00
Matheus Pimenta
65766ff4fc Add --interval and --reflect-digest flags to flux create image policy
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-28 08:25:10 +01:00
Matheus Pimenta
19d9b87c62 Merge pull request #5369 from fluxcd/oci-commands
Promote artifact commands to stable
2025-05-27 17:32:25 +01:00
Matheus Pimenta
d82ec5a211 Promote artifact commands to stable
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-27 16:53:47 +01:00
Matheus Pimenta
5e5ffdbcc3 Merge pull request #5368 from fluxcd/update-components
Update toolkit components
2025-05-27 16:11:13 +01:00
Matheus Pimenta
13ec11da58 Fix image-reflector-controller tests after output change
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-27 15:57:45 +01:00
fluxcdbot
2948d5e70f Update toolkit components
- source-controller to v1.6.0
  https://github.com/fluxcd/source-controller/blob/v1.6.0/CHANGELOG.md
- notification-controller to v1.6.0
  https://github.com/fluxcd/notification-controller/blob/v1.6.0/CHANGELOG.md
- image-reflector-controller to v0.35.0
  https://github.com/fluxcd/image-reflector-controller/blob/v0.35.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-05-27 14:49:04 +00:00
Matheus Pimenta
bb9a119456 Merge pull request #5366 from fluxcd/upgrade-deps
Update dependencies
2025-05-25 14:49:37 +01:00
Matheus Pimenta
22ac16f3a1 Update dependencies
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-25 14:30:10 +01:00
Stefan Prodan
79a654d605 Merge pull request #5364 from fluxcd/conform-4.18.0-okd
Set Kubernetes 1.31 as min supported version
2025-05-23 14:32:45 +02:00
Stefan Prodan
a421ce4266 Set Kubernetes 1.31 as min supported version
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-23 15:15:13 +03:00
Stefan Prodan
4b42c9e746 Update conformance tests to supported versions
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-05-23 14:16:29 +03:00
Stefan Prodan
5ffca1b157 Merge pull request #5357 from fluxcd/upgrade-deps
Upgrade fluxcd/pkg packages
2025-05-23 08:46:12 +02:00
Matheus Pimenta
0951061b5e Upgrade fluxcd/pkg packages
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-19 14:08:33 +01:00
leigh capili
ad9d63ac52 Merge pull request #5356 from fluxcd/upgrade-deps
Upgrade fluxcd/pkg packages
2025-05-16 20:39:34 -04:00
Matheus Pimenta
dccc658273 Upgrade fluxcd/pkg packages
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-16 14:07:09 +01:00
Matheus Pimenta
ef5389cd56 Merge pull request #5355 from fluxcd/rfc-0010-feature-gate
[RFC-0010] Update RFC feature gate behavior
2025-05-15 17:42:26 +01:00
Matheus Pimenta
3f63b3e864 [RFC-0010] Update RFC feature gate behavior
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-15 17:38:33 +01:00
Matheus Pimenta
656d9d892d Merge pull request #5354 from fluxcd/rfc-0010-feature-gate
[RFC-0010] Update RFC to include opt-in feature gate
2025-05-15 17:14:59 +01:00
Matheus Pimenta
e979df122a [RFC-0010] Update RFC to include opt-in feature gate
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-15 17:02:55 +01:00
Stefan Prodan
8804b856ea Merge pull request #5351 from fluxcd/fix-ci
Fix e2e workflow
2025-05-15 18:48:40 +03:00
Max Jonas Werner
3ba170e4d4 Fix e2e workflow
The `--short` flag has been removed from kubectl with 1.28.0
(49945dbfab/CHANGELOG/CHANGELOG-1.28.md (deprecation)).

Signed-off-by: Max Jonas Werner <max@coppersoft.com>
2025-05-14 18:28:08 +02:00
Max Jonas Werner
6150fe9942 Merge pull request #5349 from fluxcd/trace-hr-oci
Fix `flux trace` for HRs from `OCIRepository`s
2025-05-14 18:12:54 +02:00
Max Jonas Werner
3e80c5809e Fix flux trace for HRs from OCIRepositorys
Before:
```
$ flux -n default trace pod default-podinfo-585856f49c-4jl4m
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x40 pc=0x10618da70]

goroutine 1 [running]:
main.traceHelm({0x106dd7b28, 0x14000201490}, {0x12f34c0d8, 0x14000783100}, {{0x1400071e130?, 0x1061e7795?}, {0x1400071e109?, 0x1000d9c84?}}, 0x140006a6030)
	/home/runner/work/flux2/flux2/cmd/flux/trace.go:404 +0x2f0
main.traceObject({0x106dd7b28, 0x14000201490}, {0x12f34c0d8, 0x14000783100}, 0x140006a6030)
	/home/runner/work/flux2/flux2/cmd/flux/trace.go:134 +0x11c
main.traceObjects({0x106dd7b28, 0x14000201490}, {0x12f34c0d8, 0x14000783100}, {0x140006a6040, 0x1, 0x0?})
	/home/runner/work/flux2/flux2/cmd/flux/trace.go:112 +0x74
main.traceCmdRun(0x14000592800?, {0x140003aea80, 0x2, 0x4})
	/home/runner/work/flux2/flux2/cmd/flux/trace.go:107 +0x180
github.com/spf13/cobra.(*Command).execute(0x108341980, {0x140003aea40, 0x4, 0x4})
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:985 +0x834
github.com/spf13/cobra.(*Command).ExecuteC(0x108329280)
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1117 +0x344
github.com/spf13/cobra.(*Command).Execute(...)
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.1/command.go:1041
main.main()
	/home/runner/work/flux2/flux2/cmd/flux/main.go:189 +0x78
```

After:

```
 $ ~/dev/flux/flux2/bin/flux -n default trace pod default-podinfo-585856f49c-4jl4m

Object:         Pod/default-podinfo-585856f49c-4jl4m
Namespace:      default
Status:         Managed by Flux
---
HelmRelease:    podinfo
Namespace:      flux-system
Target:         default
Revision:       6.8.0+2360bdf32ddc
Status:         Last reconciled at 2025-05-14 16:10:37 +0200 CEST
Message:        Helm install succeeded for release default/default-podinfo.v1 with chart podinfo@6.8.0+2360bdf32ddc
---
OCIRepository:   podinfo
Namespace:       flux-system
URL:             oci://ghcr.io/stefanprodan/charts/podinfo
Tag:             6.8.0
Revision:        6.8.0@sha256:2360bdf32ddc50c05f8e128118173343b0a012a338daf145b16e0da9c80081a4
Status:          Last reconciled at 2025-05-14 16:09:17 +0200 CEST
Message:         stored artifact for digest '6.8.0@sha256:2360bdf32ddc50c05f8e128118173343b0a012a338daf145b16e0da9c80081a4'
```

Signed-off-by: Max Jonas Werner <max@coppersoft.com>
2025-05-14 18:02:18 +02:00
Stefan Prodan
8928ac7d39 Merge pull request #5325 from fluxcd/dependabot/github_actions/ci-2efaba0903
build(deps): bump the ci group across 1 directory with 18 updates
2025-05-12 09:38:50 +03:00
dependabot[bot]
289645f142 build(deps): bump the ci group across 1 directory with 18 updates
Bumps the ci group with 18 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [korthout/backport-action](https://github.com/korthout/backport-action) | `3.1.0` | `3.2.0` |
| [actions/setup-go](https://github.com/actions/setup-go) | `5.3.0` | `5.4.0` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.2.0` | `1.3.0` |
| [replicatedhq/replicated-actions](https://github.com/replicatedhq/replicated-actions) | `1.17.0` | `1.19.0` |
| [Azure/login](https://github.com/azure/login) | `2.2.0` | `2.3.0` |
| [google-github-actions/auth](https://github.com/google-github-actions/auth) | `2.1.8` | `2.1.10` |
| [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) | `3.4.0` | `3.6.0` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3.9.0` | `3.10.0` |
| [docker/login-action](https://github.com/docker/login-action) | `3.3.0` | `3.4.0` |
| [ossf/scorecard-action](https://github.com/ossf/scorecard-action) | `2.4.0` | `2.4.1` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4.6.0` | `4.6.2` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.28.9` | `3.28.16` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.18.0` | `0.19.0` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.8.0` | `3.8.2` |
| [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) | `6.1.0` | `6.3.0` |
| [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) | `2.0.0` | `2.1.0` |
| [fossa-contrib/fossa-action](https://github.com/fossa-contrib/fossa-action) | `3.0.0` | `3.0.1` |
| [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) | `7.0.6` | `7.0.8` |



Updates `korthout/backport-action` from 3.1.0 to 3.2.0
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](be567af183...436145e922)

Updates `actions/setup-go` from 5.3.0 to 5.4.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](f111f3307d...0aaccfd150)

Updates `fluxcd/pkg` from 1.2.0 to 1.3.0
- [Commits](c964ce7b91...7e9c75bbb6)

Updates `replicatedhq/replicated-actions` from 1.17.0 to 1.19.0
- [Release notes](https://github.com/replicatedhq/replicated-actions/releases)
- [Commits](c98ab3b979...49b440dabd)

Updates `Azure/login` from 2.2.0 to 2.3.0
- [Release notes](https://github.com/azure/login/releases)
- [Commits](a65d910e8a...a457da9ea1)

Updates `google-github-actions/auth` from 2.1.8 to 2.1.10
- [Release notes](https://github.com/google-github-actions/auth/releases)
- [Changelog](https://github.com/google-github-actions/auth/blob/main/CHANGELOG.md)
- [Commits](71f986410d...ba79af0395)

Updates `docker/setup-qemu-action` from 3.4.0 to 3.6.0
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](4574d27a47...29109295f8)

Updates `docker/setup-buildx-action` from 3.9.0 to 3.10.0
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](f7ce87c1d6...b5ca514318)

Updates `docker/login-action` from 3.3.0 to 3.4.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](9780b0c442...74a5d14239)

Updates `ossf/scorecard-action` from 2.4.0 to 2.4.1
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](62b2cac7ed...f49aabe0b5)

Updates `actions/upload-artifact` from 4.6.0 to 4.6.2
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](65c4c4a1dd...ea165f8d65)

Updates `github/codeql-action` from 3.28.9 to 3.28.16
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](9e8d0789d4...28deaeda66)

Updates `anchore/sbom-action` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](f325610c9f...9f73021414)

Updates `sigstore/cosign-installer` from 3.8.0 to 3.8.2
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](c56c2d3e59...3454372f43)

Updates `goreleaser/goreleaser-action` from 6.1.0 to 6.3.0
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](9ed2f89a66...9c156ee8a1)

Updates `slsa-framework/slsa-github-generator` from 2.0.0 to 2.1.0
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v2.0.0...v2.1.0)

Updates `fossa-contrib/fossa-action` from 3.0.0 to 3.0.1
- [Release notes](https://github.com/fossa-contrib/fossa-action/releases)
- [Changelog](https://github.com/fossa-contrib/fossa-action/blob/master/CHANGELOG.md)
- [Commits](cdc5065bcd...3d2ef181b1)

Updates `peter-evans/create-pull-request` from 7.0.6 to 7.0.8
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](67ccf781d6...271a8d0340)

---
updated-dependencies:
- dependency-name: korthout/backport-action
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: actions/setup-go
  dependency-version: 5.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: replicatedhq/replicated-actions
  dependency-version: 1.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: Azure/login
  dependency-version: 2.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: google-github-actions/auth
  dependency-version: 2.1.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: docker/setup-qemu-action
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: docker/setup-buildx-action
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: docker/login-action
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: actions/upload-artifact
  dependency-version: 4.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.28.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.8.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: goreleaser/goreleaser-action
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: slsa-framework/slsa-github-generator
  dependency-version: 2.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: fossa-contrib/fossa-action
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: peter-evans/create-pull-request
  dependency-version: 7.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-12 00:46:46 +00:00
Stefan Prodan
8d9cbe7693 Merge pull request #5338 from dgunzy/fix/get-command-error-formatting
Fix exit code handling in get command
2025-05-08 08:37:02 +03:00
Daniel Guns
392a33d425 Change error reporting in get.go from logger.Failure to fmt.Errorf to give non 0 exit code
Signed-off-by: Daniel Guns <danbguns@gmail.com>
2025-05-07 19:11:16 -03:00
Matheus Pimenta
6af448e037 Merge pull request #5333 from fluxcd/upgrade-deps
Upgrade fluxcd/pkg auth, oci, git and git/gogit
2025-05-07 18:01:48 +01:00
Matheus Pimenta
ac66adc24c Upgrade fluxcd/pkg auth, oci, git and git/gogit
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-07 17:49:36 +01:00
Stefan Prodan
0a64800784 Merge pull request #5332 from fluxcd/rfc-0010
[RFC-0010] Add RBAC for creating service account tokens
2025-05-03 08:59:24 +03:00
Matheus Pimenta
941af6a648 [RFC-0010] Add RBAC for creating service account tokens
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-05-03 02:07:03 +01:00
Matheus Pimenta
a6b5013649 Merge pull request #5309 from fluxcd/update-rfc-0010
[RFC-0010] Remove EKS Pod Identity from the proposal
2025-04-29 17:29:13 +01:00
Matheus Pimenta
c18ab38877 [RFC-0010] Remove EKS Pod Identity from the proposal
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-04-29 17:24:50 +01:00
Stefan Prodan
8738712cfa Merge pull request #5323 from fluxcd/k8s-1.33
Update to Kubernetes 1.33.0 and Go 1.24.0
2025-04-28 16:07:25 +03:00
Stefan Prodan
8816c5f7de Update to Kubernetes 1.33.0 and Go 1.24.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-04-28 15:02:33 +03:00
Stefan Prodan
e9e15c5f7a Merge pull request #5318 from fluxcd/conform-k8s-1.33.0
Run conformance tests for Kubernetes 1.33.0
2025-04-24 12:29:57 +03:00
Stefan Prodan
5b582917ec Run conformance tests for Kubernetes 1.33.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2025-04-23 22:35:48 +03:00
Stefan Prodan
d9b66f6959 Merge pull request #5219 from niveau0/allow-recursive-dry-run
fix: allow recursive dry-run over local sources
2025-04-16 11:30:10 +03:00
niveau0
1b98e16940 fix: allow recursive dry-run over local sources
Signed-off-by: niveau0 <plingplong@t-online.de>
2025-04-16 09:27:26 +02:00
Stefan Prodan
0c73420ccf Merge pull request #5302 from maboehm/fix-multiple-kustomizations
flux diff: Reset target struct before decoding
2025-04-15 15:03:04 +03:00
Marcel Boehm
8cb7188919 Reset target struct before decoding
Signed-off-by: Marcel Boehm <marcel.boehm@inovex.de>
2025-04-15 11:39:33 +02:00
Marcel Boehm
72a2866508 Add test for reading multiple Kustomizations in a single file
Signed-off-by: Marcel Boehm <marcel.boehm@inovex.de>
2025-04-15 11:39:33 +02:00
Matheus Pimenta
912718103c Merge pull request #5209 from fluxcd/rfc-multi-tenant-workload-identity
[RFC-0010] Multi-Tenant Workload Identity
2025-04-14 11:44:54 +01:00
Matheus Pimenta
a7e41df1e3 [RFC-0010] Multi-Tenant Workload Identity
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-04-14 11:33:49 +01:00
Stefan Prodan
c436708a13 Allow to pull/push artifacts to insecure registries without TLS
Allow to pull/push artifacts to insecure registries without TLS
2025-04-12 01:37:12 +03:00
Matthieu Mottet
3f4743037b Allow to pull/push artifacts without TLS
If applied, this commit will introduce a new `--insecure-repository`
flag to the following commands: `push artifacts`, `pull artifact`,
`diff artifact` and `list artifacts`. When used the flag will lead to
the option `crane.Insecure` being passed to the `crane` client allowing
the use of insecure repositories.

Signed-off-by: Matthieu Mottet <m.mottet@outlook.com>
2025-04-11 20:12:55 +02:00
Stefan Prodan
7b551b0d35 Merge pull request #5295 from fluxcd/dependabot/go_modules/helm.sh/helm/v3-3.17.3
build(deps): bump helm.sh/helm/v3 from 3.17.0 to 3.17.3
2025-04-10 18:15:06 +03:00
dependabot[bot]
bb8a10bab8 build(deps): bump helm.sh/helm/v3 from 3.17.0 to 3.17.3
Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.17.0 to 3.17.3.
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.17.0...v3.17.3)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.17.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-10 13:51:34 +00:00
Matheus Pimenta
09af0becc5 Merge pull request #5287 from piontec/ignore-scorecard-for-backports
add: OSSF scorecard configuration file - ignore false-positive
2025-04-04 11:06:29 +01:00
Matheus Pimenta
d84bff7d1b Merge branch 'main' into ignore-scorecard-for-backports 2025-04-04 10:53:35 +01:00
Stefan Prodan
a4c513487e Merge pull request #5282 from piontec/use-gh-token
change: use the default ephemeral GITHUB_TOKEN instead of the static one
2025-04-04 10:45:57 +01:00
piontec
2046003714 Merge branch 'main' into use-gh-token 2025-04-04 10:35:38 +02:00
piontec
f07ee355ea Merge branch 'main' into ignore-scorecard-for-backports 2025-04-03 17:14:13 +02:00
Łukasz Piątkowski
5e02724e49 add: OSSF scorecard configuration file - ignore false-positive
Signed-off-by: Łukasz Piątkowski <piontec@gmail.com>
2025-04-03 17:11:26 +02:00
Matheus Pimenta
e5926bcaad Merge pull request #5284 from y-eight/main
ci: switch to goreleaser changelog generation
2025-04-03 16:08:28 +01:00
maximilian.schubert@telekom.de
355f2bc5f3 ci: sw to goreleaser changlog gen; rm dep
Signed-off-by: Maximilian Schubert <maximilian.schubert@telekom.de>
2025-04-03 13:15:03 +02:00
Łukasz Piątkowski
7e8e0ab772 change: use the default ephemeral GITHUB_TOKEN instead of the static GHCR_TOKEN
Signed-off-by: Łukasz Piątkowski <piontec@gmail.com>
2025-04-03 12:56:01 +02:00
Matheus Pimenta
f0fecf7399 Merge pull request #5038 from laiminhtrung1997/remove-redundant-space
Remove redundant space.
2025-03-24 09:11:31 +00:00
laiminhtrung1997
54db4ffc8b Remove redundant space.
Signed-off-by: laiminhtrung1997 <68812829+laiminhtrung1997@users.noreply.github.com>
2025-03-24 15:07:48 +07:00
Matheus Pimenta
73fff7404f Merge pull request #5227 from fluxcd/fix-debug-hr
Fix command debug hr not taking targetPath into account
2025-03-03 11:28:14 +00:00
Matheus Pimenta
24057743bb Fix command debug hr not taking targetPath into account
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-03-03 10:56:16 +00:00
Matheus Pimenta
04d87be082 Merge pull request #5215 from fluxcd/update-labels
Update backport labels for 2.5
2025-02-25 15:36:05 +00:00
Matheus Pimenta
e7c6ebccc3 Update backport labels for 2.5
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-02-25 15:32:26 +00:00
Matheus Pimenta
48382f885b Merge pull request #5214 from fluxcd/update-components
Update kustomize-controller to v1.5.1
2025-02-25 15:31:53 +00:00
fluxcdbot
511d8346f2 Update toolkit components
- kustomize-controller to v1.5.1
  https://github.com/fluxcd/kustomize-controller/blob/v1.5.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2025-02-25 15:05:00 +00:00
Matheus Pimenta
f0e8e84ee0 Merge pull request #5141 from fluxcd/rfc-0008-implemented
Update RFC 0008 and RFC 0009 milestones
2025-02-22 22:38:10 +00:00
Matheus Pimenta
c277fbf14e Update RFC 0008 and RFC 0009 milestones
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2025-02-22 17:24:41 +00:00
Matheus Pimenta
28570296a9 Merge pull request #5202 from NotAwar/patch-1
fix: correct name on github app secret
2025-02-20 15:03:45 +00:00
Awar Abdulkarim
39ec0cb594 fix: correct name on github app secret
Signed-off-by: Awar Abdulkarim <48431495+NotAwar@users.noreply.github.com>
2025-02-20 14:40:33 +00:00
293 changed files with 6416 additions and 3489 deletions

View File

@@ -6,11 +6,9 @@ updates:
labels: ["area/ci", "dependencies"] labels: ["area/ci", "dependencies"]
groups: groups:
# Group all updates together, so that they are all applied in a single PR. # Group all updates together, so that they are all applied in a single PR.
# Grouped updates are currently in beta and is subject to change.
# xref: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups # xref: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups
ci: ci:
patterns: patterns:
- "*" - "*"
schedule: schedule:
# By default, this will be on a monday. interval: "monthly"
interval: "weekly"

15
.github/labels.yaml vendored
View File

@@ -44,15 +44,12 @@
description: Feature request proposals in the RFC format description: Feature request proposals in the RFC format
color: '#D621C3' color: '#D621C3'
aliases: ['area/RFC'] aliases: ['area/RFC']
- name: backport:release/v2.0.x - name: backport:release/v2.4.x
description: To be backported to release/v2.0.x description: To be backported to release/v2.4.x
color: '#ffd700' color: '#ffd700'
- name: backport:release/v2.1.x - name: backport:release/v2.5.x
description: To be backported to release/v2.1.x description: To be backported to release/v2.5.x
color: '#ffd700' color: '#ffd700'
- name: backport:release/v2.2.x - name: backport:release/v2.6.x
description: To be backported to release/v2.2.x description: To be backported to release/v2.6.x
color: '#ffd700'
- name: backport:release/v2.3.x
description: To be backported to release/v2.3.x
color: '#ffd700' color: '#ffd700'

View File

@@ -24,6 +24,6 @@ jobs:
name: action on ${{ matrix.version }} name: action on ${{ matrix.version }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup flux - name: Setup flux
uses: ./action uses: ./action

View File

@@ -1,34 +1,13 @@
name: backport name: backport
on: on:
pull_request_target: pull_request_target:
types: [closed, labeled] types: [closed, labeled]
permissions: read-all
permissions:
contents: read
jobs: jobs:
pull-request: backport:
runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write # for reading and creating branches.
pull-requests: write pull-requests: write # for creating pull requests against release branches.
if: github.event.pull_request.state == 'closed' && github.event.pull_request.merged && (github.event_name != 'labeled' || startsWith('backport:', github.event.label.name)) uses: fluxcd/gha-workflows/.github/workflows/backport.yaml@v0.4.0
steps: secrets:
- name: Checkout github-token: ${{ secrets.GITHUB_TOKEN }}
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Create backport PRs
uses: korthout/backport-action@be567af183754f6a5d831ae90f648954763f17f5 # v3.1.0
# xref: https://github.com/korthout/backport-action#inputs
with:
# Use token to allow workflows to be triggered for the created PR
github_token: ${{ secrets.BOT_GITHUB_TOKEN }}
# Match labels with a pattern `backport:<target-branch>`
label_pattern: '^backport:([^ ]+)$'
# A bit shorter pull-request title than the default
pull_title: '[${target_branch}] ${pull_title}'
# Simpler PR description than default
pull_description: |-
Automated backport to `${target_branch}`, triggered by a label in #${pull_number}.

View File

@@ -9,7 +9,7 @@ permissions:
contents: read contents: read
env: env:
GO_VERSION: 1.23.x GO_VERSION: 1.25.x
jobs: jobs:
conform-kubernetes: conform-kubernetes:
@@ -19,13 +19,13 @@ jobs:
matrix: matrix:
# Keep this list up-to-date with https://endoflife.date/kubernetes # Keep this list up-to-date with https://endoflife.date/kubernetes
# Build images with https://github.com/fluxcd/flux-benchmark/actions/workflows/build-kind.yaml # Build images with https://github.com/fluxcd/flux-benchmark/actions/workflows/build-kind.yaml
KUBERNETES_VERSION: [1.30.9, 1.31.5, 1.32.1 ] KUBERNETES_VERSION: [1.32.1, 1.33.0, 1.34.1]
fail-fast: false fail-fast: false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
cache-dependency-path: | cache-dependency-path: |
@@ -42,7 +42,7 @@ jobs:
- name: Setup Kubernetes - name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with: with:
version: v0.22.0 version: v0.30.0
cluster_name: ${{ steps.prep.outputs.CLUSTER }} cluster_name: ${{ steps.prep.outputs.CLUSTER }}
node_image: ghcr.io/fluxcd/kindest/node:v${{ matrix.KUBERNETES_VERSION }}-arm64 node_image: ghcr.io/fluxcd/kindest/node:v${{ matrix.KUBERNETES_VERSION }}-arm64
- name: Run e2e tests - name: Run e2e tests
@@ -76,13 +76,13 @@ jobs:
matrix: matrix:
# Keep this list up-to-date with https://endoflife.date/kubernetes # Keep this list up-to-date with https://endoflife.date/kubernetes
# Available versions can be found with "replicated cluster versions" # Available versions can be found with "replicated cluster versions"
K3S_VERSION: [ 1.30.9, 1.31.5, 1.32.1 ] K3S_VERSION: [ 1.32.8, 1.33.4 ]
fail-fast: false fail-fast: false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
cache-dependency-path: | cache-dependency-path: |
@@ -97,7 +97,7 @@ jobs:
KUBECONFIG_PATH="$(git rev-parse --show-toplevel)/bin/kubeconfig.yaml" KUBECONFIG_PATH="$(git rev-parse --show-toplevel)/bin/kubeconfig.yaml"
echo "kubeconfig-path=${KUBECONFIG_PATH}" >> $GITHUB_OUTPUT echo "kubeconfig-path=${KUBECONFIG_PATH}" >> $GITHUB_OUTPUT
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Build - name: Build
run: make build-dev run: make build-dev
- name: Create repository - name: Create repository
@@ -107,7 +107,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: Create cluster - name: Create cluster
id: create-cluster id: create-cluster
uses: replicatedhq/replicated-actions/create-cluster@c98ab3b97925af5db9faf3f9676df7a9c6736985 # v1.17.0 uses: replicatedhq/replicated-actions/create-cluster@49b440dabd7e0e868cbbabda5cfc0d8332a279fa # v1.19.0
with: with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }} api-token: ${{ secrets.REPLICATED_API_TOKEN }}
kubernetes-distribution: "k3s" kubernetes-distribution: "k3s"
@@ -151,7 +151,7 @@ jobs:
kubectl delete ns flux-system --wait kubectl delete ns flux-system --wait
- name: Delete cluster - name: Delete cluster
if: ${{ always() }} if: ${{ always() }}
uses: replicatedhq/replicated-actions/remove-cluster@c98ab3b97925af5db9faf3f9676df7a9c6736985 # v1.17.0 uses: replicatedhq/replicated-actions/remove-cluster@49b440dabd7e0e868cbbabda5cfc0d8332a279fa # v1.19.0
continue-on-error: true continue-on-error: true
with: with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }} api-token: ${{ secrets.REPLICATED_API_TOKEN }}
@@ -169,13 +169,13 @@ jobs:
strategy: strategy:
matrix: matrix:
# Keep this list up-to-date with https://endoflife.date/red-hat-openshift # Keep this list up-to-date with https://endoflife.date/red-hat-openshift
OPENSHIFT_VERSION: [ 4.17.0-okd ] OPENSHIFT_VERSION: [ 4.19.0-okd ]
fail-fast: false fail-fast: false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
cache-dependency-path: | cache-dependency-path: |
@@ -190,7 +190,7 @@ jobs:
KUBECONFIG_PATH="$(git rev-parse --show-toplevel)/bin/kubeconfig.yaml" KUBECONFIG_PATH="$(git rev-parse --show-toplevel)/bin/kubeconfig.yaml"
echo "kubeconfig-path=${KUBECONFIG_PATH}" >> $GITHUB_OUTPUT echo "kubeconfig-path=${KUBECONFIG_PATH}" >> $GITHUB_OUTPUT
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Build - name: Build
run: make build-dev run: make build-dev
- name: Create repository - name: Create repository
@@ -200,7 +200,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
- name: Create cluster - name: Create cluster
id: create-cluster id: create-cluster
uses: replicatedhq/replicated-actions/create-cluster@c98ab3b97925af5db9faf3f9676df7a9c6736985 # v1.17.0 uses: replicatedhq/replicated-actions/create-cluster@49b440dabd7e0e868cbbabda5cfc0d8332a279fa # v1.19.0
with: with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }} api-token: ${{ secrets.REPLICATED_API_TOKEN }}
kubernetes-distribution: "openshift" kubernetes-distribution: "openshift"
@@ -242,7 +242,7 @@ jobs:
kubectl delete ns flux-system --wait kubectl delete ns flux-system --wait
- name: Delete cluster - name: Delete cluster
if: ${{ always() }} if: ${{ always() }}
uses: replicatedhq/replicated-actions/remove-cluster@c98ab3b97925af5db9faf3f9676df7a9c6736985 # v1.17.0 uses: replicatedhq/replicated-actions/remove-cluster@49b440dabd7e0e868cbbabda5cfc0d8332a279fa # v1.19.0
continue-on-error: true continue-on-error: true
with: with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }} api-token: ${{ secrets.REPLICATED_API_TOKEN }}

View File

@@ -22,19 +22,18 @@ permissions:
jobs: jobs:
e2e-aks: e2e-aks:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
defaults: defaults:
run: run:
working-directory: ./tests/integration working-directory: ./tests/integration
# This job is currently disabled. Remove the false check when Azure subscription is enabled. if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
if: false && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
steps: steps:
- name: CheckoutD - name: CheckoutD
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: 1.23.x go-version: 1.25.x
cache-dependency-path: tests/integration/go.sum cache-dependency-path: tests/integration/go.sum
- name: Setup Terraform - name: Setup Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
@@ -49,9 +48,9 @@ jobs:
env: env:
SOPS_VER: 3.7.1 SOPS_VER: 3.7.1
- name: Authenticate to Azure - name: Authenticate to Azure
uses: Azure/login@a65d910e8af852a8061c627c456678983e180302 # v1.4.6 uses: Azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v1.4.6
with: with:
creds: '{"clientId":"${{ secrets.AZ_ARM_CLIENT_ID }}","clientSecret":"${{ secrets.AZ_ARM_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZ_ARM_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZ_ARM_TENANT_ID }}"}' creds: '{"clientId":"${{ secrets.ARM_CLIENT_ID }}","clientSecret":"${{ secrets.ARM_CLIENT_SECRET }}","subscriptionId":"${{ secrets.ARM_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.ARM_TENANT_ID }}"}'
- name: Set dynamic variables in .env - name: Set dynamic variables in .env
run: | run: |
cat > .env <<EOF cat > .env <<EOF
@@ -61,33 +60,35 @@ jobs:
run: cat .env run: cat .env
- name: Run Azure e2e tests - name: Run Azure e2e tests
env: env:
ARM_CLIENT_ID: ${{ secrets.AZ_ARM_CLIENT_ID }} ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZ_ARM_CLIENT_SECRET }} ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZ_ARM_SUBSCRIPTION_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZ_ARM_TENANT_ID }} ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
TF_VAR_azuredevops_org: ${{ secrets.TF_VAR_azuredevops_org }} TF_VAR_azuredevops_org: ${{ secrets.TF_VAR_azuredevops_org }}
TF_VAR_azuredevops_pat: ${{ secrets.TF_VAR_azuredevops_pat }} TF_VAR_azuredevops_pat: ${{ secrets.TF_VAR_azuredevops_pat }}
TF_VAR_location: ${{ vars.TF_VAR_azure_location }} TF_VAR_azure_location: ${{ vars.TF_VAR_azure_location }}
GITREPO_SSH_CONTENTS: ${{ secrets.AZURE_GITREPO_SSH_CONTENTS }} GITREPO_SSH_CONTENTS: ${{ secrets.GIT_SSH_IDENTITY }}
GITREPO_SSH_PUB_CONTENTS: ${{ secrets.AZURE_GITREPO_SSH_PUB_CONTENTS }} GITREPO_SSH_PUB_CONTENTS: ${{ secrets.GIT_SSH_IDENTITY_PUB }}
run: | run: |
source .env source .env
mkdir -p ./build/ssh mkdir -p ./build/ssh
touch ./build/ssh/key cat <<EOF > build/ssh/key
echo $GITREPO_SSH_CONTENTS | base64 -d > build/ssh/key $GITREPO_SSH_CONTENTS
EOF
export GITREPO_SSH_PATH=build/ssh/key export GITREPO_SSH_PATH=build/ssh/key
touch ./build/ssh/key.pub cat <<EOF > build/ssh/key.pub
echo $GITREPO_SSH_PUB_CONTENTS | base64 -d > ./build/ssh/key.pub $GITREPO_SSH_PUB_CONTENTS
EOF
export GITREPO_SSH_PUB_PATH=build/ssh/key.pub export GITREPO_SSH_PUB_PATH=build/ssh/key.pub
make test-azure make test-azure
- name: Ensure resource cleanup - name: Ensure resource cleanup
if: ${{ always() }} if: ${{ always() }}
env: env:
ARM_CLIENT_ID: ${{ secrets.AZ_ARM_CLIENT_ID }} ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZ_ARM_CLIENT_SECRET }} ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZ_ARM_SUBSCRIPTION_ID }} ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZ_ARM_TENANT_ID }} ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
TF_VAR_azuredevops_org: ${{ secrets.TF_VAR_azuredevops_org }} TF_VAR_azuredevops_org: ${{ secrets.TF_VAR_azuredevops_org }}
TF_VAR_azuredevops_pat: ${{ secrets.TF_VAR_azuredevops_pat }} TF_VAR_azuredevops_pat: ${{ secrets.TF_VAR_azuredevops_pat }}
TF_VAR_location: ${{ vars.TF_VAR_azure_location }} TF_VAR_azure_location: ${{ vars.TF_VAR_azure_location }}
run: source .env && make destroy-azure run: source .env && make destroy-azure

View File

@@ -17,27 +17,27 @@ jobs:
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: 1.23.x go-version: 1.25.x
cache-dependency-path: | cache-dependency-path: |
**/go.sum **/go.sum
**/go.mod **/go.mod
- name: Setup Kubernetes - name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with: with:
version: v0.24.0 version: v0.30.0
cluster_name: kind cluster_name: kind
# The versions below should target the newest Kubernetes version # The versions below should target the newest Kubernetes version
# Keep this up-to-date with https://endoflife.date/kubernetes # Keep this up-to-date with https://endoflife.date/kubernetes
node_image: ghcr.io/fluxcd/kindest/node:v1.31.0-amd64 node_image: ghcr.io/fluxcd/kindest/node:v1.32.1-amd64
kubectl_version: v1.31.0 kubectl_version: v1.32.0
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Setup yq - name: Setup yq
uses: fluxcd/pkg/actions/yq@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/yq@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Build - name: Build
run: make build-dev run: make build-dev
- name: Set outputs - name: Set outputs
@@ -107,6 +107,8 @@ jobs:
./bin/flux reconcile image repository podinfo ./bin/flux reconcile image repository podinfo
./bin/flux reconcile image update flux-system ./bin/flux reconcile image update flux-system
./bin/flux get images all ./bin/flux get images all
./bin/flux -n flux-system events --for ImageUpdateAutomation/flux-system
kubectl -n flux-system get -o yaml ImageUpdateAutomation flux-system
kubectl -n flux-system get -o yaml ImageUpdateAutomation flux-system | \ kubectl -n flux-system get -o yaml ImageUpdateAutomation flux-system | \
yq '.status.lastPushCommit | length > 1' | grep 'true' yq '.status.lastPushCommit | length > 1' | grep 'true'
env: env:

View File

@@ -22,18 +22,18 @@ permissions:
jobs: jobs:
e2e-gcp: e2e-gcp:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
defaults: defaults:
run: run:
working-directory: ./tests/integration working-directory: ./tests/integration
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: 1.23.x go-version: 1.25.x
cache-dependency-path: tests/integration/go.sum cache-dependency-path: tests/integration/go.sum
- name: Setup Terraform - name: Setup Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
@@ -48,19 +48,19 @@ jobs:
env: env:
SOPS_VER: 3.7.1 SOPS_VER: 3.7.1
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
uses: google-github-actions/auth@71f986410dfbc7added4569d411d040a91dc6935 # v2.1.8 uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
id: 'auth' id: 'auth'
with: with:
credentials_json: '${{ secrets.FLUX2_E2E_GOOGLE_CREDENTIALS }}' credentials_json: '${{ secrets.FLUX2_E2E_GOOGLE_CREDENTIALS }}'
token_format: 'access_token' token_format: 'access_token'
- name: Setup gcloud - name: Setup gcloud
uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4 uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3.4.0 uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Setup Docker Buildx - name: Setup Docker Buildx
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Log into us-central1-docker.pkg.dev - name: Log into us-central1-docker.pkg.dev
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with: with:
registry: us-central1-docker.pkg.dev registry: us-central1-docker.pkg.dev
username: oauth2accesstoken username: oauth2accesstoken

View File

@@ -23,30 +23,30 @@ jobs:
- 5000:5000 - 5000:5000
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: 1.23.x go-version: 1.25.x
cache-dependency-path: | cache-dependency-path: |
**/go.sum **/go.sum
**/go.mod **/go.mod
- name: Setup Kubernetes - name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with: with:
version: v0.24.0 version: v0.30.0
cluster_name: kind cluster_name: kind
wait: 5s wait: 5s
config: .github/kind/config.yaml # disable KIND-net config: .github/kind/config.yaml # disable KIND-net
# The versions below should target the oldest supported Kubernetes version # The versions below should target the oldest supported Kubernetes version
# Keep this up-to-date with https://endoflife.date/kubernetes # Keep this up-to-date with https://endoflife.date/kubernetes
node_image: ghcr.io/fluxcd/kindest/node:v1.30.9-amd64 node_image: ghcr.io/fluxcd/kindest/node:v1.32.1-amd64
kubectl_version: v1.30.9 kubectl_version: v1.32.0
- name: Setup Calico for network policy - name: Setup Calico for network policy
run: | run: |
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Run tests - name: Run tests
run: make test run: make test
- name: Run e2e tests - name: Run e2e tests
@@ -238,6 +238,9 @@ jobs:
- name: flux check - name: flux check
run: | run: |
./bin/flux check ./bin/flux check
- name: flux migrate
run: |
./bin/flux migrate
- name: flux version - name: flux version
run: | run: |
./bin/flux version ./bin/flux version
@@ -247,7 +250,7 @@ jobs:
- name: Debug failure - name: Debug failure
if: failure() if: failure()
run: | run: |
kubectl version --client --short kubectl version --client
kubectl -n flux-system get all kubectl -n flux-system get all
kubectl -n flux-system describe pods kubectl -n flux-system describe pods
kubectl -n flux-system get kustomizations -oyaml kubectl -n flux-system get kustomizations -oyaml

View File

@@ -19,21 +19,21 @@ jobs:
actions: read actions: read
contents: read contents: read
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Run analysis - name: Run analysis
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with: with:
results_file: results.sarif results_file: results.sarif
results_format: sarif results_format: sarif
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
publish_results: true publish_results: true
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: SARIF file name: SARIF file
path: results.sarif path: results.sarif
retention-days: 5 retention-days: 5
- name: Upload SARIF results - name: Upload SARIF results
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5
with: with:
sarif_file: results.sarif sarif_file: results.sarif

View File

@@ -2,7 +2,7 @@ name: release
on: on:
push: push:
tags: [ 'v*' ] tags: ["v*"]
permissions: permissions:
contents: read contents: read
@@ -20,33 +20,33 @@ jobs:
packages: write # needed for ghcr access packages: write # needed for ghcr access
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Unshallow - name: Unshallow
run: git fetch --prune --unshallow run: git fetch --prune --unshallow
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: 1.23.x go-version: 1.25.x
cache: false cache: false
- name: Setup QEMU - name: Setup QEMU
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3.4.0 uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Setup Docker Buildx - name: Setup Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Setup Syft - name: Setup Syft
uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0 uses: anchore/sbom-action/download-syft@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6
- name: Setup Cosign - name: Setup Cosign
uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0 uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with: with:
registry: ghcr.io registry: ghcr.io
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.GHCR_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with: with:
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }} password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
@@ -59,30 +59,19 @@ jobs:
run: | run: |
kustomize build manifests/crds > all-crds.yaml kustomize build manifests/crds > all-crds.yaml
- name: Generate OpenAPI JSON schemas from CRDs - name: Generate OpenAPI JSON schemas from CRDs
uses: fluxcd/pkg/actions/crdjsonschema@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/crdjsonschema@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
with: with:
crd: all-crds.yaml crd: all-crds.yaml
output: schemas output: schemas
- 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
id: run-goreleaser id: run-goreleaser
uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0 uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with: with:
version: latest version: latest
args: release --release-notes=output/notes.md --skip=validate args: release --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 }}
@@ -93,13 +82,13 @@ jobs:
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}" ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
run: | run: |
set -euo pipefail set -euo pipefail
hashes=$(echo -E $ARTIFACTS | jq --raw-output '.[] | {name, "digest": (.extra.Digest // .extra.Checksum)} | select(.digest) | {digest} + {name} | join(" ") | sub("^sha256:";"")' | base64 -w0) hashes=$(echo -E $ARTIFACTS | jq --raw-output '.[] | {name, "digest": (.extra.Digest // .extra.Checksum)} | select(.digest) | {digest} + {name} | join(" ") | sub("^sha256:";"")' | base64 -w0)
echo "hashes=$hashes" >> $GITHUB_OUTPUT echo "hashes=$hashes" >> $GITHUB_OUTPUT
image_url=fluxcd/flux-cli:$GITHUB_REF_NAME image_url=fluxcd/flux-cli:$GITHUB_REF_NAME
echo "image_url=$image_url" >> $GITHUB_OUTPUT echo "image_url=$image_url" >> $GITHUB_OUTPUT
image_digest=$(docker buildx imagetools inspect ${image_url} --format '{{json .}}' | jq -r .manifest.digest) image_digest=$(docker buildx imagetools inspect ${image_url} --format '{{json .}}' | jq -r .manifest.digest)
echo "image_digest=$image_digest" >> $GITHUB_OUTPUT echo "image_digest=$image_digest" >> $GITHUB_OUTPUT
@@ -110,24 +99,26 @@ jobs:
id-token: write id-token: write
packages: write packages: write
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Kustomize - name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Setup Flux CLI - name: Setup Flux CLI
uses: ./action/ uses: ./action/
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare - name: Prepare
id: prep id: prep
run: | run: |
VERSION=$(flux version --client | awk '{ print $NF }') VERSION=$(flux version --client | awk '{ print $NF }')
echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Login to GHCR - name: Login to GHCR
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with: with:
registry: ghcr.io registry: ghcr.io
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.GHCR_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with: with:
username: fluxcdbot username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }} password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
@@ -137,7 +128,7 @@ jobs:
flux install --registry=ghcr.io/fluxcd \ flux install --registry=ghcr.io/fluxcd \
--components-extra=image-reflector-controller,image-automation-controller \ --components-extra=image-reflector-controller,image-automation-controller \
--export > ./ghcr.io/flux-system/gotk-components.yaml --export > ./ghcr.io/flux-system/gotk-components.yaml
cd ./ghcr.io && flux push artifact \ cd ./ghcr.io && flux push artifact \
oci://ghcr.io/fluxcd/flux-manifests:${{ steps.prep.outputs.version }} \ oci://ghcr.io/fluxcd/flux-manifests:${{ steps.prep.outputs.version }} \
--path="./flux-system" \ --path="./flux-system" \
@@ -149,13 +140,13 @@ jobs:
flux install --registry=docker.io/fluxcd \ flux install --registry=docker.io/fluxcd \
--components-extra=image-reflector-controller,image-automation-controller \ --components-extra=image-reflector-controller,image-automation-controller \
--export > ./docker.io/flux-system/gotk-components.yaml --export > ./docker.io/flux-system/gotk-components.yaml
cd ./docker.io && flux push artifact \ cd ./docker.io && flux push artifact \
oci://docker.io/fluxcd/flux-manifests:${{ steps.prep.outputs.version }} \ oci://docker.io/fluxcd/flux-manifests:${{ steps.prep.outputs.version }} \
--path="./flux-system" \ --path="./flux-system" \
--source=${{ github.repositoryUrl }} \ --source=${{ github.repositoryUrl }} \
--revision="${{ github.ref_name }}@sha1:${{ github.sha }}" --revision="${{ github.ref_name }}@sha1:${{ github.sha }}"
- uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0 - uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
- name: Sign manifests - name: Sign manifests
env: env:
COSIGN_EXPERIMENTAL: 1 COSIGN_EXPERIMENTAL: 1
@@ -176,7 +167,7 @@ jobs:
actions: read # for detecting the Github Actions environment. actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing. id-token: write # for creating OIDC tokens for signing.
contents: write # for uploading attestations to GitHub releases. contents: write # for uploading attestations to GitHub releases.
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with: with:
provenance-name: "provenance.intoto.jsonl" provenance-name: "provenance.intoto.jsonl"
base64-subjects: "${{ needs.release-flux-cli.outputs.hashes }}" base64-subjects: "${{ needs.release-flux-cli.outputs.hashes }}"
@@ -188,7 +179,7 @@ jobs:
actions: read # for detecting the Github Actions environment. actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing. id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations. packages: write # for uploading attestations.
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with: with:
image: ${{ needs.release-flux-cli.outputs.image_url }} image: ${{ needs.release-flux-cli.outputs.image_url }}
digest: ${{ needs.release-flux-cli.outputs.image_digest }} digest: ${{ needs.release-flux-cli.outputs.image_digest }}
@@ -202,10 +193,10 @@ jobs:
actions: read # for detecting the Github Actions environment. actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing. id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations. packages: write # for uploading attestations.
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with: with:
image: ghcr.io/${{ needs.release-flux-cli.outputs.image_url }} image: ghcr.io/${{ needs.release-flux-cli.outputs.image_url }}
digest: ${{ needs.release-flux-cli.outputs.image_digest }} digest: ${{ needs.release-flux-cli.outputs.image_digest }}
registry-username: fluxcdbot registry-username: fluxcdbot
secrets: secrets:
registry-password: ${{ secrets.GHCR_TOKEN }} registry-password: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,5 +1,4 @@
name: scan name: scan
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
@@ -8,79 +7,13 @@ on:
branches: [ 'main', 'release/**' ] branches: [ 'main', 'release/**' ]
schedule: schedule:
- cron: '18 10 * * 3' - cron: '18 10 * * 3'
permissions: read-all
permissions:
contents: read
jobs: jobs:
scan-fossa: analyze:
runs-on: ubuntu-latest
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run FOSSA scan and upload build data
uses: fossa-contrib/fossa-action@cdc5065bcdee31a32e47d4585df72d66e8e941c2 # v3.0.0
with:
# FOSSA Push-Only API Token
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
github-token: ${{ github.token }}
scan-snyk:
runs-on: ubuntu-latest
permissions: permissions:
security-events: write contents: read # for reading the repository code.
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]' security-events: write # for uploading the CodeQL analysis results.
steps: uses: fluxcd/gha-workflows/.github/workflows/code-scan.yaml@v0.4.0
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 secrets:
- name: Setup Kustomize github-token: ${{ secrets.GITHUB_TOKEN }}
uses: fluxcd/pkg/actions/kustomize@c964ce7b91949ff4b5e3959db4f1d7bb2e029a49 # main fossa-token: ${{ secrets.FOSSA_TOKEN }}
- name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version-file: 'go.mod'
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Download modules and build manifests
run: |
make tidy
make cmd/flux/.manifests.done
- uses: snyk/actions/setup@b98d498629f1c368650224d6d212bf7dfa89e4bf
- name: Run Snyk to check for vulnerabilities
continue-on-error: true
run: |
snyk test --all-projects --sarif-file-output=snyk.sarif
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Upload result to GitHub Code Scanning
continue-on-error: true
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
with:
sarif_file: snyk.sarif
scan-codeql:
runs-on: ubuntu-latest
permissions:
security-events: write
if: github.actor != 'dependabot[bot]'
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version-file: 'go.mod'
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Initialize CodeQL
uses: github/codeql-action/init@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
with:
languages: go
# xref: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# xref: https://codeql.github.com/codeql-query-help/go/
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9

View File

@@ -6,23 +6,12 @@ on:
- main - main
paths: paths:
- .github/labels.yaml - .github/labels.yaml
permissions: read-all
permissions:
contents: read
jobs: jobs:
labels: sync-labels:
name: Run sync
runs-on: ubuntu-latest
permissions: permissions:
issues: write contents: read # for reading the labels file.
steps: issues: write # for creating and updating labels.
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: fluxcd/gha-workflows/.github/workflows/labels-sync.yaml@v0.4.0
- uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3 secrets:
with: github-token: ${{ secrets.GITHUB_TOKEN }}
# Configuration file
config-file: |
https://raw.githubusercontent.com/fluxcd/community/main/.github/standard-labels.yaml
.github/labels.yaml
# Strictly declarative
delete-other-labels: true

View File

@@ -2,8 +2,6 @@ name: update
on: on:
workflow_dispatch: workflow_dispatch:
schedule:
- cron: "0 * * * *"
push: push:
branches: [main] branches: [main]
@@ -18,24 +16,37 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go - name: Setup Go
uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with: with:
go-version: 1.23.x go-version: 1.25.x
cache-dependency-path: | cache-dependency-path: |
**/go.sum **/go.sum
**/go.mod **/go.mod
- name: Update component versions - name: Update component versions
id: update id: update
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
PR_BODY=$(mktemp) PR_BODY=$(mktemp)
bump_version() { bump_version() {
local LATEST_VERSION=$(curl -s https://api.github.com/repos/fluxcd/$1/releases | jq -r 'sort_by(.published_at) | .[-1] | .tag_name') local LATEST_VERSION=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/fluxcd/$1/releases | jq -r 'sort_by(.published_at) | .[-1] | .tag_name')
if [[ "$LATEST_VERSION" == *"-rc"* ]]; then
echo "Skipping release candidate version for $1: $LATEST_VERSION"
return
fi
local CTRL_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p;n" manifests/bases/$1/kustomization.yaml) local CTRL_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p;n" manifests/bases/$1/kustomization.yaml)
local CRD_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p" manifests/crds/kustomization.yaml) local CRD_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p" manifests/crds/kustomization.yaml)
local MOD_VERSION=$(go list -m -f '{{ .Version }}' "github.com/fluxcd/$1/api")
local API_PKG="github.com/fluxcd/$1/api"
if [[ "$1" == "source-watcher" ]]; then
API_PKG="github.com/fluxcd/$1/api/v2"
fi
local MOD_VERSION=$(go list -m -f '{{ .Version }}' "$API_PKG")
local changed=false local changed=false
@@ -50,7 +61,7 @@ jobs:
fi fi
if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then
go mod edit -require="github.com/fluxcd/$1/api@${LATEST_VERSION}" go mod edit -require="$API_PKG@${LATEST_VERSION}"
make tidy make tidy
changed=true changed=true
fi fi
@@ -69,6 +80,7 @@ jobs:
bump_version notification-controller bump_version notification-controller
bump_version image-reflector-controller bump_version image-reflector-controller
bump_version image-automation-controller bump_version image-automation-controller
bump_version source-watcher
# diff change # diff change
git diff git diff
@@ -84,7 +96,7 @@ jobs:
- name: Create Pull Request - name: Create Pull Request
id: cpr id: cpr
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6 uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with: with:
token: ${{ secrets.BOT_GITHUB_TOKEN }} token: ${{ secrets.BOT_GITHUB_TOKEN }}
commit-message: | commit-message: |

View File

@@ -1,4 +1,6 @@
project_name: flux project_name: flux
changelog:
use: github-native
builds: builds:
- <<: &build_defaults - <<: &build_defaults
binary: flux binary: flux
@@ -86,22 +88,6 @@ brews:
generate_completions_from_executable(bin/"flux", "completion") generate_completions_from_executable(bin/"flux", "completion")
test: | test: |
system "#{bin}/flux --version" system "#{bin}/flux --version"
publishers:
- name: aur-pkg-bin
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-bin/publish.sh {{ .Version }}
- name: aur-pkg-scm
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-scm/publish.sh {{ .Version }}
- name: aur-pkg-go
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-go/publish.sh {{ .Version }}
dockers: dockers:
- image_templates: - image_templates:
- 'fluxcd/flux-cli:{{ .Tag }}-amd64' - 'fluxcd/flux-cli:{{ .Tag }}-amd64'

5
.scorecard.yml Normal file
View File

@@ -0,0 +1,5 @@
annotations:
- checks:
- dangerous-workflow
reasons:
- reason: not-applicable # This workflow does not run untrusted code, the bot will only backport a code if the a PR was approved and merged into main.

View File

@@ -67,8 +67,8 @@ for source changes.
Prerequisites: Prerequisites:
* go >= 1.20 * go >= 1.24
* kubectl >= 1.24 * kubectl >= 1.30
* kustomize >= 5.0 * kustomize >= 5.0
* coreutils (on Mac OS) * coreutils (on Mac OS)

View File

@@ -1,16 +1,16 @@
FROM alpine:3.21 AS builder FROM alpine:3.22 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.32.2 ARG KUBECTL_VER=1.34.1
RUN curl -sL https://dl.k8s.io/release/v${KUBECTL_VER}/bin/${ARCH}/kubectl \ RUN curl -sL https://dl.k8s.io/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
RUN kubectl version --client=true RUN kubectl version --client=true
FROM alpine:3.21 AS flux-cli FROM alpine:3.22 AS flux-cli
RUN apk add --no-cache ca-certificates RUN apk add --no-cache ca-certificates

View File

@@ -17,8 +17,8 @@ rwildcard=$(foreach d,$(wildcard $(addsuffix *,$(1))),$(call rwildcard,$(d)/,$(2
all: test build all: test build
tidy: tidy:
go mod tidy -compat=1.23 go mod tidy -compat=1.25
cd tests/integration && go mod tidy -compat=1.23 cd tests/integration && go mod tidy -compat=1.25
fmt: fmt:
go fmt ./... go fmt ./...

View File

@@ -16,23 +16,24 @@ inputs:
description: "Alternative location for the Flux binary, defaults to path relative to $RUNNER_TOOL_CACHE." description: "Alternative location for the Flux binary, defaults to path relative to $RUNNER_TOOL_CACHE."
required: false required: false
token: token:
description: "Token used to authentication against the GitHub.com API. Defaults to the token from the GitHub context of the workflow." description: "Token used to authenticate against the GitHub.com API."
required: false required: false
runs: runs:
using: composite using: composite
steps: steps:
- name: "Download the binary to the runner's cache dir" - name: "Download the binary to the runner's cache dir"
shell: bash shell: bash
env:
VERSION: "${{ inputs.version }}"
FLUX_TOOL_DIR: "${{ inputs.bindir }}"
TOKEN: "${{ inputs.token }}"
run: | run: |
VERSION=${{ inputs.version }}
TOKEN=${{ inputs.token }}
if [[ -z "$TOKEN" ]]; then
TOKEN=${{ github.token }}
fi
if [[ -z "$VERSION" ]] || [[ "$VERSION" = "latest" ]]; then if [[ -z "$VERSION" ]] || [[ "$VERSION" = "latest" ]]; then
VERSION=$(curl -fsSL -H "Authorization: token ${TOKEN}" https://api.github.com/repos/fluxcd/flux2/releases/latest | grep tag_name | cut -d '"' -f 4) if [[ "${TOKEN}" != '' ]]; then
VERSION=$(curl -fsSL -H "Authorization: token ${TOKEN}" https://api.github.com/repos/fluxcd/flux2/releases/latest | grep tag_name | cut -d '"' -f 4)
else
VERSION=$(curl -w "%{url_effective}\n" -IsSL https://github.com/fluxcd/flux2/releases/latest -o /dev/null | sed 's$^.*/$$')
fi
fi fi
if [[ -z "$VERSION" ]]; then if [[ -z "$VERSION" ]]; then
echo "Unable to determine Flux CLI version" echo "Unable to determine Flux CLI version"
@@ -59,7 +60,6 @@ runs:
FLUX_EXEC_FILE="${FLUX_EXEC_FILE}.exe" FLUX_EXEC_FILE="${FLUX_EXEC_FILE}.exe"
fi fi
FLUX_TOOL_DIR=${{ inputs.bindir }}
if [[ -z "$FLUX_TOOL_DIR" ]]; then if [[ -z "$FLUX_TOOL_DIR" ]]; then
FLUX_TOOL_DIR="${RUNNER_TOOL_CACHE}/flux2/${VERSION}/${OS}/${ARCH}" FLUX_TOOL_DIR="${RUNNER_TOOL_CACHE}/flux2/${VERSION}/${OS}/${ARCH}"
fi fi

57
cmd/flux/artifact.go Normal file
View File

@@ -0,0 +1,57 @@
/*
Copyright 2025 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 (
"sigs.k8s.io/controller-runtime/pkg/client"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
)
// swapi.ArtifactGenerator
var artifactGeneratorType = apiType{
kind: swapi.ArtifactGeneratorKind,
humanKind: "artifactgenerator",
groupVersion: swapi.GroupVersion,
}
type artifactGeneratorAdapter struct {
*swapi.ArtifactGenerator
}
func (h artifactGeneratorAdapter) asClientObject() client.Object {
return h.ArtifactGenerator
}
func (h artifactGeneratorAdapter) deepCopyClientObject() client.Object {
return h.ArtifactGenerator.DeepCopy()
}
// swapi.ArtifactGeneratorList
type artifactGeneratorListAdapter struct {
*swapi.ArtifactGeneratorList
}
func (h artifactGeneratorListAdapter) asClientList() client.ObjectList {
return h.ArtifactGeneratorList
}
func (h artifactGeneratorListAdapter) len() int {
return len(h.ArtifactGeneratorList.Items)
}

View File

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

View File

@@ -42,7 +42,7 @@ import (
var bootstrapGitLabCmd = &cobra.Command{ var bootstrapGitLabCmd = &cobra.Command{
Use: "gitlab", Use: "gitlab",
Short: "Deploy Flux on a cluster connected to a GitLab repository", Short: "Deploy Flux on a cluster connected to a GitLab repository",
Long: `The bootstrap gitlab command creates the GitLab repository if it doesn't exists and Long: `The bootstrap gitlab command creates the GitLab repository if it doesn't exist and
commits the Flux manifests to the specified branch. commits the Flux manifests to the specified branch.
Then it configures the target cluster to synchronize with that repository. Then it configures the target cluster to synchronize with that repository.
If the Flux components are present on the cluster, If the Flux components are present on the cluster,

View File

@@ -26,15 +26,15 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
oci "github.com/fluxcd/pkg/oci/client" "github.com/fluxcd/pkg/oci"
"github.com/fluxcd/pkg/sourceignore" "github.com/fluxcd/pkg/sourceignore"
) )
var buildArtifactCmd = &cobra.Command{ var buildArtifactCmd = &cobra.Command{
Use: "artifact", Use: "artifact",
Short: "Build artifact", Short: "Build artifact",
Long: withPreviewNote(`The build artifact command creates a tgz file with the manifests Long: `The build artifact command creates a tgz file with the manifests
from the given directory or a single manifest file.`), from the given directory or a single manifest file.`,
Example: ` # Build the given manifests directory into an artifact Example: ` # Build the given manifests directory into an artifact
flux build artifact --path ./path/to/local/manifests --output ./path/to/artifact.tgz flux build artifact --path ./path/to/local/manifests --output ./path/to/artifact.tgz

View File

@@ -169,6 +169,12 @@ spec:
resultFile: "./testdata/build-kustomization/podinfo-with-my-app-result.yaml", resultFile: "./testdata/build-kustomization/podinfo-with-my-app-result.yaml",
assertFunc: "assertGoldenTemplateFile", assertFunc: "assertGoldenTemplateFile",
}, },
{
name: "build with recursive in dry-run mode",
args: "build kustomization podinfo --kustomization-file " + tmpFile + " --path ./testdata/build-kustomization/podinfo-with-my-app --recursive --local-sources GitRepository/default/podinfo=./testdata/build-kustomization --dry-run",
resultFile: "./testdata/build-kustomization/podinfo-with-my-app-result.yaml",
assertFunc: "assertGoldenTemplateFile",
},
} }
tmpl := map[string]string{ tmpl := map[string]string{

View File

@@ -60,7 +60,7 @@ type checkFlags struct {
} }
var kubernetesConstraints = []string{ var kubernetesConstraints = []string{
">=1.30.0-0", ">=1.32.0-0",
} }
var checkArgs checkFlags var checkArgs checkFlags
@@ -217,7 +217,7 @@ func componentsCheck(ctx context.Context, kubeClient client.Client) bool {
} }
} }
for _, c := range d.Spec.Template.Spec.Containers { for _, c := range d.Spec.Template.Spec.Containers {
logger.Actionf(c.Image) logger.Actionf("%s", c.Image)
} }
} }
} }
@@ -238,7 +238,7 @@ func crdsCheck(ctx context.Context, kubeClient client.Client) bool {
for _, crd := range list.Items { for _, crd := range list.Items {
versions := crd.Status.StoredVersions versions := crd.Status.StoredVersions
if len(versions) > 0 { if len(versions) > 0 {
logger.Successf(crd.Name + "/" + versions[len(versions)-1]) logger.Successf("%s", crd.Name+"/"+versions[len(versions)-1])
} else { } else {
ok = false ok = false
logger.Failuref("no stored versions for %s", crd.Name) logger.Failuref("no stored versions for %s", crd.Name)

View File

@@ -37,7 +37,6 @@ import (
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/transform" "github.com/fluxcd/pkg/runtime/transform"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/v2/internal/flags" "github.com/fluxcd/flux2/v2/internal/flags"
"github.com/fluxcd/flux2/v2/internal/utils" "github.com/fluxcd/flux2/v2/internal/utils"
@@ -95,6 +94,13 @@ var createHelmReleaseCmd = &cobra.Command{
--source=HelmRepository/podinfo \ --source=HelmRepository/podinfo \
--chart=podinfo --chart=podinfo
# Create a HelmRelease with custom storage namespace for hub-and-spoke model
flux create hr podinfo \
--target-namespace=production \
--storage-namespace=fluxcd-system \
--source=HelmRepository/podinfo \
--chart=podinfo
# Create a HelmRelease using a source from a different namespace # Create a HelmRelease using a source from a different namespace
flux create hr podinfo \ flux create hr podinfo \
--namespace=default \ --namespace=default \
@@ -128,6 +134,7 @@ type helmReleaseFlags struct {
chartVersion string chartVersion string
chartRef string chartRef string
targetNamespace string targetNamespace string
storageNamespace string
createNamespace bool createNamespace bool
valuesFiles []string valuesFiles []string
valuesFrom []string valuesFrom []string
@@ -142,7 +149,7 @@ var helmReleaseArgs helmReleaseFlags
var supportedHelmReleaseValuesFromKinds = []string{"Secret", "ConfigMap"} var supportedHelmReleaseValuesFromKinds = []string{"Secret", "ConfigMap"}
var supportedHelmReleaseReferenceKinds = []string{sourcev1b2.OCIRepositoryKind, sourcev1.HelmChartKind} var supportedHelmReleaseReferenceKinds = []string{sourcev1.OCIRepositoryKind, sourcev1.HelmChartKind}
func init() { func init() {
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.name, "release-name", "", "name used for the Helm release, defaults to a composition of '[<target-namespace>-]<HelmRelease-name>'") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.name, "release-name", "", "name used for the Helm release, defaults to a composition of '[<target-namespace>-]<HelmRelease-name>'")
@@ -151,6 +158,7 @@ func init() {
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
createHelmReleaseCmd.Flags().StringSliceVar(&helmReleaseArgs.dependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'") createHelmReleaseCmd.Flags().StringSliceVar(&helmReleaseArgs.dependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.storageNamespace, "storage-namespace", "", "namespace to store the Helm release, defaults to the target namespace")
createHelmReleaseCmd.Flags().BoolVar(&helmReleaseArgs.createNamespace, "create-target-namespace", false, "create the target namespace if it does not exist") createHelmReleaseCmd.Flags().BoolVar(&helmReleaseArgs.createNamespace, "create-target-namespace", false, "create the target namespace if it does not exist")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.reconcileStrategy, "reconcile-strategy", "ChartVersion", "the reconcile strategy for helm chart created by the helm release(accepted values: Revision and ChartRevision)") createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.reconcileStrategy, "reconcile-strategy", "ChartVersion", "the reconcile strategy for helm chart created by the helm release(accepted values: Revision and ChartRevision)")
@@ -166,6 +174,10 @@ func init() {
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error { func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
name := args[0] name := args[0]
if helmReleaseArgs.storageNamespace == "" && helmReleaseArgs.targetNamespace != "" {
helmReleaseArgs.storageNamespace = helmReleaseArgs.targetNamespace
}
if helmReleaseArgs.chart == "" && helmReleaseArgs.chartRef == "" { if helmReleaseArgs.chart == "" && helmReleaseArgs.chartRef == "" {
return fmt.Errorf("chart or chart-ref is required") return fmt.Errorf("chart or chart-ref is required")
} }
@@ -192,15 +204,27 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
}, },
Spec: helmv2.HelmReleaseSpec{ Spec: helmv2.HelmReleaseSpec{
ReleaseName: helmReleaseArgs.name, ReleaseName: helmReleaseArgs.name,
DependsOn: utils.MakeDependsOn(helmReleaseArgs.dependsOn),
Interval: metav1.Duration{ Interval: metav1.Duration{
Duration: createArgs.interval, Duration: createArgs.interval,
}, },
TargetNamespace: helmReleaseArgs.targetNamespace, TargetNamespace: helmReleaseArgs.targetNamespace,
Suspend: false, StorageNamespace: helmReleaseArgs.storageNamespace,
Suspend: false,
}, },
} }
if len(helmReleaseArgs.dependsOn) > 0 {
ls := utils.MakeDependsOn(helmReleaseArgs.dependsOn)
hrDependsOn := make([]helmv2.DependencyReference, 0, len(ls))
for _, d := range ls {
hrDependsOn = append(hrDependsOn, helmv2.DependencyReference{
Name: d.Name,
Namespace: d.Namespace,
})
}
helmRelease.Spec.DependsOn = hrDependsOn
}
switch { switch {
case helmReleaseArgs.chart != "": case helmReleaseArgs.chart != "":
helmRelease.Spec.Chart = &helmv2.HelmChartTemplate{ helmRelease.Spec.Chart = &helmv2.HelmChartTemplate{
@@ -222,7 +246,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
} }
case helmReleaseArgs.chartRef != "": case helmReleaseArgs.chartRef != "":
kind, name, ns := utils.ParseObjectKindNameNamespace(helmReleaseArgs.chartRef) kind, name, ns := utils.ParseObjectKindNameNamespace(helmReleaseArgs.chartRef)
if kind != sourcev1.HelmChartKind && kind != sourcev1b2.OCIRepositoryKind { if kind != sourcev1.HelmChartKind && kind != sourcev1.OCIRepositoryKind {
return fmt.Errorf("chart reference kind '%s' is not supported, must be one of: %s", return fmt.Errorf("chart reference kind '%s' is not supported, must be one of: %s",
kind, strings.Join(supportedHelmReleaseReferenceKinds, ", ")) kind, strings.Join(supportedHelmReleaseReferenceKinds, ", "))
} }
@@ -235,7 +259,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if helmReleaseArgs.kubeConfigSecretRef != "" { if helmReleaseArgs.kubeConfigSecretRef != "" {
helmRelease.Spec.KubeConfig = &meta.KubeConfigReference{ helmRelease.Spec.KubeConfig = &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{ SecretRef: &meta.SecretKeyReference{
Name: helmReleaseArgs.kubeConfigSecretRef, Name: helmReleaseArgs.kubeConfigSecretRef,
}, },
} }

View File

@@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"regexp/syntax" "regexp/syntax"
"strings" "strings"
"time"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@@ -28,18 +29,18 @@ import (
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var createImagePolicyCmd = &cobra.Command{ var createImagePolicyCmd = &cobra.Command{
Use: "policy [name]", Use: "policy [name]",
Short: "Create or update an ImagePolicy object", Short: "Create or update an ImagePolicy object",
Long: withPreviewNote(`The create image policy command generates an ImagePolicy resource. Long: `The create image policy command generates an ImagePolicy resource.
An ImagePolicy object calculates a "latest image" given an image An ImagePolicy object calculates a "latest image" given an image
repository and a policy, e.g., semver. repository and a policy, e.g., semver.
The image that sorts highest according to the policy is recorded in The image that sorts highest according to the policy is recorded in
the status of the object.`), the status of the object.`,
Example: ` # Create an ImagePolicy to select the latest stable release Example: ` # Create an ImagePolicy to select the latest stable release
flux create image policy podinfo \ flux create image policy podinfo \
--image-ref=podinfo \ --image-ref=podinfo \
@@ -60,6 +61,8 @@ type imagePolicyFlags struct {
numeric string numeric string
filterRegex string filterRegex string
filterExtract string filterExtract string
reflectDigest string
interval time.Duration
} }
var imagePolicyArgs = imagePolicyFlags{} var imagePolicyArgs = imagePolicyFlags{}
@@ -72,16 +75,12 @@ func init() {
flags.StringVar(&imagePolicyArgs.numeric, "select-numeric", "", "use numeric sorting to select image; either \"asc\" meaning select the last, or \"desc\" meaning select the first") flags.StringVar(&imagePolicyArgs.numeric, "select-numeric", "", "use numeric sorting to select image; either \"asc\" meaning select the last, or \"desc\" meaning select the first")
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", "regular expression pattern used to filter the image tags") flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", "regular expression pattern used to filter the image tags")
flags.StringVar(&imagePolicyArgs.filterExtract, "filter-extract", "", "replacement pattern (using capture groups from --filter-regex) to use for sorting") flags.StringVar(&imagePolicyArgs.filterExtract, "filter-extract", "", "replacement pattern (using capture groups from --filter-regex) to use for sorting")
flags.StringVar(&imagePolicyArgs.reflectDigest, "reflect-digest", "", "the digest reflection policy to use when observing latest image tags (one of 'Never', 'IfNotPresent', 'Never')")
flags.DurationVar(&imagePolicyArgs.interval, "interval", 0, "the interval at which to check for new image digests when the policy is set to 'Always'")
createImageCmd.AddCommand(createImagePolicyCmd) createImageCmd.AddCommand(createImagePolicyCmd)
} }
// getObservedGeneration is implemented here, since it's not
// (presently) needed elsewhere.
func (obj imagePolicyAdapter) getObservedGeneration() int64 {
return obj.ImagePolicy.Status.ObservedGeneration
}
func createImagePolicyRun(cmd *cobra.Command, args []string) error { func createImagePolicyRun(cmd *cobra.Command, args []string) error {
objectName := args[0] objectName := args[0]
@@ -153,6 +152,20 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("cannot specify --filter-extract without specifying --filter-regex") return fmt.Errorf("cannot specify --filter-extract without specifying --filter-regex")
} }
if p := imagev1.ReflectionPolicy(imagePolicyArgs.reflectDigest); p != "" {
if p != imagev1.ReflectNever && p != imagev1.ReflectIfNotPresent && p != imagev1.ReflectAlways {
return fmt.Errorf("invalid value for --reflect-digest, must be one of 'Never', 'IfNotPresent', 'Always'")
}
policy.Spec.DigestReflectionPolicy = p
}
if imagePolicyArgs.interval != 0 {
if imagePolicyArgs.reflectDigest != string(imagev1.ReflectAlways) {
return fmt.Errorf("the --interval flag can only be used with the 'Always' digest reflection policy, use --reflect-digest=Always")
}
policy.Spec.Interval = &metav1.Duration{Duration: imagePolicyArgs.interval}
}
if createArgs.export { if createArgs.export {
return printExport(exportImagePolicy(&policy)) return printExport(exportImagePolicy(&policy))
} }

View File

@@ -26,14 +26,14 @@ import (
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var createImageRepositoryCmd = &cobra.Command{ var createImageRepositoryCmd = &cobra.Command{
Use: "repository [name]", Use: "repository [name]",
Short: "Create or update an ImageRepository object", Short: "Create or update an ImageRepository object",
Long: withPreviewNote(`The create image repository command generates an ImageRepository resource. Long: `The create image repository command generates an ImageRepository resource.
An ImageRepository object specifies an image repository to scan.`), An ImageRepository object specifies an image repository to scan.`,
Example: ` # Create an ImageRepository object to scan the alpine image repository: Example: ` # Create an ImageRepository object to scan the alpine image repository:
flux create image repository alpine-repo --image alpine --interval 20m flux create image repository alpine-repo --image alpine --interval 20m

View File

@@ -22,16 +22,16 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
) )
var createImageUpdateCmd = &cobra.Command{ var createImageUpdateCmd = &cobra.Command{
Use: "update [name]", Use: "update [name]",
Short: "Create or update an ImageUpdateAutomation object", Short: "Create or update an ImageUpdateAutomation object",
Long: withPreviewNote(`The create image update command generates an ImageUpdateAutomation resource. Long: `The create image update command generates an ImageUpdateAutomation resource.
An ImageUpdateAutomation object specifies an automated update to images An ImageUpdateAutomation object specifies an automated update to images
mentioned in YAMLs in a git repository.`), mentioned in YAMLs in a git repository.`,
Example: ` # Configure image updates for the main repository created by flux bootstrap Example: ` # Configure image updates for the main repository created by flux bootstrap
flux create image update flux-system \ flux create image update flux-system \
--git-repo-ref=flux-system \ --git-repo-ref=flux-system \

View File

@@ -153,7 +153,6 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
Labels: kslabels, Labels: kslabels,
}, },
Spec: kustomizev1.KustomizationSpec{ Spec: kustomizev1.KustomizationSpec{
DependsOn: utils.MakeDependsOn(kustomizationArgs.dependsOn),
Interval: metav1.Duration{ Interval: metav1.Duration{
Duration: createArgs.interval, Duration: createArgs.interval,
}, },
@@ -169,9 +168,21 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
}, },
} }
if len(kustomizationArgs.dependsOn) > 0 {
ls := utils.MakeDependsOn(kustomizationArgs.dependsOn)
ksDependsOn := make([]kustomizev1.DependencyReference, 0, len(ls))
for _, d := range ls {
ksDependsOn = append(ksDependsOn, kustomizev1.DependencyReference{
Name: d.Name,
Namespace: d.Namespace,
})
}
kustomization.Spec.DependsOn = ksDependsOn
}
if kustomizationArgs.kubeConfigSecretRef != "" { if kustomizationArgs.kubeConfigSecretRef != "" {
kustomization.Spec.KubeConfig = &meta.KubeConfigReference{ kustomization.Spec.KubeConfig = &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{ SecretRef: &meta.SecretKeyReference{
Name: kustomizationArgs.kubeConfigSecretRef, Name: kustomizationArgs.kubeConfigSecretRef,
}, },
} }

View File

@@ -172,7 +172,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme) return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateGit(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -99,7 +99,7 @@ func createSecretGitHubAppCmdRun(cmd *cobra.Command, args []string) error {
opts.GitHubAppBaseURL = secretGitHubAppArgs.baseURL opts.GitHubAppBaseURL = secretGitHubAppArgs.baseURL
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateGitHubApp(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -83,10 +83,12 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
} }
var certFile, keyFile []byte var certFile, keyFile []byte
if secretHelmArgs.tlsCrtFile != "" && secretHelmArgs.tlsKeyFile != "" { if secretHelmArgs.tlsCrtFile != "" {
if certFile, err = os.ReadFile(secretHelmArgs.tlsCrtFile); err != nil { if certFile, err = os.ReadFile(secretHelmArgs.tlsCrtFile); err != nil {
return fmt.Errorf("failed to read cert file: %w", err) return fmt.Errorf("failed to read cert file: %w", err)
} }
}
if secretHelmArgs.tlsKeyFile != "" {
if keyFile, err = os.ReadFile(secretHelmArgs.tlsKeyFile); err != nil { if keyFile, err = os.ReadFile(secretHelmArgs.tlsKeyFile); err != nil {
return fmt.Errorf("failed to read key file: %w", err) return fmt.Errorf("failed to read key file: %w", err)
} }
@@ -102,7 +104,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
TLSCrt: certFile, TLSCrt: certFile,
TLSKey: keyFile, TLSKey: keyFile,
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateHelm(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -132,7 +132,7 @@ func createSecretNotationCmdRun(cmd *cobra.Command, args []string) error {
VerificationCrts: caCerts, VerificationCrts: caCerts,
TrustPolicy: policy, TrustPolicy: policy,
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateNotation(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -92,7 +92,7 @@ func createSecretOCICmdRun(cmd *cobra.Command, args []string) error {
Username: secretOCIArgs.username, Username: secretOCIArgs.username,
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateOCI(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -83,7 +83,7 @@ func createSecretProxyCmdRun(cmd *cobra.Command, args []string) error {
Username: secretProxyArgs.username, Username: secretProxyArgs.username,
Password: secretProxyArgs.password, Password: secretProxyArgs.password,
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateProxy(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -84,16 +84,18 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
if secretTLSArgs.tlsCrtFile != "" && secretTLSArgs.tlsKeyFile != "" { if secretTLSArgs.tlsCrtFile != "" {
if opts.TLSCrt, err = os.ReadFile(secretTLSArgs.tlsCrtFile); err != nil { if opts.TLSCrt, err = os.ReadFile(secretTLSArgs.tlsCrtFile); err != nil {
return fmt.Errorf("failed to read cert file: %w", err) return fmt.Errorf("failed to read cert file: %w", err)
} }
}
if secretTLSArgs.tlsKeyFile != "" {
if opts.TLSKey, err = os.ReadFile(secretTLSArgs.tlsKeyFile); err != nil { if opts.TLSKey, err = os.ReadFile(secretTLSArgs.tlsKeyFile); err != nil {
return fmt.Errorf("failed to read key file: %w", err) return fmt.Errorf("failed to read key file: %w", err)
} }
} }
secret, err := sourcesecret.Generate(opts) secret, err := sourcesecret.GenerateTLS(opts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -19,7 +19,6 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -114,12 +113,6 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
tmpDir, err := os.MkdirTemp("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
var ignorePaths *string var ignorePaths *string
if len(sourceBucketArgs.ignorePaths) > 0 { if len(sourceBucketArgs.ignorePaths) > 0 {
ignorePathsStr := strings.Join(sourceBucketArgs.ignorePaths, "\n") ignorePathsStr := strings.Join(sourceBucketArgs.ignorePaths, "\n")

View File

@@ -44,25 +44,26 @@ import (
) )
type sourceGitFlags struct { type sourceGitFlags struct {
url string url string
branch string branch string
tag string tag string
semver string semver string
refName string refName string
commit string commit string
username string username string
password string password string
keyAlgorithm flags.PublicKeyAlgorithm keyAlgorithm flags.PublicKeyAlgorithm
keyRSABits flags.RSAKeyBits keyRSABits flags.RSAKeyBits
keyECDSACurve flags.ECDSACurve keyECDSACurve flags.ECDSACurve
secretRef string secretRef string
proxySecretRef string proxySecretRef string
provider flags.SourceGitProvider provider flags.SourceGitProvider
caFile string caFile string
privateKeyFile string privateKeyFile string
recurseSubmodules bool recurseSubmodules bool
silent bool silent bool
ignorePaths []string ignorePaths []string
sparseCheckoutPaths []string
} }
var createSourceGitCmd = &cobra.Command{ var createSourceGitCmd = &cobra.Command{
@@ -138,7 +139,7 @@ func init() {
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.branch, "branch", "", "git branch") createSourceGitCmd.Flags().StringVar(&sourceGitArgs.branch, "branch", "", "git branch")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.tag, "tag", "", "git tag") createSourceGitCmd.Flags().StringVar(&sourceGitArgs.tag, "tag", "", "git tag")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.semver, "tag-semver", "", "git tag semver range") createSourceGitCmd.Flags().StringVar(&sourceGitArgs.semver, "tag-semver", "", "git tag semver range")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.refName, "ref-name", "", " git reference name") createSourceGitCmd.Flags().StringVar(&sourceGitArgs.refName, "ref-name", "", "git reference name")
createSourceGitCmd.Flags().StringVar(&sourceGitArgs.commit, "commit", "", "git commit") createSourceGitCmd.Flags().StringVar(&sourceGitArgs.commit, "commit", "", "git commit")
createSourceGitCmd.Flags().StringVarP(&sourceGitArgs.username, "username", "u", "", "basic authentication username") createSourceGitCmd.Flags().StringVarP(&sourceGitArgs.username, "username", "u", "", "basic authentication username")
createSourceGitCmd.Flags().StringVarP(&sourceGitArgs.password, "password", "p", "", "basic authentication password") createSourceGitCmd.Flags().StringVarP(&sourceGitArgs.password, "password", "p", "", "basic authentication password")
@@ -154,6 +155,7 @@ func init() {
"when enabled, configures the GitRepository source to initialize and include Git submodules in the artifact it produces") "when enabled, configures the GitRepository source to initialize and include Git submodules in the artifact it produces")
createSourceGitCmd.Flags().BoolVarP(&sourceGitArgs.silent, "silent", "s", false, "assumes the deploy key is already setup, skips confirmation") createSourceGitCmd.Flags().BoolVarP(&sourceGitArgs.silent, "silent", "s", false, "assumes the deploy key is already setup, skips confirmation")
createSourceGitCmd.Flags().StringSliceVar(&sourceGitArgs.ignorePaths, "ignore-paths", nil, "set paths to ignore in git resource (can specify multiple paths with commas: path1,path2)") createSourceGitCmd.Flags().StringSliceVar(&sourceGitArgs.ignorePaths, "ignore-paths", nil, "set paths to ignore in git resource (can specify multiple paths with commas: path1,path2)")
createSourceGitCmd.Flags().StringSliceVar(&sourceGitArgs.sparseCheckoutPaths, "sparse-checkout-paths", nil, "set paths to sparse checkout in git resource (can specify multiple paths with commas: path1,path2)")
createSourceCmd.AddCommand(createSourceGitCmd) createSourceCmd.AddCommand(createSourceGitCmd)
} }
@@ -189,12 +191,6 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("specifying a CA file is not supported for Git over SSH") return fmt.Errorf("specifying a CA file is not supported for Git over SSH")
} }
tmpDir, err := os.MkdirTemp("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
sourceLabels, err := parseLabels() sourceLabels, err := parseLabels()
if err != nil { if err != nil {
return err return err
@@ -220,6 +216,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
RecurseSubmodules: sourceGitArgs.recurseSubmodules, RecurseSubmodules: sourceGitArgs.recurseSubmodules,
Reference: &sourcev1.GitRepositoryRef{}, Reference: &sourcev1.GitRepositoryRef{},
Ignore: ignorePaths, Ignore: ignorePaths,
SparseCheckout: sourceGitArgs.sparseCheckoutPaths,
}, },
} }
@@ -302,7 +299,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
secretOpts.Username = sourceGitArgs.username secretOpts.Username = sourceGitArgs.username
secretOpts.Password = sourceGitArgs.password secretOpts.Password = sourceGitArgs.password
} }
secret, err := sourcesecret.Generate(secretOpts) secret, err := sourcesecret.GenerateGit(secretOpts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -87,7 +87,7 @@ func (r *reconciler) conditionFunc() (bool, error) {
} }
func TestCreateSourceGitExport(t *testing.T) { func TestCreateSourceGitExport(t *testing.T) {
var command = "create source git podinfo --url=https://github.com/stefanprodan/podinfo --branch=master --ignore-paths .cosign,non-existent-dir/ -n default --interval 1m --export --timeout=" + testTimeout.String() var command = "create source git podinfo --url=https://github.com/stefanprodan/podinfo --branch=master --sparse-checkout-paths .cosign,non-existent-dir/ --ignore-paths .cosign,non-existent-dir/ -n default --interval 1m --export --timeout=" + testTimeout.String()
cases := []struct { cases := []struct {
name string name string
@@ -101,7 +101,7 @@ func TestCreateSourceGitExport(t *testing.T) {
}, },
{ {
name: "no args", name: "no args",
args: "create secret git", args: "create source git --url=https://github.com/stefanprodan/podinfo",
assert: assertError("name is required"), assert: assertError("name is required"),
}, },
{ {
@@ -204,12 +204,13 @@ func TestCreateSourceGit(t *testing.T) {
ObservedGeneration: repo.GetGeneration(), ObservedGeneration: repo.GetGeneration(),
} }
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition) apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
repo.Status.Artifact = &sourcev1.Artifact{ repo.Status.Artifact = &meta.Artifact{
Path: "some-path", Path: "some-path",
Revision: "v1", Revision: "v1",
LastUpdateTime: metav1.Time{ LastUpdateTime: metav1.Time{
Time: time.Now(), Time: time.Now(),
}, },
Digest: "sha256:1234567890abcdef",
} }
repo.Status.ObservedGeneration = repo.GetGeneration() repo.Status.ObservedGeneration = repo.GetGeneration()
}, },

View File

@@ -114,12 +114,6 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
tmpDir, err := os.MkdirTemp("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if _, err := url.Parse(sourceHelmArgs.url); err != nil { if _, err := url.Parse(sourceHelmArgs.url); err != nil {
return fmt.Errorf("url parse failed: %w", err) return fmt.Errorf("url parse failed: %w", err)
} }
@@ -202,7 +196,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
TLSKey: keyFile, TLSKey: keyFile,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile, ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
} }
secret, err := sourcesecret.Generate(secretOpts) secret, err := sourcesecret.GenerateHelm(secretOpts)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -29,9 +29,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/v2/internal/flags" "github.com/fluxcd/flux2/v2/internal/flags"
"github.com/fluxcd/flux2/v2/internal/utils" "github.com/fluxcd/flux2/v2/internal/utils"
@@ -81,7 +79,7 @@ var sourceOCIRepositoryArgs = newSourceOCIFlags()
func newSourceOCIFlags() sourceOCIRepositoryFlags { func newSourceOCIFlags() sourceOCIRepositoryFlags {
return sourceOCIRepositoryFlags{ return sourceOCIRepositoryFlags{
provider: flags.SourceOCIProvider(sourcev1b2.GenericOCIProvider), provider: flags.SourceOCIProvider(sourcev1.GenericOCIProvider),
} }
} }
@@ -127,20 +125,20 @@ func createSourceOCIRepositoryCmdRun(cmd *cobra.Command, args []string) error {
ignorePaths = &ignorePathsStr ignorePaths = &ignorePathsStr
} }
repository := &sourcev1b2.OCIRepository{ repository := &sourcev1.OCIRepository{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: *kubeconfigArgs.Namespace, Namespace: *kubeconfigArgs.Namespace,
Labels: sourceLabels, Labels: sourceLabels,
}, },
Spec: sourcev1b2.OCIRepositorySpec{ Spec: sourcev1.OCIRepositorySpec{
Provider: sourceOCIRepositoryArgs.provider.String(), Provider: sourceOCIRepositoryArgs.provider.String(),
URL: sourceOCIRepositoryArgs.url, URL: sourceOCIRepositoryArgs.url,
Insecure: sourceOCIRepositoryArgs.insecure, Insecure: sourceOCIRepositoryArgs.insecure,
Interval: metav1.Duration{ Interval: metav1.Duration{
Duration: createArgs.interval, Duration: createArgs.interval,
}, },
Reference: &sourcev1b2.OCIRepositoryRef{}, Reference: &sourcev1.OCIRepositoryRef{},
Ignore: ignorePaths, Ignore: ignorePaths,
}, },
} }
@@ -237,13 +235,13 @@ func createSourceOCIRepositoryCmdRun(cmd *cobra.Command, args []string) error {
} }
func upsertOCIRepository(ctx context.Context, kubeClient client.Client, func upsertOCIRepository(ctx context.Context, kubeClient client.Client,
ociRepository *sourcev1b2.OCIRepository) (types.NamespacedName, error) { ociRepository *sourcev1.OCIRepository) (types.NamespacedName, error) {
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: ociRepository.GetNamespace(), Namespace: ociRepository.GetNamespace(),
Name: ociRepository.GetName(), Name: ociRepository.GetName(),
} }
var existing sourcev1b2.OCIRepository var existing sourcev1.OCIRepository
err := kubeClient.Get(ctx, namespacedName, &existing) err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {

View File

@@ -21,7 +21,6 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/fluxcd/flux2/v2/internal/utils"
"github.com/spf13/cobra" "github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1" rbacv1 "k8s.io/api/rbac/v1"
@@ -32,6 +31,8 @@ import (
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/v2/internal/utils"
) )
var createTenantCmd = &cobra.Command{ var createTenantCmd = &cobra.Command{
@@ -59,6 +60,7 @@ const (
type tenantFlags struct { type tenantFlags struct {
namespaces []string namespaces []string
clusterRole string clusterRole string
account string
} }
var tenantArgs tenantFlags var tenantArgs tenantFlags
@@ -66,6 +68,7 @@ var tenantArgs tenantFlags
func init() { func init() {
createTenantCmd.Flags().StringSliceVar(&tenantArgs.namespaces, "with-namespace", nil, "namespace belonging to this tenant") createTenantCmd.Flags().StringSliceVar(&tenantArgs.namespaces, "with-namespace", nil, "namespace belonging to this tenant")
createTenantCmd.Flags().StringVar(&tenantArgs.clusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding") createTenantCmd.Flags().StringVar(&tenantArgs.clusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
createTenantCmd.Flags().StringVar(&tenantArgs.account, "with-service-account", "", "service account belonging to this tenant")
createCmd.AddCommand(createTenantCmd) createCmd.AddCommand(createTenantCmd)
} }
@@ -107,9 +110,17 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
} }
namespaces = append(namespaces, namespace) namespaces = append(namespaces, namespace)
accountName := tenant
if tenantArgs.account != "" {
accountName = tenantArgs.account
}
if err := validation.IsQualifiedName(accountName); len(err) > 0 {
return fmt.Errorf("invalid service-account name '%s': %v", accountName, err)
}
account := corev1.ServiceAccount{ account := corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: tenant, Name: accountName,
Namespace: ns, Namespace: ns,
Labels: objLabels, Labels: objLabels,
}, },
@@ -131,7 +142,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
}, },
{ {
Kind: "ServiceAccount", Kind: "ServiceAccount",
Name: tenant, Name: accountName,
Namespace: ns, Namespace: ns,
}, },
}, },
@@ -282,10 +293,10 @@ func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, rol
if err != nil { if err != nil {
return err return err
} }
fmt.Println("---")
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1) data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data))
printlnStdout("---")
printlnStdout(resourceToString(data))
account.TypeMeta = metav1.TypeMeta{ account.TypeMeta = metav1.TypeMeta{
APIVersion: "v1", APIVersion: "v1",
@@ -295,10 +306,10 @@ func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, rol
if err != nil { if err != nil {
return err return err
} }
fmt.Println("---")
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1) data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data))
printlnStdout("---")
printlnStdout(resourceToString(data))
roleBinding.TypeMeta = metav1.TypeMeta{ roleBinding.TypeMeta = metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1", APIVersion: "rbac.authorization.k8s.io/v1",
@@ -309,8 +320,8 @@ func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, rol
return err return err
} }
fmt.Println("---") printlnStdout("---")
fmt.Println(resourceToString(data)) printlnStdout(resourceToString(data))
return nil return nil
} }

View File

@@ -0,0 +1,68 @@
//go:build e2e
// +build e2e
/*
Copyright 2025 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 TestCreateTenant(t *testing.T) {
tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "no args",
args: "create tenant",
assert: assertError("name is required"),
},
{
name: "no namespace",
args: "create tenant dev-team --cluster-role=cluster-admin",
assert: assertError("with-namespace is required"),
},
{
name: "basic tenant",
args: "create tenant dev-team --with-namespace=apps --cluster-role=cluster-admin --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-basic.yaml"),
},
{
name: "tenant with custom serviceaccount",
args: "create tenant dev-team --with-namespace=apps --cluster-role=cluster-admin --with-service-account=flux-tenant --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-with-service-account.yaml"),
},
{
name: "tenant with custom cluster role",
args: "create tenant dev-team --with-namespace=apps --cluster-role=custom-role --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-with-cluster-role.yaml"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args,
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}

View File

@@ -21,7 +21,6 @@ import (
"fmt" "fmt"
helmv2 "github.com/fluxcd/helm-controller/api/v2" helmv2 "github.com/fluxcd/helm-controller/api/v2"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/chartutil" "github.com/fluxcd/pkg/chartutil"
"github.com/go-logr/logr" "github.com/go-logr/logr"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -41,15 +40,19 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
flux debug hr podinfo --show-status flux debug hr podinfo --show-status
# Export the final values of a Helm release composed from referred ConfigMaps and Secrets # Export the final values of a Helm release composed from referred ConfigMaps and Secrets
flux debug hr podinfo --show-values > values.yaml`, flux debug hr podinfo --show-values > values.yaml
# Print the reconciliation history of a Helm release
flux debug hr podinfo --show-history`,
RunE: debugHelmReleaseCmdRun, RunE: debugHelmReleaseCmdRun,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
ValidArgsFunction: resourceNamesCompletionFunc(helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)), ValidArgsFunction: resourceNamesCompletionFunc(helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)),
} }
type debugHelmReleaseFlags struct { type debugHelmReleaseFlags struct {
showStatus bool showStatus bool
showValues bool showValues bool
showHistory bool
} }
var debugHelmReleaseArgs debugHelmReleaseFlags var debugHelmReleaseArgs debugHelmReleaseFlags
@@ -57,15 +60,25 @@ var debugHelmReleaseArgs debugHelmReleaseFlags
func init() { func init() {
debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showStatus, "show-status", false, "print the status of the Helm release") debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showStatus, "show-status", false, "print the status of the Helm release")
debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showValues, "show-values", false, "print the final values of the Helm release") debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showValues, "show-values", false, "print the final values of the Helm release")
debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showHistory, "show-history", false, "print the reconciliation history of the Helm release")
debugCmd.AddCommand(debugHelmReleaseCmd) debugCmd.AddCommand(debugHelmReleaseCmd)
} }
func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error { func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
name := args[0] name := args[0]
if (!debugHelmReleaseArgs.showStatus && !debugHelmReleaseArgs.showValues) || flagsSet := 0
(debugHelmReleaseArgs.showStatus && debugHelmReleaseArgs.showValues) { if debugHelmReleaseArgs.showStatus {
return fmt.Errorf("either --show-status or --show-values must be set") flagsSet++
}
if debugHelmReleaseArgs.showValues {
flagsSet++
}
if debugHelmReleaseArgs.showHistory {
flagsSet++
}
if flagsSet != 1 {
return fmt.Errorf("exactly one of --show-status, --show-values, or --show-history must be set")
} }
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
@@ -93,23 +106,12 @@ func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
} }
if debugHelmReleaseArgs.showValues { if debugHelmReleaseArgs.showValues {
// TODO(stefan): remove the mapping when helm-controller/api v1.2.0 has been released
var valuesRefs []meta.ValuesReference
for _, source := range hr.Spec.ValuesFrom {
valuesRefs = append(valuesRefs, meta.ValuesReference{
Kind: source.Kind,
Name: source.Name,
ValuesKey: source.ValuesKey,
Optional: source.Optional,
})
}
finalValues, err := chartutil.ChartValuesFromReferences(ctx, finalValues, err := chartutil.ChartValuesFromReferences(ctx,
logr.Discard(), logr.Discard(),
kubeClient, kubeClient,
hr.GetNamespace(), hr.GetNamespace(),
hr.GetValues(), hr.GetValues(),
valuesRefs...) hr.Spec.ValuesFrom...)
if err != nil { if err != nil {
return err return err
} }
@@ -121,5 +123,20 @@ func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
rootCmd.Print(string(values)) rootCmd.Print(string(values))
} }
if debugHelmReleaseArgs.showHistory {
if len(hr.Status.History) == 0 {
hr.Status.History = helmv2.Snapshots{}
}
history, err := yaml.Marshal(hr.Status.History)
if err != nil {
return err
}
rootCmd.Println("# History documentation: https://fluxcd.io/flux/components/helm/helmreleases/#history")
rootCmd.Print(string(history))
return nil
}
return nil return nil
} }

View File

@@ -56,6 +56,18 @@ func TestDebugHelmRelease(t *testing.T) {
"testdata/debug_helmrelease/values-from.golden.yaml", "testdata/debug_helmrelease/values-from.golden.yaml",
tmpl, tmpl,
}, },
{
"debug history",
"debug helmrelease test-with-history --show-history --show-status=false",
"testdata/debug_helmrelease/history.golden.yaml",
tmpl,
},
{
"debug history empty",
"debug helmrelease test-values-inline --show-history --show-status=false",
"testdata/debug_helmrelease/history-empty.golden.yaml",
tmpl,
},
} }
for _, tt := range cases { for _, tt := range cases {

View File

@@ -24,6 +24,7 @@ import (
"strings" "strings"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/kustomize" "github.com/fluxcd/pkg/kustomize"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -44,15 +45,19 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
flux debug ks podinfo --show-status flux debug ks podinfo --show-status
# Export the final variables used for post-build substitutions composed from referred ConfigMaps and Secrets # Export the final variables used for post-build substitutions composed from referred ConfigMaps and Secrets
flux debug ks podinfo --show-vars > vars.env`, flux debug ks podinfo --show-vars > vars.env
# Print the reconciliation history of a Flux Kustomization
flux debug ks podinfo --show-history`,
RunE: debugKustomizationCmdRun, RunE: debugKustomizationCmdRun,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)), ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
} }
type debugKustomizationFlags struct { type debugKustomizationFlags struct {
showStatus bool showStatus bool
showVars bool showVars bool
showHistory bool
} }
var debugKustomizationArgs debugKustomizationFlags var debugKustomizationArgs debugKustomizationFlags
@@ -60,15 +65,25 @@ var debugKustomizationArgs debugKustomizationFlags
func init() { func init() {
debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showStatus, "show-status", false, "print the status of the Flux Kustomization") debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showStatus, "show-status", false, "print the status of the Flux Kustomization")
debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showVars, "show-vars", false, "print the final vars of the Flux Kustomization in dot env format") debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showVars, "show-vars", false, "print the final vars of the Flux Kustomization in dot env format")
debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showHistory, "show-history", false, "print the reconciliation history of the Flux Kustomization")
debugCmd.AddCommand(debugKustomizationCmd) debugCmd.AddCommand(debugKustomizationCmd)
} }
func debugKustomizationCmdRun(cmd *cobra.Command, args []string) error { func debugKustomizationCmdRun(cmd *cobra.Command, args []string) error {
name := args[0] name := args[0]
if (!debugKustomizationArgs.showStatus && !debugKustomizationArgs.showVars) || flagsSet := 0
(debugKustomizationArgs.showStatus && debugKustomizationArgs.showVars) { if debugKustomizationArgs.showStatus {
return fmt.Errorf("either --show-status or --show-vars must be set") flagsSet++
}
if debugKustomizationArgs.showVars {
flagsSet++
}
if debugKustomizationArgs.showHistory {
flagsSet++
}
if flagsSet != 1 {
return fmt.Errorf("exactly one of --show-status, --show-vars, or --show-history must be set")
} }
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
@@ -130,5 +145,20 @@ func debugKustomizationCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
if debugKustomizationArgs.showHistory {
if len(ks.Status.History) == 0 {
ks.Status.History = meta.History{}
}
history, err := yaml.Marshal(ks.Status.History)
if err != nil {
return err
}
rootCmd.Println("# History documentation: https://fluxcd.io/flux/components/kustomize/kustomizations/#history")
rootCmd.Print(string(history))
return nil
}
return nil return nil
} }

View File

@@ -55,6 +55,17 @@ func TestDebugKustomization(t *testing.T) {
"debug ks test-from --show-vars --show-status=false", "debug ks test-from --show-vars --show-status=false",
"testdata/debug_kustomization/vars-from.golden.env", "testdata/debug_kustomization/vars-from.golden.env",
tmpl, tmpl,
}, {
"debug history",
"debug ks test-with-history --show-history --show-status=false",
"testdata/debug_kustomization/history.golden.yaml",
tmpl,
},
{
"debug history empty",
"debug ks test --show-history --show-status=false",
"testdata/debug_kustomization/history-empty.golden.yaml",
tmpl,
}, },
} }

View File

@@ -19,13 +19,13 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var deleteImagePolicyCmd = &cobra.Command{ var deleteImagePolicyCmd = &cobra.Command{
Use: "policy [name]", Use: "policy [name]",
Short: "Delete an ImagePolicy object", Short: "Delete an ImagePolicy object",
Long: withPreviewNote(`The delete image policy command deletes the given ImagePolicy from the cluster.`), Long: `The delete image policy command deletes the given ImagePolicy from the cluster.`,
Example: ` # Delete an image policy Example: ` # Delete an image policy
flux delete image policy alpine3.x`, flux delete image policy alpine3.x`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)), ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),

View File

@@ -19,13 +19,13 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var deleteImageRepositoryCmd = &cobra.Command{ var deleteImageRepositoryCmd = &cobra.Command{
Use: "repository [name]", Use: "repository [name]",
Short: "Delete an ImageRepository object", Short: "Delete an ImageRepository object",
Long: withPreviewNote("The delete image repository command deletes the given ImageRepository from the cluster."), Long: "The delete image repository command deletes the given ImageRepository from the cluster.",
Example: ` # Delete an image repository Example: ` # Delete an image repository
flux delete image repository alpine`, flux delete image repository alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)), ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)),

View File

@@ -19,13 +19,13 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
) )
var deleteImageUpdateCmd = &cobra.Command{ var deleteImageUpdateCmd = &cobra.Command{
Use: "update [name]", Use: "update [name]",
Short: "Delete an ImageUpdateAutomation object", Short: "Delete an ImageUpdateAutomation object",
Long: withPreviewNote(`The delete image update command deletes the given ImageUpdateAutomation from the cluster.`), Long: `The delete image update command deletes the given ImageUpdateAutomation from the cluster.`,
Example: ` # Delete an image update automation Example: ` # Delete an image update automation
flux delete image update latest-images`, flux delete image update latest-images`,
ValidArgsFunction: resourceNamesCompletionFunc(autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)), ValidArgsFunction: resourceNamesCompletionFunc(autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)),

View File

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

View File

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

View File

@@ -21,8 +21,9 @@ import (
"fmt" "fmt"
"os" "os"
oci "github.com/fluxcd/pkg/oci/client" "github.com/fluxcd/pkg/oci"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fluxcd/flux2/v2/internal/flags" "github.com/fluxcd/flux2/v2/internal/flags"
@@ -31,7 +32,7 @@ import (
var diffArtifactCmd = &cobra.Command{ var diffArtifactCmd = &cobra.Command{
Use: "artifact", Use: "artifact",
Short: "Diff Artifact", Short: "Diff Artifact",
Long: withPreviewNote(`The diff artifact command computes the diff between the remote OCI artifact and a local directory or file`), Long: `The diff artifact command computes the diff between the remote OCI artifact and a local directory or file`,
Example: `# Check if local files differ from remote Example: `# Check if local files differ from remote
flux diff artifact oci://ghcr.io/stefanprodan/manifests:podinfo:6.2.0 --path=./kustomize`, flux diff artifact oci://ghcr.io/stefanprodan/manifests:podinfo:6.2.0 --path=./kustomize`,
RunE: diffArtifactCmdRun, RunE: diffArtifactCmdRun,
@@ -42,6 +43,7 @@ type diffArtifactFlags struct {
creds string creds string
provider flags.SourceOCIProvider provider flags.SourceOCIProvider
ignorePaths []string ignorePaths []string
insecure bool
} }
var diffArtifactArgs = newDiffArtifactArgs() var diffArtifactArgs = newDiffArtifactArgs()
@@ -57,6 +59,7 @@ func init() {
diffArtifactCmd.Flags().StringVar(&diffArtifactArgs.creds, "creds", "", "credentials for OCI registry in the format <username>[:<password>] if --provider is generic") diffArtifactCmd.Flags().StringVar(&diffArtifactArgs.creds, "creds", "", "credentials for OCI registry in the format <username>[:<password>] if --provider is generic")
diffArtifactCmd.Flags().Var(&diffArtifactArgs.provider, "provider", sourceOCIRepositoryArgs.provider.Description()) diffArtifactCmd.Flags().Var(&diffArtifactArgs.provider, "provider", sourceOCIRepositoryArgs.provider.Description())
diffArtifactCmd.Flags().StringSliceVar(&diffArtifactArgs.ignorePaths, "ignore-paths", excludeOCI, "set paths to ignore in .gitignore format") diffArtifactCmd.Flags().StringSliceVar(&diffArtifactArgs.ignorePaths, "ignore-paths", excludeOCI, "set paths to ignore in .gitignore format")
diffArtifactCmd.Flags().BoolVar(&diffArtifactArgs.insecure, "insecure-registry", false, "allows the remote artifact to be pulled without TLS")
diffCmd.AddCommand(diffArtifactCmd) diffCmd.AddCommand(diffArtifactCmd)
} }
@@ -82,7 +85,22 @@ func diffArtifactCmdRun(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()
ociClient := oci.NewClient(oci.DefaultOptions()) opts := oci.DefaultOptions()
if diffArtifactArgs.insecure {
opts = append(opts, crane.Insecure)
}
if diffArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
opt, _, err := loginWithProvider(ctx, url, diffArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
opts = append(opts, opt)
}
ociClient := oci.NewClient(opts)
if diffArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && diffArtifactArgs.creds != "" { if diffArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && diffArtifactArgs.creds != "" {
logger.Actionf("logging in to registry with credentials") logger.Actionf("logging in to registry with credentials")
@@ -91,18 +109,6 @@ func diffArtifactCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
if diffArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
ociProvider, err := diffArtifactArgs.provider.ToOCIProvider()
if err != nil {
return fmt.Errorf("provider not supported: %w", err)
}
if err := ociClient.LoginWithProvider(ctx, url, ociProvider); err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
}
if err := ociClient.Diff(ctx, url, diffArtifactArgs.path, diffArtifactArgs.ignorePaths); err != nil { if err := ociClient.Diff(ctx, url, diffArtifactArgs.path, diffArtifactArgs.ignorePaths); err != nil {
return err return err
} }

View File

@@ -96,7 +96,7 @@ func TestDiffArtifact(t *testing.T) {
tt.url = fmt.Sprintf(tt.url, dockerReg) tt.url = fmt.Sprintf(tt.url, dockerReg)
_, err := executeCommand("push artifact " + tt.url + " --path=" + tt.pushFile + " --source=test --revision=test") _, err := executeCommand("push artifact " + tt.url + " --path=" + tt.pushFile + " --source=test --revision=test")
if err != nil { if err != nil {
t.Fatalf(fmt.Errorf("failed to push image: %w", err).Error()) t.Fatal(fmt.Errorf("failed to push image: %w", err).Error())
} }
cmd := cmdTestCase{ cmd := cmdTestCase{

View File

@@ -27,6 +27,7 @@ import (
"github.com/fluxcd/flux2/v2/internal/build" "github.com/fluxcd/flux2/v2/internal/build"
"github.com/fluxcd/pkg/ssa" "github.com/fluxcd/pkg/ssa"
"github.com/fluxcd/pkg/ssa/normalize"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
) )
@@ -151,7 +152,7 @@ func createObjectFromFile(objectFile string, templateValues map[string]string, t
t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err) t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err)
} }
if err := ssa.SetNativeKindsDefaults(clientObjects); err != nil { if err := normalize.UnstructuredList(clientObjects); err != nil {
t.Fatalf("Error setting native kinds defaults for '%s': %v", objectFile, err) t.Fatalf("Error setting native kinds defaults for '%s': %v", objectFile, err)
} }

View File

@@ -20,7 +20,6 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"sort" "sort"
"strings" "strings"
"time" "time"
@@ -40,13 +39,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2" helmv2 "github.com/fluxcd/helm-controller/api/v2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
notificationv1 "github.com/fluxcd/notification-controller/api/v1" notificationv1 "github.com/fluxcd/notification-controller/api/v1"
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3" notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2" swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
"github.com/fluxcd/flux2/v2/internal/utils" "github.com/fluxcd/flux2/v2/internal/utils"
"github.com/fluxcd/flux2/v2/pkg/printers" "github.com/fluxcd/flux2/v2/pkg/printers"
@@ -113,7 +112,12 @@ func eventsCmdRun(cmd *cobra.Command, args []string) error {
} }
var diffRefNs bool var diffRefNs bool
clientListOpts := []client.ListOption{client.InNamespace(*kubeconfigArgs.Namespace)} // Build the base list options. When --all-namespaces is set we must NOT constrain the
// query to a single namespace, otherwise we silently return a partial result set.
clientListOpts := []client.ListOption{}
if !eventArgs.allNamespaces {
clientListOpts = append(clientListOpts, client.InNamespace(*kubeconfigArgs.Namespace))
}
var refListOpts [][]client.ListOption var refListOpts [][]client.ListOption
if eventArgs.forSelector != "" { if eventArgs.forSelector != "" {
kind, name := getKindNameFromSelector(eventArgs.forSelector) kind, name := getKindNameFromSelector(eventArgs.forSelector)
@@ -247,7 +251,7 @@ func eventsCmdWatchRun(ctx context.Context, kubeclient client.WithWatch, listOpt
hdr = getHeaders(showNs) hdr = getHeaders(showNs)
firstIteration = false firstIteration = false
} }
return printers.TablePrinter(hdr).Print(os.Stdout, [][]string{rows}) return printers.TablePrinter(hdr).Print(rootCmd.OutOrStdout(), [][]string{rows})
} }
for _, refOpts := range refListOpts { for _, refOpts := range refListOpts {
@@ -446,11 +450,12 @@ var fluxKindMap = refMap{
field: []string{"spec", "sourceRef"}, field: []string{"spec", "sourceRef"},
}, },
sourcev1.GitRepositoryKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind)}, sourcev1.GitRepositoryKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind)},
sourcev1b2.OCIRepositoryKind: {gvk: sourcev1b2.GroupVersion.WithKind(sourcev1b2.OCIRepositoryKind)}, sourcev1.OCIRepositoryKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.OCIRepositoryKind)},
sourcev1.BucketKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)}, sourcev1.BucketKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)},
sourcev1.HelmRepositoryKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)}, sourcev1.HelmRepositoryKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)},
autov1.ImageUpdateAutomationKind: {gvk: autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)}, autov1.ImageUpdateAutomationKind: {gvk: autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)},
imagev1.ImageRepositoryKind: {gvk: imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)}, imagev1.ImageRepositoryKind: {gvk: imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)},
swapi.ArtifactGeneratorKind: {gvk: swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)},
} }
func ignoreEvent(e corev1.Event) bool { func ignoreEvent(e corev1.Event) bool {

View File

@@ -140,7 +140,7 @@ spec:
address: https://hooks.slack.com/services/mock address: https://hooks.slack.com/services/mock
type: slack type: slack
--- ---
apiVersion: image.toolkit.fluxcd.io/v1beta2 apiVersion: image.toolkit.fluxcd.io/v1
kind: ImagePolicy kind: ImagePolicy
metadata: metadata:
name: podinfo name: podinfo

View File

@@ -109,13 +109,13 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
return nil return nil
} }
func printExport(export interface{}) error { func printExport(export any) error {
data, err := yaml.Marshal(export) data, err := yaml.Marshal(export)
if err != nil { if err != nil {
return err return err
} }
rootCmd.Println("---") printlnStdout("---")
rootCmd.Println(resourceToString(data)) printlnStdout(resourceToString(data))
return nil return nil
} }

View File

@@ -0,0 +1,31 @@
/*
Copyright 2025 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 exportArtifactCmd = &cobra.Command{
Use: "artifact",
Short: "Export artifact objects",
Long: `The export artifact sub-commands export artifacts objects in YAML format.`,
}
func init() {
exportCmd.AddCommand(exportArtifactCmd)
}

View File

@@ -0,0 +1,72 @@
/*
Copyright 2025 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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
)
var exportArtifactGeneratorCmd = &cobra.Command{
Use: "generator [name]",
Short: "Export ArtifactGenerator resources in YAML format",
Long: "The export artifact generator command exports one or all ArtifactGenerator resources in YAML format.",
Example: ` # Export all ArtifactGenerator resources
flux export artifact generator --all > artifact-generators.yaml
# Export a specific generator
flux export artifact generator my-generator > my-generator.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)),
RunE: exportCommand{
object: artifactGeneratorAdapter{&swapi.ArtifactGenerator{}},
list: artifactGeneratorListAdapter{&swapi.ArtifactGeneratorList{}},
}.run,
}
func init() {
exportArtifactCmd.AddCommand(exportArtifactGeneratorCmd)
}
// Export returns an ArtifactGenerator value which has
// extraneous information stripped out.
func exportArtifactGenerator(item *swapi.ArtifactGenerator) interface{} {
gvk := swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)
export := swapi.ArtifactGenerator{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: item.Name,
Namespace: item.Namespace,
Labels: item.Labels,
Annotations: item.Annotations,
},
Spec: item.Spec,
}
return export
}
func (ex artifactGeneratorAdapter) export() interface{} {
return exportArtifactGenerator(ex.ArtifactGenerator)
}
func (ex artifactGeneratorListAdapter) exportItem(i int) interface{} {
return exportArtifactGenerator(&ex.ArtifactGeneratorList.Items[i])
}

View File

@@ -20,13 +20,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var exportImagePolicyCmd = &cobra.Command{ var exportImagePolicyCmd = &cobra.Command{
Use: "policy [name]", Use: "policy [name]",
Short: "Export ImagePolicy resources in YAML format", Short: "Export ImagePolicy resources in YAML format",
Long: withPreviewNote("The export image policy command exports one or all ImagePolicy resources in YAML format."), Long: "The export image policy command exports one or all ImagePolicy resources in YAML format.",
Example: ` # Export all ImagePolicy resources Example: ` # Export all ImagePolicy resources
flux export image policy --all > image-policies.yaml flux export image policy --all > image-policies.yaml

View File

@@ -20,13 +20,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var exportImageRepositoryCmd = &cobra.Command{ var exportImageRepositoryCmd = &cobra.Command{
Use: "repository [name]", Use: "repository [name]",
Short: "Export ImageRepository resources in YAML format", Short: "Export ImageRepository resources in YAML format",
Long: withPreviewNote("The export image repository command exports one or all ImageRepository resources in YAML format."), Long: "The export image repository command exports one or all ImageRepository resources in YAML format.",
Example: ` # Export all ImageRepository resources Example: ` # Export all ImageRepository resources
flux export image repository --all > image-repositories.yaml flux export image repository --all > image-repositories.yaml

View File

@@ -20,13 +20,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
) )
var exportImageUpdateCmd = &cobra.Command{ var exportImageUpdateCmd = &cobra.Command{
Use: "update [name]", Use: "update [name]",
Short: "Export ImageUpdateAutomation resources in YAML format", Short: "Export ImageUpdateAutomation resources in YAML format",
Long: withPreviewNote("The export image update command exports one or all ImageUpdateAutomation resources in YAML format."), Long: "The export image update command exports one or all ImageUpdateAutomation resources in YAML format.",
Example: ` # Export all ImageUpdateAutomation resources Example: ` # Export all ImageUpdateAutomation resources
flux export image update --all > updates.yaml flux export image update --all > updates.yaml

View File

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

View File

@@ -184,13 +184,13 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
if get.list.len() == 0 { if get.list.len() == 0 {
if len(args) > 0 { if len(args) > 0 {
logger.Failuref("%s object '%s' not found in %s namespace", return fmt.Errorf("%s object '%s' not found in %s namespace",
get.kind, get.kind,
args[0], args[0],
namespaceNameOrAny(getArgs.allNamespaces, *kubeconfigArgs.Namespace), namespaceNameOrAny(getArgs.allNamespaces, *kubeconfigArgs.Namespace),
) )
} else if !getAll { } else if !getAll {
logger.Failuref("no %s objects found in %s namespace", return fmt.Errorf("no %s objects found in %s namespace",
get.kind, get.kind,
namespaceNameOrAny(getArgs.allNamespaces, *kubeconfigArgs.Namespace), namespaceNameOrAny(getArgs.allNamespaces, *kubeconfigArgs.Namespace),
) )

View File

@@ -87,7 +87,7 @@ var getAllCmd = &cobra.Command{
func logError(err error) { func logError(err error) {
if !apimeta.IsNoMatchError(err) { if !apimeta.IsNoMatchError(err) {
logger.Failuref(err.Error()) logger.Failuref("%s", err.Error())
} }
} }

32
cmd/flux/get_artifact.go Normal file
View File

@@ -0,0 +1,32 @@
/*
Copyright 2025 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 getArtifactCmd = &cobra.Command{
Use: "artifacts",
Aliases: []string{"artifact"},
Short: "Get artifact object status",
Long: `The get artifact sub-commands print the status of artifact objects.`,
}
func init() {
getCmd.AddCommand(getArtifactCmd)
}

View File

@@ -0,0 +1,93 @@
/*
Copyright 2025 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"
"strconv"
"github.com/spf13/cobra"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
)
var getArtifactGeneratorCmd = &cobra.Command{
Use: "generators",
Aliases: []string{"generator"},
Short: "Get artifact generator statuses",
Long: `The get artifact generator command prints the statuses of the resources.`,
Example: ` # List all ArtifactGenerators and their status
flux get artifact generators`,
ValidArgsFunction: resourceNamesCompletionFunc(swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)),
RunE: func(cmd *cobra.Command, args []string) error {
get := getCommand{
apiType: receiverType,
list: artifactGeneratorListAdapter{&swapi.ArtifactGeneratorList{}},
funcMap: make(typeMap),
}
err := get.funcMap.registerCommand(get.apiType.kind, func(obj runtime.Object) (summarisable, error) {
o, ok := obj.(*swapi.ArtifactGenerator)
if !ok {
return nil, fmt.Errorf("impossible to cast type %#v generator", obj)
}
sink := artifactGeneratorListAdapter{&swapi.ArtifactGeneratorList{
Items: []swapi.ArtifactGenerator{
*o,
}}}
return sink, nil
})
if err != nil {
return err
}
if err := get.run(cmd, args); err != nil {
return err
}
return nil
},
}
func init() {
getArtifactCmd.AddCommand(getArtifactGeneratorCmd)
}
func (s artifactGeneratorListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind),
cases.Title(language.English).String(strconv.FormatBool(item.IsDisabled())), status, msg)
}
func (s artifactGeneratorListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Suspended", "Ready", "Message"}
if includeNamespace {
return append(namespaceHeader, headers...)
}
return headers
}
func (s artifactGeneratorListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
item := s.Items[i]
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
}

View File

@@ -19,14 +19,14 @@ package main
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var getImageAllCmd = &cobra.Command{ var getImageAllCmd = &cobra.Command{
Use: "all", Use: "all",
Short: "Get all image statuses", Short: "Get all image statuses",
Long: withPreviewNote("The get image sub-commands print the statuses of all image objects."), Long: "The get image sub-commands print the statuses of all image objects.",
Example: ` # List all image objects in a namespace Example: ` # List all image objects in a namespace
flux get images all --namespace=flux-system flux get images all --namespace=flux-system
@@ -55,7 +55,7 @@ var getImageAllCmd = &cobra.Command{
for _, c := range allImageCmd { for _, c := range allImageCmd {
if err := c.run(cmd, args); err != nil { if err := c.run(cmd, args); err != nil {
logger.Failuref(err.Error()) logger.Failuref("%s", err.Error())
} }
} }

View File

@@ -22,13 +22,13 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var getImagePolicyCmd = &cobra.Command{ var getImagePolicyCmd = &cobra.Command{
Use: "policy", Use: "policy",
Short: "Get ImagePolicy status", Short: "Get ImagePolicy status",
Long: withPreviewNote("The get image policy command prints the status of ImagePolicy objects."), Long: "The get image policy command prints the status of ImagePolicy objects.",
Example: ` # List all image policies and their status Example: ` # List all image policies and their status
flux get image policy flux get image policy
@@ -74,11 +74,16 @@ func init() {
func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string { func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i] item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions) status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), item.Status.LatestImage, status, msg) var image, tag string
if ref := item.Status.LatestRef; ref != nil {
image = ref.Name
tag = ref.Tag
}
return append(nameColumns(&item, includeNamespace, includeKind), image, tag, status, msg)
} }
func (s imagePolicyListAdapter) headers(includeNamespace bool) []string { func (s imagePolicyListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Latest image", "Ready", "Message"} headers := []string{"Name", "Image", "Tag", "Ready", "Message"}
if includeNamespace { if includeNamespace {
return append(namespaceHeader, headers...) return append(namespaceHeader, headers...)
} }

View File

@@ -26,13 +26,13 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var getImageRepositoryCmd = &cobra.Command{ var getImageRepositoryCmd = &cobra.Command{
Use: "repository", Use: "repository",
Short: "Get ImageRepository status", Short: "Get ImageRepository status",
Long: withPreviewNote("The get image repository command prints the status of ImageRepository objects."), Long: "The get image repository command prints the status of ImageRepository objects.",
Example: ` # List all image repositories and their status Example: ` # List all image repositories and their status
flux get image repository flux get image repository

View File

@@ -26,13 +26,13 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
) )
var getImageUpdateCmd = &cobra.Command{ var getImageUpdateCmd = &cobra.Command{
Use: "update", Use: "update",
Short: "Get ImageUpdateAutomation status", Short: "Get ImageUpdateAutomation status",
Long: withPreviewNote("The get image update command prints the status of ImageUpdateAutomation objects."), Long: "The get image update command prints the status of ImageUpdateAutomation objects.",
Example: ` # List all image update automation object and their status Example: ` # List all image update automation object and their status
flux get image update flux get image update

View File

@@ -21,7 +21,6 @@ import (
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var getSourceAllCmd = &cobra.Command{ var getSourceAllCmd = &cobra.Command{
@@ -42,7 +41,7 @@ var getSourceAllCmd = &cobra.Command{
var allSourceCmd = []getCommand{ var allSourceCmd = []getCommand{
{ {
apiType: ociRepositoryType, apiType: ociRepositoryType,
list: &ociRepositoryListAdapter{&sourcev1b2.OCIRepositoryList{}}, list: &ociRepositoryListAdapter{&sourcev1.OCIRepositoryList{}},
}, },
{ {
apiType: bucketType, apiType: bucketType,
@@ -65,7 +64,7 @@ var getSourceAllCmd = &cobra.Command{
for _, c := range allSourceCmd { for _, c := range allSourceCmd {
if err := c.run(cmd, args); err != nil { if err := c.run(cmd, args); err != nil {
if !apimeta.IsNoMatchError(err) { if !apimeta.IsNoMatchError(err) {
logger.Failuref(err.Error()) logger.Failuref("%s", err.Error())
} }
} }
} }

View File

@@ -25,7 +25,7 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/fluxcd/flux2/v2/internal/utils" "github.com/fluxcd/flux2/v2/internal/utils"
) )

View File

@@ -19,7 +19,10 @@ limitations under the License.
package main package main
import "testing" import (
"fmt"
"testing"
)
func Test_GetCmd(t *testing.T) { func Test_GetCmd(t *testing.T) {
tmpl := map[string]string{ tmpl := map[string]string{
@@ -59,3 +62,76 @@ func Test_GetCmd(t *testing.T) {
}) })
} }
} }
func Test_GetCmdErrors(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/get/objects.yaml", tmpl, t)
tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "specific object not found",
args: "get kustomization non-existent-resource -n " + tmpl["fluxns"],
assert: assertError(fmt.Sprintf("Kustomization object 'non-existent-resource' not found in \"%s\" namespace", tmpl["fluxns"])),
},
{
name: "no objects found in namespace",
args: "get helmrelease -n " + tmpl["fluxns"],
assert: assertError(fmt.Sprintf("no HelmRelease objects found in \"%s\" namespace", tmpl["fluxns"])),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args,
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}
func Test_GetCmdSuccess(t *testing.T) {
tmpl := map[string]string{
"fluxns": allocateNamespace("flux-system"),
}
testEnv.CreateObjectFile("./testdata/get/objects.yaml", tmpl, t)
tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "list sources git",
args: "get sources git -n " + tmpl["fluxns"],
assert: assertSuccess(),
},
{
name: "get help",
args: "get --help",
assert: assertSuccess(),
},
{
name: "get with all namespaces flag",
args: "get sources git -A",
assert: assertSuccess(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args,
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}

View File

@@ -17,10 +17,12 @@ limitations under the License.
package main package main
import ( import (
"fmt"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
// These are general-purpose adapters for attaching methods to, for // These are general-purpose adapters for attaching methods to, for
@@ -77,6 +79,34 @@ func (a imagePolicyAdapter) asClientObject() client.Object {
return a.ImagePolicy return a.ImagePolicy
} }
func (a imagePolicyAdapter) deepCopyClientObject() client.Object {
return a.ImagePolicy.DeepCopy()
}
func (a imagePolicyAdapter) isStatic() bool {
return false
}
func (a imagePolicyAdapter) lastHandledReconcileRequest() string {
return a.Status.GetLastHandledReconcileRequest()
}
func (a imagePolicyAdapter) isSuspended() bool {
return a.Spec.Suspend
}
func (a imagePolicyAdapter) setSuspended() {
a.Spec.Suspend = true
}
func (a imagePolicyAdapter) successMessage() string {
return fmt.Sprintf("selected ref %s", a.Status.LatestRef.String())
}
func (a imagePolicyAdapter) setUnsuspended() {
a.Spec.Suspend = false
}
// imagev1.ImagePolicyList // imagev1.ImagePolicyList
type imagePolicyListAdapter struct { type imagePolicyListAdapter struct {
@@ -91,6 +121,18 @@ func (a imagePolicyListAdapter) len() int {
return len(a.ImagePolicyList.Items) return len(a.ImagePolicyList.Items)
} }
func (a imagePolicyListAdapter) resumeItem(i int) resumable {
return &imagePolicyAdapter{&a.ImagePolicyList.Items[i]}
}
func (obj imagePolicyAdapter) getObservedGeneration() int64 {
return obj.ImagePolicy.Status.ObservedGeneration
}
func (a imagePolicyListAdapter) item(i int) suspendable {
return &imagePolicyAdapter{&a.ImagePolicyList.Items[i]}
}
// autov1.ImageUpdateAutomation // autov1.ImageUpdateAutomation
var imageUpdateAutomationType = apiType{ var imageUpdateAutomationType = apiType{

View File

@@ -38,7 +38,7 @@ func TestImageScanning(t *testing.T) {
"testdata/image/create_image_repository.golden", "testdata/image/create_image_repository.golden",
}, },
{ {
"create image policy podinfo-semver --image-ref=podinfo --interval=10m --select-semver=5.0.x", "create image policy podinfo-semver --image-ref=podinfo --interval=10m --reflect-digest=Always --select-semver=5.0.x",
"testdata/image/create_image_policy.golden", "testdata/image/create_image_policy.golden",
}, },
{ {
@@ -46,13 +46,25 @@ func TestImageScanning(t *testing.T) {
"testdata/image/get_image_policy_semver.golden", "testdata/image/get_image_policy_semver.golden",
}, },
{ {
`create image policy podinfo-regex --image-ref=podinfo --interval=10m --select-semver=">4.0.0" --filter-regex="5\.0\.0"`, `create image policy podinfo-regex --image-ref=podinfo --select-semver=">4.0.0" --filter-regex="5\.0\.0"`,
"testdata/image/create_image_policy.golden", "testdata/image/create_image_policy.golden",
}, },
{ {
"get image policy podinfo-regex", "get image policy podinfo-regex",
"testdata/image/get_image_policy_regex.golden", "testdata/image/get_image_policy_regex.golden",
}, },
{
"suspend image policy podinfo-semver",
"testdata/image/suspend_image_policy.golden",
},
{
"resume image policy podinfo-semver",
"testdata/image/resume_image_policy.golden",
},
{
"reconcile image policy podinfo-semver",
"testdata/image/reconcile_image_policy.golden",
},
} }
for _, tc := range cases { for _, tc := range cases {

View File

@@ -83,7 +83,7 @@ type installFlags struct {
force bool force bool
} }
var installArgs = NewInstallFlags() var installArgs = newInstallFlags()
func init() { func init() {
installCmd.Flags().BoolVar(&installArgs.export, "export", false, installCmd.Flags().BoolVar(&installArgs.export, "export", false,
@@ -93,7 +93,7 @@ func init() {
installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components, installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values") "list of components, accepts comma-separated values")
installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil, installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'") "list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller,source-watcher'")
installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory") installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry, installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published") "container registry where the toolkit images are published")
@@ -115,9 +115,14 @@ func init() {
rootCmd.AddCommand(installCmd) rootCmd.AddCommand(installCmd)
} }
func NewInstallFlags() installFlags { func newInstallFlags() installFlags {
return installFlags{ return installFlags{
logLevel: flags.LogLevel(rootArgs.defaults.LogLevel), logLevel: flags.LogLevel(rootArgs.defaults.LogLevel),
defaultComponents: rootArgs.defaults.Components,
registry: rootArgs.defaults.Registry,
watchAllNamespaces: rootArgs.defaults.WatchAllNamespaces,
networkPolicy: rootArgs.defaults.NetworkPolicy,
clusterDomain: rootArgs.defaults.ClusterDomain,
} }
} }
@@ -195,10 +200,13 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
} }
if installArgs.export { if installArgs.export {
fmt.Print(manifest.Content) _, err = rootCmd.OutOrStdout().Write([]byte(manifest.Content))
return nil return err
} else if rootArgs.verbose { } else if rootArgs.verbose {
fmt.Print(manifest.Content) _, err = rootCmd.OutOrStdout().Write([]byte(manifest.Content))
if err != nil {
return err
}
} }
logger.Successf("manifests build completed") logger.Successf("manifests build completed")
@@ -238,7 +246,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }
fmt.Fprintln(os.Stderr, applyOutput) rootCmd.Println(applyOutput)
if opts.ImagePullSecret != "" && opts.RegistryCredential != "" { if opts.ImagePullSecret != "" && opts.RegistryCredential != "" {
logger.Actionf("generating image pull secret %s", opts.ImagePullSecret) logger.Actionf("generating image pull secret %s", opts.ImagePullSecret)
@@ -250,7 +258,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
Username: credentials[0], Username: credentials[0],
Password: credentials[1], Password: credentials[1],
} }
imagePullSecret, err := sourcesecret.Generate(secretOpts) imagePullSecret, err := sourcesecret.GenerateOCI(secretOpts)
if err != nil { if err != nil {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2022 The Flux authors Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@@ -16,7 +16,17 @@ limitations under the License.
package main package main
import "testing" import (
"strings"
"testing"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
ssautil "github.com/fluxcd/pkg/ssa/utils"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/install"
)
func TestInstall(t *testing.T) { func TestInstall(t *testing.T) {
// The pointer to kubeconfigArgs.Namespace is shared across // The pointer to kubeconfigArgs.Namespace is shared across
@@ -59,3 +69,43 @@ func TestInstall(t *testing.T) {
}) })
} }
} }
func TestInstall_ComponentsExtra(t *testing.T) {
g := NewWithT(t)
command := "install --export --components-extra=" +
strings.Join(install.MakeDefaultOptions().ComponentsExtra, ",")
output, err := executeCommand(command)
g.Expect(err).NotTo(HaveOccurred())
manifests, err := ssautil.ReadObjects(strings.NewReader(output))
g.Expect(err).NotTo(HaveOccurred())
foundImageAutomation := false
foundImageReflector := false
foundSourceWatcher := false
foundExternalArtifact := false
for _, obj := range manifests {
if obj.GetKind() == "Deployment" && obj.GetName() == "image-automation-controller" {
foundImageAutomation = true
}
if obj.GetKind() == "Deployment" && obj.GetName() == "image-reflector-controller" {
foundImageReflector = true
}
if obj.GetKind() == "Deployment" && obj.GetName() == "source-watcher" {
foundSourceWatcher = true
}
if obj.GetKind() == "Deployment" &&
(obj.GetName() == "kustomize-controller" || obj.GetName() == "helm-controller") {
containers, _, _ := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "containers")
g.Expect(containers).ToNot(BeEmpty())
args, _, _ := unstructured.NestedSlice(containers[0].(map[string]any), "args")
g.Expect(args).To(ContainElement("--feature-gates=ExternalArtifact=true"))
foundExternalArtifact = true
}
}
g.Expect(foundImageAutomation).To(BeTrue(), "image-automation-controller deployment not found")
g.Expect(foundImageReflector).To(BeTrue(), "image-reflector-controller deployment not found")
g.Expect(foundSourceWatcher).To(BeTrue(), "source-watcher deployment not found")
g.Expect(foundExternalArtifact).To(BeTrue(), "ExternalArtifact feature gate not found")
}

View File

@@ -20,10 +20,11 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/spf13/cobra" "github.com/spf13/cobra"
oci "github.com/fluxcd/pkg/oci/client" "github.com/fluxcd/pkg/oci"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/fluxcd/flux2/v2/internal/flags" "github.com/fluxcd/flux2/v2/internal/flags"
"github.com/fluxcd/flux2/v2/pkg/printers" "github.com/fluxcd/flux2/v2/pkg/printers"
@@ -34,6 +35,7 @@ type listArtifactFlags struct {
regexFilter string regexFilter string
creds string creds string
provider flags.SourceOCIProvider provider flags.SourceOCIProvider
insecure bool
} }
var listArtifactArgs = newListArtifactFlags() var listArtifactArgs = newListArtifactFlags()
@@ -47,10 +49,10 @@ func newListArtifactFlags() listArtifactFlags {
var listArtifactsCmd = &cobra.Command{ var listArtifactsCmd = &cobra.Command{
Use: "artifacts", Use: "artifacts",
Short: "list artifacts", Short: "list artifacts",
Long: withPreviewNote(`The list command fetches the tags and their metadata from a remote OCI repository. Long: `The list command fetches the tags and their metadata from a remote OCI repository.
The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`), The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`,
Example: ` # List the artifacts stored in an OCI repository Example: ` # List the artifacts stored in an OCI repository
flux list artifact oci://ghcr.io/org/config/app flux list artifacts oci://ghcr.io/org/config/app
`, `,
RunE: listArtifactsCmdRun, RunE: listArtifactsCmdRun,
} }
@@ -60,6 +62,7 @@ func init() {
listArtifactsCmd.Flags().StringVar(&listArtifactArgs.regexFilter, "filter-regex", "", "filter tags returned from the oci repository using regex") listArtifactsCmd.Flags().StringVar(&listArtifactArgs.regexFilter, "filter-regex", "", "filter tags returned from the oci repository using regex")
listArtifactsCmd.Flags().StringVar(&listArtifactArgs.creds, "creds", "", "credentials for OCI registry in the format <username>[:<password>] if --provider is generic") listArtifactsCmd.Flags().StringVar(&listArtifactArgs.creds, "creds", "", "credentials for OCI registry in the format <username>[:<password>] if --provider is generic")
listArtifactsCmd.Flags().Var(&listArtifactArgs.provider, "provider", listArtifactArgs.provider.Description()) listArtifactsCmd.Flags().Var(&listArtifactArgs.provider, "provider", listArtifactArgs.provider.Description())
listArtifactsCmd.Flags().BoolVar(&listArtifactArgs.insecure, "insecure-registry", false, "allows the remote artifacts list to be fetched without TLS")
listCmd.AddCommand(listArtifactsCmd) listCmd.AddCommand(listArtifactsCmd)
} }
@@ -78,7 +81,22 @@ func listArtifactsCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
ociClient := oci.NewClient(oci.DefaultOptions()) ociOpts := oci.DefaultOptions()
if listArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
ociOpt, _, err := loginWithProvider(ctx, url, listArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
ociOpts = append(ociOpts, ociOpt)
}
if listArtifactArgs.insecure {
ociOpts = append(ociOpts, crane.Insecure)
}
ociClient := oci.NewClient(ociOpts)
if listArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && listArtifactArgs.creds != "" { if listArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && listArtifactArgs.creds != "" {
logger.Actionf("logging in to registry with credentials") logger.Actionf("logging in to registry with credentials")
@@ -87,18 +105,6 @@ func listArtifactsCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
if listArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
ociProvider, err := listArtifactArgs.provider.ToOCIProvider()
if err != nil {
return fmt.Errorf("provider not supported: %w", err)
}
if err := ociClient.LoginWithProvider(ctx, url, ociProvider); err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
}
opts := oci.ListOptions{ opts := oci.ListOptions{
RegexFilter: listArtifactArgs.regexFilter, RegexFilter: listArtifactArgs.regexFilter,
SemverFilter: listArtifactArgs.semverFilter, SemverFilter: listArtifactArgs.semverFilter,

View File

@@ -247,3 +247,8 @@ While we try our best to not introduce breaking changes, they may occur when
we adapt to new features and/or find better ways to facilitate what it does.` we adapt to new features and/or find better ways to facilitate what it does.`
return fmt.Sprintf("%s\n\n%s", strings.TrimSpace(desc), previewNote) return fmt.Sprintf("%s\n\n%s", strings.TrimSpace(desc), previewNote)
} }
// printlnStdout prints the given text to stdout with a newline.
func printlnStdout(txt string) {
_, _ = rootCmd.OutOrStdout().Write([]byte(txt + "\n"))
}

View File

@@ -447,6 +447,7 @@ func resetCmdArgs() {
imagePolicyArgs = imagePolicyFlags{} imagePolicyArgs = imagePolicyFlags{}
imageRepoArgs = imageRepoFlags{} imageRepoArgs = imageRepoFlags{}
imageUpdateArgs = imageUpdateFlags{} imageUpdateArgs = imageUpdateFlags{}
installArgs = newInstallFlags()
kustomizationArgs = NewKustomizationFlags() kustomizationArgs = NewKustomizationFlags()
receiverArgs = receiverFlags{} receiverArgs = receiverFlags{}
resumeArgs = ResumeFlags{} resumeArgs = ResumeFlags{}

691
cmd/flux/migrate.go Normal file
View File

@@ -0,0 +1,691 @@
/*
Copyright 2025 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"
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/fluxcd/pkg/ssa"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
imageautov1 "github.com/fluxcd/image-automation-controller/api/v1"
imageautov1b2 "github.com/fluxcd/image-automation-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
imagev1b2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
swv1b1 "github.com/fluxcd/source-watcher/api/v2/v1beta1"
"github.com/fluxcd/flux2/v2/internal/utils"
)
// APIVersions holds the mapping of GroupKinds to their respective
// latest API versions for a specific Flux version.
type APIVersions struct {
FluxVersion string
LatestVersions map[schema.GroupKind]string
}
// TODO: Update this mapping when new Flux minor versions are released!
// latestAPIVersions contains the latest API versions for each GroupKind
// for each supported Flux version. We maintain the latest two minor versions.
var latestAPIVersions = []APIVersions{
{
FluxVersion: "2.7",
LatestVersions: map[schema.GroupKind]string{
// source-controller
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.BucketKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.GitRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.OCIRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmChartKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.ExternalArtifactKind}: sourcev1.GroupVersion.Version,
// kustomize-controller
{Group: kustomizev1.GroupVersion.Group, Kind: kustomizev1.KustomizationKind}: kustomizev1.GroupVersion.Version,
// helm-controller
{Group: helmv2.GroupVersion.Group, Kind: helmv2.HelmReleaseKind}: helmv2.GroupVersion.Version,
// notification-controller
{Group: notificationv1.GroupVersion.Group, Kind: notificationv1.ReceiverKind}: notificationv1.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.AlertKind}: notificationv1b3.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.ProviderKind}: notificationv1b3.GroupVersion.Version,
// image-reflector-controller
{Group: imagev1.GroupVersion.Group, Kind: imagev1.ImageRepositoryKind}: imagev1.GroupVersion.Version,
{Group: imagev1.GroupVersion.Group, Kind: imagev1.ImagePolicyKind}: imagev1.GroupVersion.Version,
// image-automation-controller
{Group: imageautov1.GroupVersion.Group, Kind: imageautov1.ImageUpdateAutomationKind}: imageautov1.GroupVersion.Version,
// source-watcher
{Group: swv1b1.GroupVersion.Group, Kind: swv1b1.ArtifactGeneratorKind}: swv1b1.GroupVersion.Version,
},
},
{
FluxVersion: "2.6",
LatestVersions: map[schema.GroupKind]string{
// source-controller
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.BucketKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.GitRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.OCIRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmChartKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.ExternalArtifactKind}: sourcev1.GroupVersion.Version,
// kustomize-controller
{Group: kustomizev1.GroupVersion.Group, Kind: kustomizev1.KustomizationKind}: kustomizev1.GroupVersion.Version,
// helm-controller
{Group: helmv2.GroupVersion.Group, Kind: helmv2.HelmReleaseKind}: helmv2.GroupVersion.Version,
// notification-controller
{Group: notificationv1.GroupVersion.Group, Kind: notificationv1.ReceiverKind}: notificationv1.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.AlertKind}: notificationv1b3.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.ProviderKind}: notificationv1b3.GroupVersion.Version,
// image-reflector-controller
{Group: imagev1b2.GroupVersion.Group, Kind: imagev1b2.ImageRepositoryKind}: imagev1b2.GroupVersion.Version,
{Group: imagev1b2.GroupVersion.Group, Kind: imagev1b2.ImagePolicyKind}: imagev1b2.GroupVersion.Version,
// image-automation-controller
{Group: imageautov1b2.GroupVersion.Group, Kind: imageautov1b2.ImageUpdateAutomationKind}: imageautov1b2.GroupVersion.Version,
},
},
}
var migrateCmd = &cobra.Command{
Use: "migrate",
Args: cobra.NoArgs,
Short: "Migrate the Flux custom resources to their latest API version",
Long: `The migrate command must be run before a Flux minor version upgrade.
The command has two modes of operation:
- Cluster mode (default): migrates all the Flux custom resources stored in Kubernetes etcd to their latest API version.
- File system mode (-f): migrates the Flux custom resources defined in the manifests located in the specified path.
`,
Example: ` # Migrate all the Flux custom resources in the cluster.
# This uses the current kubeconfig context and requires cluster-admin permissions.
flux migrate
# Migrate all the Flux custom resources in a Git repository
# checked out in the current working directory.
flux migrate -f .
# Migrate all Flux custom resources defined in YAML and Helm YAML template files.
flux migrate -f . --extensions=.yml,.yaml,.tpl
# Migrate the Flux custom resources to the latest API versions of Flux 2.6.
flux migrate -f . --version=2.6
# Migrate the Flux custom resources defined in a multi-document YAML manifest file.
flux migrate -f path/to/manifest.yaml
# Simulate the migration without making any changes.
flux migrate -f . --dry-run
# Run the migration skipping confirmation prompts.
flux migrate -f . --yes
`,
RunE: runMigrateCmd,
}
var migrateFlags struct {
yes bool
dryRun bool
path string
version string
extensions []string
}
func init() {
rootCmd.AddCommand(migrateCmd)
migrateCmd.Flags().StringVarP(&migrateFlags.path, "path", "f", "",
"the path to the directory containing the manifests to migrate")
migrateCmd.Flags().StringSliceVarP(&migrateFlags.extensions, "extensions", "e", []string{".yaml", ".yml"},
"the file extensions to consider when migrating manifests, only applicable with --path")
migrateCmd.Flags().StringVarP(&migrateFlags.version, "version", "v", "",
"the target Flux minor version to migrate manifests to, only applicable with --path (defaults to the version of the CLI)")
migrateCmd.Flags().BoolVarP(&migrateFlags.yes, "yes", "y", false,
"skip confirmation prompts when migrating manifests, only applicable with --path")
migrateCmd.Flags().BoolVar(&migrateFlags.dryRun, "dry-run", false,
"simulate the migration of manifests without making any changes, only applicable with --path")
}
func runMigrateCmd(*cobra.Command, []string) error {
if migrateFlags.path == "" {
return migrateCluster()
}
return migrateFileSystem()
}
func migrateCluster() error {
logger.Actionf("starting migration of custom resources")
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
if err != nil {
return fmt.Errorf("the Kubernetes client initialization failed: %w", err)
}
kubeClient, err := client.New(cfg, client.Options{Scheme: utils.NewScheme()})
if err != nil {
return err
}
migrator := NewClusterMigrator(kubeClient, client.MatchingLabels{
"app.kubernetes.io/part-of": "flux",
})
if err := migrator.Run(ctx); err != nil {
return err
}
logger.Successf("custom resources migrated successfully")
return nil
}
func migrateFileSystem() error {
pathRoot, err := os.OpenRoot(".")
if err != nil {
return fmt.Errorf("failed to open filesystem at the current working directory: %w", err)
}
defer pathRoot.Close()
fileSystem := &osFS{pathRoot.FS()}
yes := migrateFlags.yes
dryRun := migrateFlags.dryRun
path := migrateFlags.path
extensions := migrateFlags.extensions
var latestVersions map[schema.GroupKind]string
// Determine latest API versions based on the Flux version.
if migrateFlags.version == "" {
latestVersions = latestAPIVersions[0].LatestVersions
} else {
supportedVersions := make([]string, 0, len(latestAPIVersions))
for _, v := range latestAPIVersions {
if v.FluxVersion == migrateFlags.version {
latestVersions = v.LatestVersions
break
}
supportedVersions = append(supportedVersions, v.FluxVersion)
}
if latestVersions == nil {
return fmt.Errorf("version %s is not supported, supported versions are: %s",
migrateFlags.version, strings.Join(supportedVersions, ", "))
}
}
return NewFileSystemMigrator(fileSystem, yes, dryRun, path, extensions, latestVersions).Run()
}
// ClusterMigrator migrates all the CRs in the cluster for the CRDs matching the label selector.
type ClusterMigrator struct {
labelSelector client.MatchingLabels
kubeClient client.Client
}
// NewClusterMigrator creates a new ClusterMigrator instance with the specified label selector.
func NewClusterMigrator(kubeClient client.Client, labelSelector client.MatchingLabels) *ClusterMigrator {
return &ClusterMigrator{
labelSelector: labelSelector,
kubeClient: kubeClient,
}
}
func (c *ClusterMigrator) Run(ctx context.Context) error {
crdList := &apiextensionsv1.CustomResourceDefinitionList{}
if err := c.kubeClient.List(ctx, crdList, c.labelSelector); err != nil {
return fmt.Errorf("failed to list CRDs: %w", err)
}
for _, crd := range crdList.Items {
if err := c.migrateCRD(ctx, crd.Name); err != nil {
return err
}
}
return nil
}
func (c *ClusterMigrator) migrateCRD(ctx context.Context, name string) error {
crd := &apiextensionsv1.CustomResourceDefinition{}
if err := c.kubeClient.Get(ctx, client.ObjectKey{Name: name}, crd); err != nil {
return fmt.Errorf("failed to get CRD %s: %w", name, err)
}
// get the latest storage version for the CRD
storageVersion := c.getStorageVersion(crd)
if storageVersion == "" {
return fmt.Errorf("no storage version found for CRD %s", name)
}
// migrate all the resources for the CRD
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
return c.migrateCR(ctx, crd, storageVersion)
})
if err != nil {
return fmt.Errorf("failed to migrate resources for CRD %s: %w", name, err)
}
// set the CRD status to contain only the latest storage version
if len(crd.Status.StoredVersions) > 1 || crd.Status.StoredVersions[0] != storageVersion {
crd.Status.StoredVersions = []string{storageVersion}
if err := c.kubeClient.Status().Update(ctx, crd); err != nil {
return fmt.Errorf("failed to update CRD %s status: %w", crd.Name, err)
}
logger.Successf("%s migrated to storage version %s", crd.Name, storageVersion)
}
return nil
}
// migrateCR migrates all CRs for the given CRD to the specified version by patching them.
func (c *ClusterMigrator) migrateCR(ctx context.Context, crd *apiextensionsv1.CustomResourceDefinition, version string) error {
list := &unstructured.UnstructuredList{}
apiVersion := crd.Spec.Group + "/" + version
listKind := crd.Spec.Names.ListKind
list.SetAPIVersion(apiVersion)
list.SetKind(listKind)
err := c.kubeClient.List(ctx, list, client.InNamespace(""))
if err != nil {
return fmt.Errorf("failed to list resources for CRD %s: %w", crd.Name, err)
}
if len(list.Items) == 0 {
return nil
}
for _, item := range list.Items {
patches, err := ssa.PatchMigrateToVersion(&item, apiVersion)
if err != nil {
return fmt.Errorf("failed to create migration patch for %s/%s/%s: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
if len(patches) == 0 {
// patch the resource with an empty patch to update the version
if err := c.kubeClient.Patch(
ctx,
&item,
client.RawPatch(client.Merge.Type(), []byte("{}")),
); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf(" %s/%s/%s failed to migrate: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
} else {
// patch the resource to migrate the managed fields to the latest apiVersion
rawPatch, err := json.Marshal(patches)
if err != nil {
return fmt.Errorf("failed to marshal migration patch for %s/%s/%s: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
if err := c.kubeClient.Patch(
ctx,
&item,
client.RawPatch(types.JSONPatchType, rawPatch),
); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf(" %s/%s/%s failed to migrate managed fields: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
}
logger.Successf("%s/%s/%s migrated to version %s",
item.GetKind(), item.GetNamespace(), item.GetName(), version)
}
return nil
}
// getStorageVersion retrieves the storage version of a CustomResourceDefinition.
func (c *ClusterMigrator) getStorageVersion(crd *apiextensionsv1.CustomResourceDefinition) string {
var version string
for _, v := range crd.Spec.Versions {
if v.Storage {
version = v.Name
break
}
}
return version
}
// WritableFS extends fs.FS with a WriteFile method.
type WritableFS interface {
fs.FS
WriteFile(name string, data []byte, perm os.FileMode) error
}
// osFS is a WritableFS implementation that uses the file system of the OS.
type osFS struct {
fs.FS
}
func (o *osFS) WriteFile(name string, data []byte, perm os.FileMode) error {
return os.WriteFile(name, data, perm)
}
// FileSystemMigrator migrates all the CRs found in the manifests located in the specified path.
type FileSystemMigrator struct {
fileSystem WritableFS
yes bool
dryRun bool
path string
extensions []string
latestVersions map[schema.GroupKind]string
}
// FileAPIUpgrades represents the API upgrades detected in a specific manifest file.
type FileAPIUpgrades struct {
File string
Upgrades []APIUpgrade
}
// APIUpgrade represents an upgrade of a specific API version in a manifest file.
type APIUpgrade struct {
Line int
Kind string
OldVersion string
NewVersion string
}
// NewFileSystemMigrator creates a new FileSystemMigrator instance with the specified flags.
func NewFileSystemMigrator(fileSystem WritableFS, yes, dryRun bool, path string,
extensions []string, latestVersions map[schema.GroupKind]string) *FileSystemMigrator {
return &FileSystemMigrator{
fileSystem: fileSystem,
yes: yes,
dryRun: dryRun,
path: filepath.Clean(path), // convert dir/ to dir to avoid error when walking
extensions: extensions,
latestVersions: latestVersions,
}
}
func (f *FileSystemMigrator) Run() error {
logger.Actionf("starting migration of custom resources")
// List and filter files.
files, err := f.listFiles()
if err != nil {
return err
}
// Detect upgrades.
upgrades, err := f.detectUpgrades(files)
if err != nil {
return err
}
if len(upgrades) == 0 {
logger.Successf("no custom resources found that require migration")
return nil
}
if f.dryRun {
logger.Successf("dry-run mode enabled, no changes will be made")
return nil
}
// Confirm upgrades.
if !f.yes {
prompt := promptui.Prompt{
Label: "Are you sure you want to proceed with the above upgrades", // Already prints "? [y/N]"
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return err
}
}
// Migrate files.
for _, fileUpgrades := range upgrades {
if err := f.migrateFile(&fileUpgrades); err != nil {
return err
}
logger.Successf("file %s migrated successfully", fileUpgrades.File)
}
logger.Successf("custom resources migrated successfully")
return nil
}
func (f *FileSystemMigrator) listFiles() ([]string, error) {
fileInfo, err := fs.Stat(f.fileSystem, f.path)
if err != nil {
return nil, fmt.Errorf("failed to stat path %s: %w", f.path, err)
}
if fileInfo.IsDir() {
return f.listDirectoryFiles()
}
if err := f.validateSingleFile(); err != nil {
return nil, err
}
return []string{f.path}, nil
}
func (f *FileSystemMigrator) listDirectoryFiles() ([]string, error) {
var files []string
err := fs.WalkDir(f.fileSystem, f.path, func(path string, dirEntry fs.DirEntry, err error) error {
if err != nil {
return err
}
if !f.matchesExtensions(path) {
return nil
}
fileInfo, err := dirEntry.Info()
if err != nil {
return err
}
if fileInfo.Mode().IsRegular() {
files = append(files, path)
} else if !fileInfo.IsDir() {
logger.Warningf("skipping irregular file %s", path)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to walk directory %s: %w", f.path, err)
}
return files, nil
}
func (f *FileSystemMigrator) validateSingleFile() error {
if !f.matchesExtensions(f.path) {
return fmt.Errorf("file %s does not match the specified extensions: %v",
f.path, strings.Join(f.extensions, ", "))
}
// Check if it's irregular by walking the parent directory.
var irregular bool
err := fs.WalkDir(f.fileSystem, filepath.Dir(f.path), func(path string, dirEntry fs.DirEntry, err error) error {
if err != nil {
return err
}
if path != f.path {
return nil
}
fileInfo, err := dirEntry.Info()
if err != nil {
return err
}
if !fileInfo.Mode().IsRegular() {
irregular = true
}
return nil
})
if err != nil {
return fmt.Errorf("failed to validate file %s: %w", f.path, err)
}
if irregular {
return fmt.Errorf("file %s is irregular", f.path)
}
return nil
}
func (f *FileSystemMigrator) matchesExtensions(file string) bool {
for _, ext := range f.extensions {
if strings.HasSuffix(file, ext) {
return true
}
}
return false
}
func (f *FileSystemMigrator) detectUpgrades(files []string) ([]FileAPIUpgrades, error) {
var upgrades []FileAPIUpgrades
for _, file := range files {
fileUpgrades, err := f.detectFileUpgrades(file)
if err != nil {
return nil, err
}
if len(fileUpgrades) == 0 {
continue
}
fu := FileAPIUpgrades{
File: file,
Upgrades: fileUpgrades,
}
upgrades = append(upgrades, fu)
f.printDetectedUpgrades(&fu)
}
return upgrades, nil
}
func (f *FileSystemMigrator) detectFileUpgrades(file string) ([]APIUpgrade, error) {
b, err := fs.ReadFile(f.fileSystem, file)
if err != nil {
return nil, fmt.Errorf("failed to read file %s: %w", file, err)
}
lines := strings.Split(string(b), "\n")
var fileUpgrades []APIUpgrade
for line, apiVersionLine := range lines {
// Parse apiVersion.
const apiVersionPrefix = "apiVersion: "
idx := strings.Index(apiVersionLine, apiVersionPrefix)
if idx == -1 {
continue
}
apiVersionValuePrefix := strings.TrimSpace(apiVersionLine[idx+len(apiVersionPrefix):])
apiVersion := strings.Split(apiVersionValuePrefix, " ")[0]
gv, err := schema.ParseGroupVersion(apiVersion)
if err != nil {
logger.Warningf("%s:%d: %v", file, line+1, err)
continue
}
// Parse kind.
if line+1 >= len(lines) {
continue
}
kindLine := lines[line+1]
const kindPrefix = "kind: "
idx = strings.Index(kindLine, kindPrefix)
if idx == -1 {
continue
}
kindValuePrefix := strings.TrimSpace(kindLine[idx+len(kindPrefix):])
kind := strings.Split(kindValuePrefix, " ")[0]
// Build GroupKind.
gk := schema.GroupKind{
Group: gv.Group,
Kind: kind,
}
// Check if there's a newer version for the GroupKind.
latestVersion, ok := f.latestVersions[gk]
if !ok || latestVersion == gv.Version {
continue
}
// Record the upgrade.
fileUpgrades = append(fileUpgrades, APIUpgrade{
Line: line,
Kind: kind,
OldVersion: gv.Version,
NewVersion: latestVersion,
})
}
return fileUpgrades, nil
}
func (f *FileSystemMigrator) printDetectedUpgrades(fileUpgrades *FileAPIUpgrades) {
for _, upgrade := range fileUpgrades.Upgrades {
logger.Generatef("%s:%d: %s %s -> %s",
fileUpgrades.File,
upgrade.Line+1,
upgrade.Kind,
upgrade.OldVersion,
upgrade.NewVersion)
}
}
func (f *FileSystemMigrator) migrateFile(fileUpgrades *FileAPIUpgrades) error {
// Read file and map lines.
b, err := fs.ReadFile(f.fileSystem, fileUpgrades.File)
if err != nil {
return fmt.Errorf("failed to read file %s: %w", fileUpgrades.File, err)
}
lines := strings.Split(string(b), "\n")
// Apply upgrades to lines.
for _, upgrade := range fileUpgrades.Upgrades {
line := lines[upgrade.Line]
line = strings.Replace(line, upgrade.OldVersion, upgrade.NewVersion, 1)
lines[upgrade.Line] = line
}
// Read file info to preserve permissions.
fileInfo, err := fs.Stat(f.fileSystem, fileUpgrades.File)
if err != nil {
return fmt.Errorf("failed to stat file %s: %w", fileUpgrades.File, err)
}
// Write file with preserved permissions.
b = []byte(strings.Join(lines, "\n"))
if err := f.fileSystem.WriteFile(fileUpgrades.File, b, fileInfo.Mode()); err != nil {
return fmt.Errorf("failed to write file %s: %w", fileUpgrades.File, err)
}
return nil
}

161
cmd/flux/migrate_test.go Normal file
View File

@@ -0,0 +1,161 @@
/*
Copyright 2025 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 (
"bytes"
"io/fs"
"os"
"testing"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type writeToMemoryFS struct {
fs.FS
writtenFiles map[string][]byte
}
func (m *writeToMemoryFS) WriteFile(name string, data []byte, perm os.FileMode) error {
m.writtenFiles[name] = data
return nil
}
type writtenFile struct {
file string
goldenFile string
}
func TestFileSystemMigrator(t *testing.T) {
for _, tt := range []struct {
name string
path string
outputGolden string
writtenFiles []writtenFile
err string
}{
{
name: "errors out for single file that is a symlink",
path: "testdata/migrate/file-system/single-file-link.yaml",
err: "file testdata/migrate/file-system/single-file-link.yaml is irregular",
},
{
name: "errors out for single file with wrong extension",
path: "testdata/migrate/file-system/single-file-wrong-ext.json",
err: "file testdata/migrate/file-system/single-file-wrong-ext.json does not match the specified extensions: .yaml, .yml",
},
{
name: "migrate single file",
path: "testdata/migrate/file-system/single-file.yaml",
outputGolden: "testdata/migrate/file-system/single-file.yaml.output.golden",
writtenFiles: []writtenFile{
{
file: "testdata/migrate/file-system/single-file.yaml",
goldenFile: "testdata/migrate/file-system/single-file.yaml.golden",
},
},
},
{
name: "migrate files in directory",
path: "testdata/migrate/file-system/dir",
outputGolden: "testdata/migrate/file-system/dir.output.golden",
writtenFiles: []writtenFile{
{
file: "testdata/migrate/file-system/dir/some-dir/another-file.yaml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-dir/another-file.yaml",
},
{
file: "testdata/migrate/file-system/dir/some-dir/another-file.yml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-dir/another-file.yml",
},
{
file: "testdata/migrate/file-system/dir/some-file.yaml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-file.yaml",
},
{
file: "testdata/migrate/file-system/dir/some-file.yml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-file.yml",
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
// Store logger, replace with test logger, and restore at the end of the test.
var testLogger bytes.Buffer
oldLogger := logger
logger = stderrLogger{&testLogger}
t.Cleanup(func() { logger = oldLogger })
// Open current working directory as root and build write-to-memory filesystem.
pathRoot, err := os.OpenRoot(".")
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() { pathRoot.Close() })
fileSystem := &writeToMemoryFS{
FS: pathRoot.FS(),
writtenFiles: make(map[string][]byte),
}
// Prepare other inputs.
const yes = true
const dryRun = false
extensions := []string{".yaml", ".yml"}
latestVersions := map[schema.GroupKind]string{
{Group: "image.toolkit.fluxcd.io", Kind: "ImageRepository"}: "v1",
{Group: "image.toolkit.fluxcd.io", Kind: "ImagePolicy"}: "v1",
{Group: "image.toolkit.fluxcd.io", Kind: "ImageUpdateAutomation"}: "v1",
}
// Run migration.
err = NewFileSystemMigrator(fileSystem, yes, dryRun, tt.path, extensions, latestVersions).Run()
if tt.err != "" {
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(Equal(tt.err))
return
}
g.Expect(err).ToNot(HaveOccurred())
// Assert logger output.
b, err := os.ReadFile(tt.outputGolden)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(string(b)).To(Equal(testLogger.String()),
"logger output does not match golden file %s", tt.outputGolden)
// Assert which files were written.
writtenFiles := make([]string, 0, len(fileSystem.writtenFiles))
for name := range fileSystem.writtenFiles {
writtenFiles = append(writtenFiles, name)
}
expectedWrittenFiles := make([]string, 0, len(tt.writtenFiles))
for _, wf := range tt.writtenFiles {
expectedWrittenFiles = append(expectedWrittenFiles, wf.file)
}
g.Expect(writtenFiles).To(ConsistOf(expectedWrittenFiles))
// Assert contents of written files.
for _, wf := range tt.writtenFiles {
b, err := os.ReadFile(wf.goldenFile)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(string(fileSystem.writtenFiles[wf.file])).To(Equal(string(b)),
"file %s does not match golden file %s", wf.file, wf.goldenFile)
}
})
}
}

42
cmd/flux/oci.go Normal file
View File

@@ -0,0 +1,42 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/fluxcd/pkg/auth"
"github.com/fluxcd/pkg/auth/azure"
authutils "github.com/fluxcd/pkg/auth/utils"
)
// loginWithProvider gets a crane authentication option for the given provider and URL.
func loginWithProvider(ctx context.Context, url, provider string) (crane.Option, authn.Authenticator, error) {
var opts []auth.Option
if provider == azure.ProviderName {
opts = append(opts, auth.WithAllowShellOut())
}
authenticator, err := authutils.GetArtifactRegistryCredentials(ctx, provider, url, opts...)
if err != nil {
return nil, nil, fmt.Errorf("could not login to provider %s with url %s: %w", provider, url, err)
}
return crane.WithAuth(authenticator), authenticator, nil
}

View File

@@ -21,19 +21,20 @@ import (
"fmt" "fmt"
"os" "os"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/google/go-containerregistry/pkg/crane"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fluxcd/flux2/v2/internal/flags" "github.com/fluxcd/pkg/oci"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
oci "github.com/fluxcd/pkg/oci/client" "github.com/fluxcd/flux2/v2/internal/flags"
) )
var pullArtifactCmd = &cobra.Command{ var pullArtifactCmd = &cobra.Command{
Use: "artifact", Use: "artifact",
Short: "Pull artifact", Short: "Pull artifact",
Long: withPreviewNote(`The pull artifact command downloads and extracts the OCI artifact content to the given path. Long: `The pull artifact command downloads and extracts the OCI artifact content to the given path.
The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`), The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`,
Example: ` # Pull an OCI artifact created by flux from GHCR Example: ` # Pull an OCI artifact created by flux from GHCR
flux pull artifact oci://ghcr.io/org/manifests/app:v0.0.1 --output ./path/to/local/manifests flux pull artifact oci://ghcr.io/org/manifests/app:v0.0.1 --output ./path/to/local/manifests
`, `,
@@ -43,6 +44,7 @@ The command can read the credentials from '~/.docker/config.json' but they can a
type pullArtifactFlags struct { type pullArtifactFlags struct {
output string output string
creds string creds string
insecure bool
provider flags.SourceOCIProvider provider flags.SourceOCIProvider
} }
@@ -58,6 +60,7 @@ func init() {
pullArtifactCmd.Flags().StringVarP(&pullArtifactArgs.output, "output", "o", "", "path where the artifact content should be extracted.") pullArtifactCmd.Flags().StringVarP(&pullArtifactArgs.output, "output", "o", "", "path where the artifact content should be extracted.")
pullArtifactCmd.Flags().StringVar(&pullArtifactArgs.creds, "creds", "", "credentials for OCI registry in the format <username>[:<password>] if --provider is generic") pullArtifactCmd.Flags().StringVar(&pullArtifactArgs.creds, "creds", "", "credentials for OCI registry in the format <username>[:<password>] if --provider is generic")
pullArtifactCmd.Flags().Var(&pullArtifactArgs.provider, "provider", sourceOCIRepositoryArgs.provider.Description()) pullArtifactCmd.Flags().Var(&pullArtifactArgs.provider, "provider", sourceOCIRepositoryArgs.provider.Description())
pullArtifactCmd.Flags().BoolVar(&pullArtifactArgs.insecure, "insecure-registry", false, "allows artifacts to be pulled without TLS")
pullCmd.AddCommand(pullArtifactCmd) pullCmd.AddCommand(pullArtifactCmd)
} }
@@ -83,7 +86,22 @@ func pullArtifactCmdRun(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()
ociClient := oci.NewClient(oci.DefaultOptions()) opts := oci.DefaultOptions()
if pullArtifactArgs.insecure {
opts = append(opts, crane.Insecure)
}
if pullArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
opt, _, err := loginWithProvider(ctx, url, pullArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
opts = append(opts, opt)
}
ociClient := oci.NewClient(opts)
if pullArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && pullArtifactArgs.creds != "" { if pullArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && pullArtifactArgs.creds != "" {
logger.Actionf("logging in to registry with credentials") logger.Actionf("logging in to registry with credentials")
@@ -92,18 +110,6 @@ func pullArtifactCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
if pullArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
ociProvider, err := pullArtifactArgs.provider.ToOCIProvider()
if err != nil {
return fmt.Errorf("provider not supported: %w", err)
}
if err := ociClient.LoginWithProvider(ctx, url, ociProvider); err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
}
logger.Actionf("pulling artifact from %s", url) logger.Actionf("pulling artifact from %s", url)
meta, err := ociClient.Pull(ctx, url, pullArtifactArgs.output) meta, err := ociClient.Pull(ctx, url, pullArtifactArgs.output)

View File

@@ -34,9 +34,7 @@ import (
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"github.com/fluxcd/pkg/oci" "github.com/fluxcd/pkg/oci"
"github.com/fluxcd/pkg/oci/auth/login" sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/fluxcd/pkg/oci/client"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/fluxcd/flux2/v2/internal/flags" "github.com/fluxcd/flux2/v2/internal/flags"
) )
@@ -44,8 +42,8 @@ import (
var pushArtifactCmd = &cobra.Command{ var pushArtifactCmd = &cobra.Command{
Use: "artifact", Use: "artifact",
Short: "Push artifact", Short: "Push artifact",
Long: withPreviewNote(`The push artifact command creates a tarball from the given directory or the single file and uploads the artifact to an OCI repository. Long: `The push artifact command creates a tarball from the given directory or the single file and uploads the artifact to an OCI repository.
The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`), The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`,
Example: ` # Push manifests to GHCR using the short Git SHA as the OCI artifact tag Example: ` # Push manifests to GHCR using the short Git SHA as the OCI artifact tag
echo $GITHUB_PAT | docker login ghcr.io --username flux --password-stdin echo $GITHUB_PAT | docker login ghcr.io --username flux --password-stdin
flux push artifact oci://ghcr.io/org/config/app:$(git rev-parse --short HEAD) \ flux push artifact oci://ghcr.io/org/config/app:$(git rev-parse --short HEAD) \
@@ -115,6 +113,7 @@ type pushArtifactFlags struct {
output string output string
debug bool debug bool
reproducible bool reproducible bool
insecure bool
} }
var pushArtifactArgs = newPushArtifactFlags() var pushArtifactArgs = newPushArtifactFlags()
@@ -137,6 +136,7 @@ func init() {
"the format in which the artifact digest should be printed, can be 'json' or 'yaml'") "the format in which the artifact digest should be printed, can be 'json' or 'yaml'")
pushArtifactCmd.Flags().BoolVarP(&pushArtifactArgs.debug, "debug", "", false, "display logs from underlying library") pushArtifactCmd.Flags().BoolVarP(&pushArtifactArgs.debug, "debug", "", false, "display logs from underlying library")
pushArtifactCmd.Flags().BoolVar(&pushArtifactArgs.reproducible, "reproducible", false, "ensure reproducible image digests by setting the created timestamp to '1970-01-01T00:00:00Z'") pushArtifactCmd.Flags().BoolVar(&pushArtifactArgs.reproducible, "reproducible", false, "ensure reproducible image digests by setting the created timestamp to '1970-01-01T00:00:00Z'")
pushArtifactCmd.Flags().BoolVar(&pushArtifactArgs.insecure, "insecure-registry", false, "allows artifacts to be pushed without TLS")
pushCmd.AddCommand(pushArtifactCmd) pushCmd.AddCommand(pushArtifactCmd)
} }
@@ -159,7 +159,7 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("invalid path %q", pushArtifactArgs.path) return fmt.Errorf("invalid path %q", pushArtifactArgs.path)
} }
url, err := client.ParseArtifactURL(ociURL) url, err := oci.ParseArtifactURL(ociURL)
if err != nil { if err != nil {
return err return err
} }
@@ -198,7 +198,7 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
logs.Warn.SetOutput(os.Stderr) logs.Warn.SetOutput(os.Stderr)
} }
meta := client.Metadata{ meta := oci.Metadata{
Source: pushArtifactArgs.source, Source: pushArtifactArgs.source,
Revision: pushArtifactArgs.revision, Revision: pushArtifactArgs.revision,
Annotations: annotations, Annotations: annotations,
@@ -212,29 +212,25 @@ func pushArtifactCmdRun(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()
var auth authn.Authenticator var authenticator authn.Authenticator
opts := client.DefaultOptions() opts := oci.DefaultOptions()
if pushArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && pushArtifactArgs.creds != "" { if pushArtifactArgs.provider.String() == sourcev1.GenericOCIProvider && pushArtifactArgs.creds != "" {
logger.Actionf("logging in to registry with credentials") logger.Actionf("logging in to registry with credentials")
auth, err = client.GetAuthFromCredentials(pushArtifactArgs.creds) authenticator, err = oci.GetAuthFromCredentials(pushArtifactArgs.creds)
if err != nil { if err != nil {
return fmt.Errorf("could not login with credentials: %w", err) return fmt.Errorf("could not login with credentials: %w", err)
} }
opts = append(opts, crane.WithAuth(auth)) opts = append(opts, crane.WithAuth(authenticator))
} }
if pushArtifactArgs.provider.String() != sourcev1.GenericOCIProvider { if provider := pushArtifactArgs.provider.String(); provider != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials") logger.Actionf("logging in to registry with provider credentials")
ociProvider, err := pushArtifactArgs.provider.ToOCIProvider() var opt crane.Option
if err != nil { opt, authenticator, err = loginWithProvider(ctx, url, provider)
return fmt.Errorf("provider not supported: %w", err)
}
auth, err = login.NewManager().Login(ctx, url, ref, getProviderLoginOption(ociProvider))
if err != nil { if err != nil {
return fmt.Errorf("error during login with provider: %w", err) return fmt.Errorf("error during login with provider: %w", err)
} }
opts = append(opts, crane.WithAuth(auth)) opts = append(opts, opt)
} }
if rootArgs.timeout != 0 { if rootArgs.timeout != 0 {
@@ -249,27 +245,37 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
Cap: rootArgs.timeout, Cap: rootArgs.timeout,
} }
if auth == nil { if authenticator == nil {
auth, err = authn.DefaultKeychain.Resolve(ref.Context()) authenticator, err = authn.DefaultKeychain.Resolve(ref.Context())
if err != nil { if err != nil {
return err return err
} }
} }
transportOpts, err := client.WithRetryTransport(ctx, ref, auth, backoff, []string{ref.Context().Scope(transport.PushScope)}) transportOpts, err := oci.WithRetryTransport(ctx,
ref,
authenticator,
backoff,
[]string{ref.Context().Scope(transport.PushScope)},
pushArtifactArgs.insecure,
)
if err != nil { if err != nil {
return fmt.Errorf("error setting up transport: %w", err) return fmt.Errorf("error setting up transport: %w", err)
} }
opts = append(opts, transportOpts, client.WithRetryBackOff(backoff)) opts = append(opts, transportOpts, oci.WithRetryBackOff(backoff))
} }
if pushArtifactArgs.output == "" { if pushArtifactArgs.output == "" {
logger.Actionf("pushing artifact to %s", url) logger.Actionf("pushing artifact to %s", url)
} }
ociClient := client.NewClient(opts) if pushArtifactArgs.insecure {
opts = append(opts, crane.Insecure)
}
ociClient := oci.NewClient(opts)
digestURL, err := ociClient.Push(ctx, url, path, digestURL, err := ociClient.Push(ctx, url, path,
client.WithPushMetadata(meta), oci.WithPushMetadata(meta),
client.WithPushIgnorePaths(pushArtifactArgs.ignorePaths...), oci.WithPushIgnorePaths(pushArtifactArgs.ignorePaths...),
) )
if err != nil { if err != nil {
return fmt.Errorf("pushing artifact failed: %w", err) return fmt.Errorf("pushing artifact failed: %w", err)
@@ -317,16 +323,3 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
return nil return nil
} }
func getProviderLoginOption(provider oci.Provider) login.ProviderOptions {
var opts login.ProviderOptions
switch provider {
case oci.ProviderAzure:
opts.AzureAutoLogin = true
case oci.ProviderAWS:
opts.AwsAutoLogin = true
case oci.ProviderGCP:
opts.GcpAutoLogin = true
}
return opts
}

View File

@@ -108,7 +108,7 @@ func isObjectReady(obj client.Object, statusType objectStatusType) (bool, error)
case kstatus.InProgressStatus: case kstatus.InProgressStatus:
return false, nil return false, nil
default: default:
return false, fmt.Errorf(result.Message) return false, fmt.Errorf("%s", result.Message)
} }
} }

View File

@@ -132,7 +132,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
if readyCond.Status != metav1.ConditionTrue { if readyCond.Status != metav1.ConditionTrue {
return fmt.Errorf("%s reconciliation failed: '%s'", reconcile.kind, readyCond.Message) return fmt.Errorf("%s reconciliation failed: '%s'", reconcile.kind, readyCond.Message)
} }
logger.Successf(reconcile.object.successMessage()) logger.Successf("%s", reconcile.object.successMessage())
return nil return nil
} }

View File

@@ -24,7 +24,6 @@ import (
helmv2 "github.com/fluxcd/helm-controller/api/v2" helmv2 "github.com/fluxcd/helm-controller/api/v2"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var reconcileHrCmd = &cobra.Command{ var reconcileHrCmd = &cobra.Command{
@@ -92,7 +91,7 @@ func (obj helmReleaseAdapter) getSource() (reconcileSource, types.NamespacedName
} }
return reconcileCommand{ return reconcileCommand{
apiType: ociRepositoryType, apiType: ociRepositoryType,
object: ociRepositoryAdapter{&sourcev1b2.OCIRepository{}}, object: ociRepositoryAdapter{&sourcev1.OCIRepository{}},
}, namespacedName }, namespacedName
default: default:
// default case assumes the HelmRelease is using a HelmChartTemplate // default case assumes the HelmRelease is using a HelmChartTemplate

View File

@@ -0,0 +1,40 @@
/*
Copyright 2025 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 (
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
"github.com/spf13/cobra"
)
var reconcileImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Reconcile an ImagePolicy",
Long: `The reconcile image policy command triggers a reconciliation of an ImagePolicy resource and waits for it to finish.`,
Example: `
# Trigger a reconciliation for an existing image policy called 'alpine'
flux reconcile image policy alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: reconcileCommand{
apiType: imagePolicyType,
object: imagePolicyAdapter{&imagev1.ImagePolicy{}},
}.run,
}
func init() {
reconcileImageCmd.AddCommand(reconcileImagePolicyCmd)
}

View File

@@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2" imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
) )
var reconcileImageRepositoryCmd = &cobra.Command{ var reconcileImageRepositoryCmd = &cobra.Command{

View File

@@ -22,7 +22,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta" apimeta "k8s.io/apimachinery/pkg/api/meta"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2" autov1 "github.com/fluxcd/image-automation-controller/api/v1"
meta "github.com/fluxcd/pkg/apis/meta" meta "github.com/fluxcd/pkg/apis/meta"
) )

View File

@@ -22,7 +22,6 @@ import (
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1" kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1" sourcev1 "github.com/fluxcd/source-controller/api/v1"
sourcev1b2 "github.com/fluxcd/source-controller/api/v1beta2"
) )
var reconcileKsCmd = &cobra.Command{ var reconcileKsCmd = &cobra.Command{
@@ -66,10 +65,10 @@ func (obj kustomizationAdapter) reconcileSource() bool {
func (obj kustomizationAdapter) getSource() (reconcileSource, types.NamespacedName) { func (obj kustomizationAdapter) getSource() (reconcileSource, types.NamespacedName) {
var cmd reconcileCommand var cmd reconcileCommand
switch obj.Spec.SourceRef.Kind { switch obj.Spec.SourceRef.Kind {
case sourcev1b2.OCIRepositoryKind: case sourcev1.OCIRepositoryKind:
cmd = reconcileCommand{ cmd = reconcileCommand{
apiType: ociRepositoryType, apiType: ociRepositoryType,
object: ociRepositoryAdapter{&sourcev1b2.OCIRepository{}}, object: ociRepositoryAdapter{&sourcev1.OCIRepository{}},
} }
case sourcev1.GitRepositoryKind: case sourcev1.GitRepositoryKind:
cmd = reconcileCommand{ cmd = reconcileCommand{

View File

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

View File

@@ -96,6 +96,6 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
if readyCond.Status != metav1.ConditionTrue { if readyCond.Status != metav1.ConditionTrue {
return fmt.Errorf("%s reconciliation failed: %s", reconcile.kind, readyCond.Message) return fmt.Errorf("%s reconciliation failed: %s", reconcile.kind, readyCond.Message)
} }
logger.Successf(reconcile.object.successMessage()) logger.Successf("%s", reconcile.object.successMessage())
return nil return nil
} }

View File

@@ -251,9 +251,9 @@ func (resume resumeCommand) printMessage(responses []reconcileResponse) {
continue continue
} }
if r.err != nil { if r.err != nil {
logger.Failuref(r.err.Error()) logger.Failuref("%s", r.err.Error())
} }
logger.Successf("%s %s reconciliation completed", resume.kind, r.asClientObject().GetName()) logger.Successf("%s %s reconciliation completed", resume.kind, r.asClientObject().GetName())
logger.Successf(r.successMessage()) logger.Successf("%s", r.successMessage())
} }
} }

View File

@@ -0,0 +1,40 @@
/*
Copyright 2025 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 (
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
"github.com/spf13/cobra"
)
var resumeImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Resume an ImagePolicy",
Long: `The resume image policy command resumes a suspended ImagePolicy resource.`,
Example: `
# Resume a suspended image policy called 'alpine'
flux resume image policy alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: resumeCommand{
apiType: imagePolicyType,
list: imagePolicyListAdapter{&imagev1.ImagePolicyList{}},
}.run,
}
func init() {
resumeImageCmd.AddCommand(resumeImagePolicyCmd)
}

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