Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cff96ed7ca | ||
|
|
4e8a600f34 | ||
|
|
4fd5684277 | ||
|
|
06bf469ba7 | ||
|
|
b8a215230c | ||
|
|
2460cfcf1c | ||
|
|
364242c857 | ||
|
|
29e2900f59 | ||
|
|
61e1fb770e | ||
|
|
2d3fcbdea3 | ||
|
|
47e15cee3d | ||
|
|
adeb3e3f42 | ||
|
|
fb1278285b | ||
|
|
e371610849 | ||
|
|
424de63bd1 | ||
|
|
832c925d39 | ||
|
|
378f118d51 | ||
|
|
d651777122 | ||
|
|
65d8ebabb8 | ||
|
|
9195ed9a1b | ||
|
|
5df8f7313c | ||
|
|
25ed6ca0a4 | ||
|
|
9f972995bd | ||
|
|
29c46a9892 | ||
|
|
ef579fe596 | ||
|
|
5b268f62a3 | ||
|
|
1f1c8286a5 | ||
|
|
5401e1ace4 | ||
|
|
69294ef56d | ||
|
|
a685ed8029 | ||
|
|
68d0be3818 | ||
|
|
84e2cb4c1f | ||
|
|
263c664acd | ||
|
|
b12c4c22fb | ||
|
|
9f39fadb9e | ||
|
|
4c29a1ca27 | ||
|
|
f4db124d50 | ||
|
|
8f8c7cccc6 | ||
|
|
e2097c28bd | ||
|
|
871eb444fc | ||
|
|
bc5fbb9fa5 | ||
|
|
3e9749c6b1 | ||
|
|
eaf08fbe90 | ||
|
|
df411cdb88 | ||
|
|
a83c26a864 | ||
|
|
6aa853491c | ||
|
|
3af1d7a5b8 | ||
|
|
c7c57f6717 | ||
|
|
cbb97768d1 | ||
|
|
2bb40d335b | ||
|
|
1b581d6f51 | ||
|
|
c219eb2883 | ||
|
|
65a2c87b5a | ||
|
|
13aa523c37 | ||
|
|
584f0eea58 | ||
|
|
b5ebdb16b2 | ||
|
|
a18f84c27b | ||
|
|
eb86505375 | ||
|
|
984f1c8669 | ||
|
|
c7378edabc | ||
|
|
ac6c6e3a30 | ||
|
|
1bca31f32c | ||
|
|
28d099a6b2 | ||
|
|
6a2b53fbf5 | ||
|
|
7568f301b8 | ||
|
|
6add511447 | ||
|
|
a7586e69fd | ||
|
|
77db369213 | ||
|
|
2eb6a0513e | ||
|
|
38468c72db | ||
|
|
5f759200c6 | ||
|
|
81f68157fa | ||
|
|
0f3e8abf06 | ||
|
|
fcadd5312d | ||
|
|
6e32820910 | ||
|
|
8499269bab | ||
|
|
72122120cb | ||
|
|
2bbcb95f4f | ||
|
|
19982fa4a6 | ||
|
|
41cf38c6a7 | ||
|
|
16e74647eb | ||
|
|
53cdcbc4ee | ||
|
|
eb2535e066 | ||
|
|
f5c29a7a72 | ||
|
|
e243df93f1 | ||
|
|
388642d9dd | ||
|
|
9e1db06936 | ||
|
|
a260403334 | ||
|
|
6396b25886 | ||
|
|
ca480164b7 | ||
|
|
714f9df3cf | ||
|
|
6a7f1e7d48 | ||
|
|
bcdce02b78 | ||
|
|
2f0835b655 | ||
|
|
36bafa23df | ||
|
|
db611549f2 | ||
|
|
5d4cdcc207 | ||
|
|
a3b9c094b6 | ||
|
|
f82174adae | ||
|
|
c7080d2834 | ||
|
|
381127d413 | ||
|
|
f6fa468acb | ||
|
|
9228130f92 | ||
|
|
207c50ceac | ||
|
|
c3255a6e1e | ||
|
|
5e1c93a167 | ||
|
|
43c33a0cc3 | ||
|
|
f5117329e4 | ||
|
|
f7c62d12a5 | ||
|
|
fe5f181706 | ||
|
|
cc09b29a2e | ||
|
|
406601eead | ||
|
|
341d860c51 | ||
|
|
8214bb8e33 | ||
|
|
884e3c678c | ||
|
|
3b249dfe69 | ||
|
|
d236a9af57 | ||
|
|
ad9b0ae067 | ||
|
|
31f166cd02 | ||
|
|
5685ebc3a5 | ||
|
|
46bcf5da33 | ||
|
|
1784d15f36 | ||
|
|
cafce536bb | ||
|
|
d03280a12f | ||
|
|
b30ef523f8 | ||
|
|
a6a303629a | ||
|
|
61e79ef793 | ||
|
|
f632abd8fa | ||
|
|
c3911fe490 | ||
|
|
505701e1c6 | ||
|
|
67643e7487 | ||
|
|
a962c17adb | ||
|
|
479b4b5859 | ||
|
|
57f8cf85ca | ||
|
|
dd2c20b225 | ||
|
|
9da427a515 | ||
|
|
604773e866 | ||
|
|
1331f5260a | ||
|
|
65d0f3569c | ||
|
|
ba522877ec | ||
|
|
4b63ccf140 | ||
|
|
4fcf93306a | ||
|
|
96d8ec2016 | ||
|
|
3697a5e348 | ||
|
|
084c587c0e | ||
|
|
dcb505045e | ||
|
|
0aeb3128ed |
46
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
46
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve Flux v2
|
||||
title: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
Find out more about your support options and getting help at
|
||||
|
||||
https://fluxcd.io/support/
|
||||
|
||||
-->
|
||||
|
||||
### Describe the bug
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
### To Reproduce
|
||||
|
||||
Steps to reproduce the behaviour:
|
||||
|
||||
1. Provide Flux install instructions
|
||||
2. Provide a GitHub repository with Kubernetes manifests
|
||||
|
||||
### Expected behavior
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
### Additional context
|
||||
|
||||
- Kubernetes version:
|
||||
- Git provider:
|
||||
- Container registry provider:
|
||||
|
||||
Below please provide the output of the following commands:
|
||||
|
||||
```cli
|
||||
flux --version
|
||||
flux check
|
||||
kubectl -n <namespace> get all
|
||||
kubectl -n <namespace> logs deploy/source-controller
|
||||
kubectl -n <namespace> logs deploy/kustomize-controller
|
||||
```
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Ask a question
|
||||
url: https://github.com/fluxcd/flux2/discussions
|
||||
about: Please ask and answer questions here.
|
||||
5
.github/kind/config.yaml
vendored
Normal file
5
.github/kind/config.yaml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
kind: Cluster
|
||||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
networking:
|
||||
disableDefaultCNI: true # disable kindnet
|
||||
podSubnet: 192.168.0.0/16 # set to Calico's default subnet
|
||||
12
.github/workflows/docs.yaml
vendored
12
.github/workflows/docs.yaml
vendored
@@ -54,6 +54,18 @@ jobs:
|
||||
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/notification-controller/$NOTIFICATION_VER/docs/spec/v1beta1/receiver.md" > docs/components/notification/receiver.md
|
||||
}
|
||||
|
||||
{
|
||||
# image-*-controller CRDs; these use the same API group
|
||||
IMG_REFL_VER=$(controller_version image-reflector-controller)
|
||||
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-reflector-controller/$IMG_REFL_VER/docs/api/image-reflector.md" > docs/components/image/reflector-api.md
|
||||
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-reflector-controller/$IMG_REFL_VER/docs/spec/v1alpha1/imagerepositories.md" > docs/components/image/imagerepositories.md
|
||||
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-reflector-controller/$IMG_REFL_VER/docs/spec/v1alpha1/imagepolicies.md" > docs/components/image/imagepolicies.md
|
||||
|
||||
IMG_AUTO_VER=$(controller_version image-automation-controller)
|
||||
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-automation-controller/$IMG_AUTO_VER/docs/api/image-automation.md" > docs/components/image/automation-api.md
|
||||
curl -# -Lf "https://raw.githubusercontent.com/fluxcd/image-automation-controller/$IMG_AUTO_VER/docs/spec/v1alpha1/imageupdateautomations.md" > docs/components/image/imageupdateautomations.md
|
||||
}
|
||||
|
||||
{
|
||||
# install script
|
||||
cp install/flux.sh docs/install.sh
|
||||
|
||||
31
.github/workflows/e2e.yaml
vendored
31
.github/workflows/e2e.yaml
vendored
@@ -26,7 +26,13 @@ jobs:
|
||||
- name: Setup Kubernetes
|
||||
uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
image: kindest/node:v1.16.9
|
||||
version: "v0.10.0"
|
||||
image: kindest/node:v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab
|
||||
config: .github/kind/config.yaml # disable KIND-net
|
||||
- name: Setup Calico for network policy
|
||||
run: |
|
||||
kubectl apply -f https://docs.projectcalico.org/v3.16/manifests/calico.yaml
|
||||
kubectl -n kube-system set env daemonset/calico-node FELIX_IGNORELOOSERPF=true
|
||||
- name: Run test
|
||||
run: make test
|
||||
- name: Check if working tree is dirty
|
||||
@@ -44,6 +50,15 @@ jobs:
|
||||
- name: flux install --manifests
|
||||
run: |
|
||||
./bin/flux install --manifests ./manifests/install/
|
||||
- name: flux create secret
|
||||
run: |
|
||||
./bin/flux create secret git git-ssh-test \
|
||||
--url ssh://git@github.com/stefanprodan/podinfo
|
||||
./bin/flux create secret git git-https-test \
|
||||
--url https://github.com/stefanprodan/podinfo \
|
||||
--username=test --password=test
|
||||
./bin/flux create secret helm helm-test \
|
||||
--username=test --password=test
|
||||
- name: flux create source git
|
||||
run: |
|
||||
./bin/flux create source git podinfo \
|
||||
@@ -146,6 +161,20 @@ jobs:
|
||||
--chart=podinfo \
|
||||
--chart-version="5.0.x" \
|
||||
--service-account=dev-team
|
||||
- name: flux create image repository
|
||||
run: |
|
||||
./bin/flux create image repository podinfo \
|
||||
--image=ghcr.io/stefanprodan/podinfo \
|
||||
--interval=1m
|
||||
- name: flux create image policy
|
||||
run: |
|
||||
./bin/flux create image policy podinfo \
|
||||
--image-ref=podinfo \
|
||||
--interval=1m \
|
||||
--semver=5.0.x
|
||||
- name: flux get image policy
|
||||
run: |
|
||||
./bin/flux get image policy podinfo | grep '5.0.3'
|
||||
- name: flux2-kustomize-helm-example
|
||||
run: |
|
||||
./bin/flux create source git flux-system \
|
||||
|
||||
2
.github/workflows/update.yml
vendored
2
.github/workflows/update.yml
vendored
@@ -4,6 +4,8 @@ on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 * * * *"
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
update-components:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
project_name: flux
|
||||
builds:
|
||||
- <<: &build_defaults
|
||||
binary: flux
|
||||
|
||||
36
README.md
36
README.md
@@ -66,6 +66,8 @@ the following guides:
|
||||
- [Setup Notifications](https://toolkit.fluxcd.io/guides/notifications/)
|
||||
- [Setup Webhook Receivers](https://toolkit.fluxcd.io/guides/webhook-receivers/)
|
||||
|
||||
If you should need help, please refer to our **[Support page](https://fluxcd.io/support/)**.
|
||||
|
||||
## GitOps Toolkit
|
||||
|
||||
The GitOps Toolkit is the set of APIs and controllers that make up the
|
||||
@@ -97,28 +99,22 @@ guides](https://toolkit.fluxcd.io/dev-guides/source-watcher/).
|
||||
|
||||
## Community
|
||||
|
||||
The Flux project is always looking for new contributors and there are a multitude of ways to get involved.
|
||||
Depending on what you want to do, some of the following bits might be your first steps:
|
||||
Need help or want to contribute? Please see the links below. The Flux project is always looking for new contributors and there are a multitude of ways to get involved.
|
||||
|
||||
- Join our upcoming dev meetings ([meeting access and agenda](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view))
|
||||
- Talk to us in the #flux channel on [CNCF Slack](https://slack.cncf.io/)
|
||||
- Join the [planning discussions](https://github.com/fluxcd/flux2/discussions)
|
||||
- And if you are completely new to Flux and the GitOps Toolkit, take a look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
|
||||
- To be part of the conversation about Flux's development, [join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
|
||||
- Check out [how to contribute](CONTRIBUTING.md) to the project
|
||||
- Getting Started?
|
||||
- Look at our [Get Started guide](https://toolkit.fluxcd.io/get-started/) and give us feedback
|
||||
- Need help?
|
||||
- First: Ask questions on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
|
||||
- Second: Talk to us in the #flux channel on [CNCF Slack](https://slack.cncf.io/)
|
||||
- Please follow our [Support Guidelines](https://fluxcd.io/support/) (in short: be nice, be respectful of volunteers' time, understand that maintainers and contributors cannot respond to all DMs, and keep discussions in the public #flux channel as much as possible).
|
||||
- Have feature proposals or want to contribute?
|
||||
- Propose features on our [GH Discussions page](https://github.com/fluxcd/flux2/discussions)
|
||||
- Join our upcoming dev meetings ([meeting access and agenda](https://docs.google.com/document/d/1l_M0om0qUEN_NNiGgpqJ2tvsF2iioHkaARDeh6b70B0/view))
|
||||
- [Join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
|
||||
- Check out [how to contribute](CONTRIBUTING.md) to the project
|
||||
|
||||
### Upcoming Events
|
||||
- 11 Jan 2021 - [Helm + GitOps = ⚡️⚡️⚡️ with Scott Rigby](https://www.meetup.com/GitOps-Community/events/275348736/)
|
||||
### Events
|
||||
|
||||
### Featured Talks
|
||||
- 14 Dec 2020 - [The Power of GitOps with Flux and Flagger (GitOps Hands-On) with Leigh Capili](https://youtu.be/cB7iXeNLteE)
|
||||
- 30 Nov 2020 - [The Power of GitOps with Flux 2 - Part 3 with Leigh Capili](https://youtu.be/N_K5g7o9JKg)
|
||||
- 24 Nov 2020 - [Flux CD v2 with GitOps Toolkit - Kubernetes Deployment and Sync Mechanism](https://youtu.be/R6OeIgb7lUI)
|
||||
- 02 Nov 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 2 with Leigh Capili](https://youtu.be/fC2YCxQRUwU)
|
||||
- 28 Oct 2020 - [The Kubelist Podcast: Flux with Michael Bridgen](https://www.heavybit.com/library/podcasts/the-kubelist-podcast/ep-5-flux-with-michael-bridgen-of-weaveworks/)
|
||||
- 19 Oct 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 1 with Leigh Capili](https://youtu.be/0v5bjysXTL8)
|
||||
- 12 Oct 2020 - [Rawkode Live: Introduction to GitOps Toolkit with Stefan Prodan](https://youtu.be/HqTzuOBP0eY)
|
||||
- 04 Sep 2020 - [KubeCon Europe: The road to Flux v2 and Progressive Delivery with Stefan Prodan & Hidde Beydals](https://youtu.be/8v94nUkXsxU)
|
||||
- 25 Jun 2020 - [Cloud Native Nordics: Introduction to GitOps & GitOps Toolkit with Alexis Richardson & Stefan Prodan](https://youtu.be/qQBtSkgl7tI)
|
||||
Check out our **[events calendar](https://fluxcd.io/community/#talks)**, both with upcoming talks you can attend or past events videos you can watch.
|
||||
|
||||
We look forward to seeing you with us!
|
||||
|
||||
@@ -22,7 +22,7 @@ Note that this action can only be used on GitHub **Linux AMD64** runners.
|
||||
|
||||
### Automate Flux updates
|
||||
|
||||
Example workflow for updating Flux's components generated with `flux bootstrap --arch=amd64 --path=clusters/production`:
|
||||
Example workflow for updating Flux's components generated with `flux bootstrap --path=clusters/production`:
|
||||
|
||||
```yaml
|
||||
name: update-flux
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
- name: Check for updates
|
||||
id: update
|
||||
run: |
|
||||
flux install --arch=amd64 \
|
||||
flux install \
|
||||
--export > ./clusters/production/flux-system/gotk-components.yaml
|
||||
|
||||
VERSION="$(flux -v)"
|
||||
|
||||
@@ -45,61 +45,71 @@ var bootstrapCmd = &cobra.Command{
|
||||
Long: "The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.",
|
||||
}
|
||||
|
||||
var (
|
||||
bootstrapVersion string
|
||||
bootstrapDefaultComponents []string
|
||||
bootstrapExtraComponents []string
|
||||
bootstrapRegistry string
|
||||
bootstrapImagePullSecret string
|
||||
bootstrapBranch string
|
||||
bootstrapWatchAllNamespaces bool
|
||||
bootstrapNetworkPolicy bool
|
||||
bootstrapManifestsPath string
|
||||
bootstrapArch = flags.Arch(defaults.Arch)
|
||||
bootstrapLogLevel = flags.LogLevel(defaults.LogLevel)
|
||||
bootstrapRequiredComponents = []string{"source-controller", "kustomize-controller"}
|
||||
bootstrapTokenAuth bool
|
||||
bootstrapClusterDomain string
|
||||
)
|
||||
type bootstrapFlags struct {
|
||||
version string
|
||||
defaultComponents []string
|
||||
extraComponents []string
|
||||
registry string
|
||||
imagePullSecret string
|
||||
branch string
|
||||
watchAllNamespaces bool
|
||||
networkPolicy bool
|
||||
manifestsPath string
|
||||
arch flags.Arch
|
||||
logLevel flags.LogLevel
|
||||
requiredComponents []string
|
||||
tokenAuth bool
|
||||
clusterDomain string
|
||||
}
|
||||
|
||||
const (
|
||||
bootstrapDefaultBranch = "main"
|
||||
)
|
||||
|
||||
var bootstrapArgs = NewBootstrapFlags()
|
||||
|
||||
func init() {
|
||||
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapVersion, "version", "v", defaults.Version,
|
||||
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapArgs.version, "version", "v", rootArgs.defaults.Version,
|
||||
"toolkit version")
|
||||
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapDefaultComponents, "components", defaults.Components,
|
||||
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components,
|
||||
"list of components, accepts comma-separated values")
|
||||
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapExtraComponents, "components-extra", nil,
|
||||
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil,
|
||||
"list of components in addition to those supplied or defaulted, accepts comma-separated values")
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapRegistry, "registry", "ghcr.io/fluxcd",
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
|
||||
"container registry where the toolkit images are published")
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapImagePullSecret, "image-pull-secret", "",
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.imagePullSecret, "image-pull-secret", "",
|
||||
"Kubernetes secret name used for pulling the toolkit images from a private registry")
|
||||
bootstrapCmd.PersistentFlags().Var(&bootstrapArch, "arch", bootstrapArch.Description())
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapBranch, "branch", bootstrapDefaultBranch,
|
||||
bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.arch, "arch", bootstrapArgs.arch.Description())
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.branch, "branch", bootstrapDefaultBranch,
|
||||
"default branch (for GitHub this must match the default branch setting for the organization)")
|
||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapWatchAllNamespaces, "watch-all-namespaces", true,
|
||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.watchAllNamespaces, "watch-all-namespaces", true,
|
||||
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
|
||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapNetworkPolicy, "network-policy", true,
|
||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.networkPolicy, "network-policy", true,
|
||||
"deny ingress access to the toolkit controllers from other namespaces using network policies")
|
||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapTokenAuth, "token-auth", false,
|
||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapArgs.tokenAuth, "token-auth", false,
|
||||
"when enabled, the personal access token will be used instead of SSH deploy key")
|
||||
bootstrapCmd.PersistentFlags().Var(&bootstrapLogLevel, "log-level", bootstrapLogLevel.Description())
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapManifestsPath, "manifests", "", "path to the manifest directory")
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapClusterDomain, "cluster-domain", defaults.ClusterDomain, "internal cluster domain")
|
||||
bootstrapCmd.PersistentFlags().Var(&bootstrapArgs.logLevel, "log-level", bootstrapArgs.logLevel.Description())
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.manifestsPath, "manifests", "", "path to the manifest directory")
|
||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.clusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
|
||||
bootstrapCmd.PersistentFlags().MarkHidden("manifests")
|
||||
bootstrapCmd.PersistentFlags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
|
||||
rootCmd.AddCommand(bootstrapCmd)
|
||||
}
|
||||
|
||||
func NewBootstrapFlags() bootstrapFlags {
|
||||
return bootstrapFlags{
|
||||
logLevel: flags.LogLevel(rootArgs.defaults.LogLevel),
|
||||
requiredComponents: []string{"source-controller", "kustomize-controller"},
|
||||
}
|
||||
}
|
||||
|
||||
func bootstrapComponents() []string {
|
||||
return append(bootstrapDefaultComponents, bootstrapExtraComponents...)
|
||||
return append(bootstrapArgs.defaultComponents, bootstrapArgs.extraComponents...)
|
||||
}
|
||||
|
||||
func bootstrapValidate() error {
|
||||
components := bootstrapComponents()
|
||||
for _, component := range bootstrapRequiredComponents {
|
||||
for _, component := range bootstrapArgs.requiredComponents {
|
||||
if !utils.ContainsItemString(components, component) {
|
||||
return fmt.Errorf("component %s is required", component)
|
||||
}
|
||||
@@ -115,24 +125,23 @@ func bootstrapValidate() error {
|
||||
func generateInstallManifests(targetPath, namespace, tmpDir string, localManifests string) (string, error) {
|
||||
opts := install.Options{
|
||||
BaseURL: localManifests,
|
||||
Version: bootstrapVersion,
|
||||
Namespace: namespace,
|
||||
Version: bootstrapArgs.version,
|
||||
Namespace: rootArgs.namespace,
|
||||
Components: bootstrapComponents(),
|
||||
Registry: bootstrapRegistry,
|
||||
ImagePullSecret: bootstrapImagePullSecret,
|
||||
Arch: bootstrapArch.String(),
|
||||
WatchAllNamespaces: bootstrapWatchAllNamespaces,
|
||||
NetworkPolicy: bootstrapNetworkPolicy,
|
||||
LogLevel: bootstrapLogLevel.String(),
|
||||
NotificationController: defaults.NotificationController,
|
||||
ManifestFile: defaults.ManifestFile,
|
||||
Timeout: timeout,
|
||||
Registry: bootstrapArgs.registry,
|
||||
ImagePullSecret: bootstrapArgs.imagePullSecret,
|
||||
WatchAllNamespaces: bootstrapArgs.watchAllNamespaces,
|
||||
NetworkPolicy: bootstrapArgs.networkPolicy,
|
||||
LogLevel: bootstrapArgs.logLevel.String(),
|
||||
NotificationController: rootArgs.defaults.NotificationController,
|
||||
ManifestFile: rootArgs.defaults.ManifestFile,
|
||||
Timeout: rootArgs.timeout,
|
||||
TargetPath: targetPath,
|
||||
ClusterDomain: bootstrapClusterDomain,
|
||||
ClusterDomain: bootstrapArgs.clusterDomain,
|
||||
}
|
||||
|
||||
if localManifests == "" {
|
||||
opts.BaseURL = defaults.BaseURL
|
||||
opts.BaseURL = rootArgs.defaults.BaseURL
|
||||
}
|
||||
|
||||
output, err := install.Generate(opts)
|
||||
@@ -149,13 +158,13 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
|
||||
|
||||
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
|
||||
kubectlArgs := []string{"apply", "-f", manifestPath}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
}
|
||||
|
||||
for _, deployment := range components {
|
||||
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
kubectlArgs = []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
}
|
||||
}
|
||||
@@ -191,20 +200,20 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
|
||||
|
||||
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, manifestsPath string) error {
|
||||
kubectlArgs := []string{"apply", "-k", manifestsPath}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for cluster sync")
|
||||
|
||||
var gitRepository sourcev1.GitRepository
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, types.NamespacedName{Name: name, Namespace: namespace}, &gitRepository)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var kustomization kustomizev1.Kustomization
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isKustomizationReady(ctx, kubeClient, types.NamespacedName{Name: name, Namespace: namespace}, &kustomization)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -239,7 +248,7 @@ func shouldCreateDeployKey(ctx context.Context, kubeClient client.Client, namesp
|
||||
}
|
||||
|
||||
func generateDeployKey(ctx context.Context, kubeClient client.Client, url *url.URL, namespace string) (string, error) {
|
||||
pair, err := generateKeyPair(ctx, sourceGitKeyAlgorithm, sourceGitRSABits, sourceGitECDSACurve)
|
||||
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ the bootstrap command will perform an upgrade if needed.`,
|
||||
flux bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
|
||||
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
|
||||
# Run bootstrap for a private repo hosted on GitHub Enterprise using SSH auth
|
||||
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --ssh-hostname=<domain>
|
||||
@@ -71,35 +71,37 @@ the bootstrap command will perform an upgrade if needed.`,
|
||||
RunE: bootstrapGitHubCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
ghOwner string
|
||||
ghRepository string
|
||||
ghInterval time.Duration
|
||||
ghPersonal bool
|
||||
ghPrivate bool
|
||||
ghHostname string
|
||||
ghPath flags.SafeRelativePath
|
||||
ghTeams []string
|
||||
ghDelete bool
|
||||
ghSSHHostname string
|
||||
)
|
||||
type githubFlags struct {
|
||||
owner string
|
||||
repository string
|
||||
interval time.Duration
|
||||
personal bool
|
||||
private bool
|
||||
hostname string
|
||||
path flags.SafeRelativePath
|
||||
teams []string
|
||||
delete bool
|
||||
sshHostname string
|
||||
}
|
||||
|
||||
const (
|
||||
ghDefaultPermission = "maintain"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghOwner, "owner", "", "GitHub user or organization name")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghRepository, "repository", "", "GitHub repository name")
|
||||
bootstrapGitHubCmd.Flags().StringArrayVar(&ghTeams, "team", []string{}, "GitHub team to be given maintainer access")
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&ghPersonal, "personal", false, "is personal repository")
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&ghPrivate, "private", true, "is private repository")
|
||||
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghSSHHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||
bootstrapGitHubCmd.Flags().Var(&ghPath, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
|
||||
var githubArgs githubFlags
|
||||
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
|
||||
func init() {
|
||||
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.owner, "owner", "", "GitHub user or organization name")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.repository, "repository", "", "GitHub repository name")
|
||||
bootstrapGitHubCmd.Flags().StringArrayVar(&githubArgs.teams, "team", []string{}, "GitHub team to be given maintainer access")
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.personal, "personal", false, "is personal repository")
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.private, "private", true, "is private repository")
|
||||
bootstrapGitHubCmd.Flags().DurationVar(&githubArgs.interval, "interval", time.Minute, "sync interval")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.hostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&githubArgs.sshHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||
bootstrapGitHubCmd.Flags().Var(&githubArgs.path, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
|
||||
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&githubArgs.delete, "delete", false, "delete repository (used for testing only)")
|
||||
bootstrapGitHubCmd.Flags().MarkHidden("delete")
|
||||
|
||||
bootstrapCmd.AddCommand(bootstrapGitHubCmd)
|
||||
@@ -115,41 +117,41 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, namespace, filepath.ToSlash(ghPath.String()))
|
||||
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, rootArgs.namespace, filepath.ToSlash(githubArgs.path.String()))
|
||||
|
||||
if bootstrapPathDiffers {
|
||||
return fmt.Errorf("cluster already bootstrapped to %v path", usedPath)
|
||||
}
|
||||
|
||||
repository, err := git.NewRepository(ghRepository, ghOwner, ghHostname, ghToken, "flux", ghOwner+"@users.noreply.github.com")
|
||||
repository, err := git.NewRepository(githubArgs.repository, githubArgs.owner, githubArgs.hostname, ghToken, "flux", githubArgs.owner+"@users.noreply.github.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ghSSHHostname != "" {
|
||||
repository.SSHHost = ghSSHHostname
|
||||
if githubArgs.sshHostname != "" {
|
||||
repository.SSHHost = githubArgs.sshHostname
|
||||
}
|
||||
|
||||
provider := &git.GithubProvider{
|
||||
IsPrivate: ghPrivate,
|
||||
IsPersonal: ghPersonal,
|
||||
IsPrivate: githubArgs.private,
|
||||
IsPersonal: githubArgs.personal,
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", namespace)
|
||||
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if ghDelete {
|
||||
if githubArgs.delete {
|
||||
if err := provider.DeleteRepository(ctx, repository); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -158,7 +160,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// create GitHub repository if doesn't exists
|
||||
logger.Actionf("connecting to %s", ghHostname)
|
||||
logger.Actionf("connecting to %s", githubArgs.hostname)
|
||||
changed, err := provider.CreateRepository(ctx, repository)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -169,8 +171,8 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
withErrors := false
|
||||
// add teams to org repository
|
||||
if !ghPersonal {
|
||||
for _, team := range ghTeams {
|
||||
if !githubArgs.personal {
|
||||
for _, team := range githubArgs.teams {
|
||||
if changed, err := provider.AddTeam(ctx, repository, team, ghDefaultPermission); err != nil {
|
||||
logger.Failuref(err.Error())
|
||||
withErrors = true
|
||||
@@ -181,20 +183,20 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// clone repository and checkout the main branch
|
||||
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
|
||||
if err := repository.Checkout(ctx, bootstrapArgs.branch, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("repository cloned")
|
||||
|
||||
// generate install manifests
|
||||
logger.Generatef("generating manifests")
|
||||
installManifest, err := generateInstallManifests(ghPath.String(), namespace, tmpDir, bootstrapManifestsPath)
|
||||
installManifest, err := generateInstallManifests(githubArgs.path.String(), rootArgs.namespace, tmpDir, bootstrapArgs.manifestsPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stage install manifests
|
||||
changed, err = repository.Commit(ctx, path.Join(ghPath.String(), namespace), "Add manifests")
|
||||
changed, err = repository.Commit(ctx, path.Join(githubArgs.path.String(), rootArgs.namespace), "Add manifests")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -210,11 +212,11 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// determine if repo synchronization is working
|
||||
isInstall := shouldInstallManifests(ctx, kubeClient, namespace)
|
||||
isInstall := shouldInstallManifests(ctx, kubeClient, rootArgs.namespace)
|
||||
|
||||
if isInstall {
|
||||
// apply install manifests
|
||||
logger.Actionf("installing components in %s namespace", namespace)
|
||||
logger.Actionf("installing components in %s namespace", rootArgs.namespace)
|
||||
if err := applyInstallManifests(ctx, installManifest, bootstrapComponents()); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -223,12 +225,12 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
repoURL := repository.GetURL()
|
||||
|
||||
if bootstrapTokenAuth {
|
||||
if bootstrapArgs.tokenAuth {
|
||||
// setup HTTPS token auth
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
Namespace: namespace,
|
||||
Name: rootArgs.namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"username": "git",
|
||||
@@ -241,21 +243,21 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
// setup SSH deploy key
|
||||
repoURL = repository.GetSSH()
|
||||
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
||||
if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
|
||||
logger.Actionf("configuring deploy key")
|
||||
u, err := url.Parse(repository.GetSSH())
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
|
||||
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
|
||||
key, err := generateDeployKey(ctx, kubeClient, u, rootArgs.namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating deploy key failed: %w", err)
|
||||
}
|
||||
|
||||
keyName := "flux"
|
||||
if ghPath != "" {
|
||||
keyName = fmt.Sprintf("flux-%s", ghPath)
|
||||
if githubArgs.path != "" {
|
||||
keyName = fmt.Sprintf("flux-%s", githubArgs.path)
|
||||
}
|
||||
|
||||
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
|
||||
@@ -268,13 +270,13 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// configure repo synchronization
|
||||
logger.Actionf("generating sync manifests")
|
||||
syncManifests, err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, filepath.ToSlash(ghPath.String()), tmpDir, ghInterval)
|
||||
syncManifests, err := generateSyncManifests(repoURL, bootstrapArgs.branch, rootArgs.namespace, rootArgs.namespace, filepath.ToSlash(githubArgs.path.String()), tmpDir, githubArgs.interval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// commit and push manifests
|
||||
if changed, err = repository.Commit(ctx, path.Join(ghPath.String(), namespace), "Add manifests"); err != nil {
|
||||
if changed, err = repository.Commit(ctx, path.Join(githubArgs.path.String(), rootArgs.namespace), "Add manifests"); err != nil {
|
||||
return err
|
||||
} else if changed {
|
||||
if err := repository.Push(ctx); err != nil {
|
||||
@@ -285,7 +287,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// apply manifests and waiting for sync
|
||||
logger.Actionf("applying sync manifests")
|
||||
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, syncManifests); err != nil {
|
||||
if err := applySyncManifests(ctx, kubeClient, rootArgs.namespace, rootArgs.namespace, syncManifests); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ the bootstrap command will perform an upgrade if needed.`,
|
||||
Example: ` # Create a GitLab API token and export it as an env var
|
||||
export GITLAB_TOKEN=<my-token>
|
||||
|
||||
# Run bootstrap for a private repo using HTTPS token authentication
|
||||
# Run bootstrap for a private repo using HTTPS token authentication
|
||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --token-auth
|
||||
|
||||
# Run bootstrap for a private repo using SSH authentication
|
||||
@@ -60,7 +60,7 @@ the bootstrap command will perform an upgrade if needed.`,
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal --token-auth
|
||||
|
||||
# Run bootstrap for a private repo hosted on a GitLab server
|
||||
# Run bootstrap for a private repo hosted on a GitLab server
|
||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain> --token-auth
|
||||
|
||||
# Run bootstrap for a an existing repository with a branch named main
|
||||
@@ -73,26 +73,28 @@ const (
|
||||
gitlabProjectRegex = `\A[[:alnum:]\x{00A9}-\x{1f9ff}_][[:alnum:]\p{Pd}\x{00A9}-\x{1f9ff}_\.]*\z`
|
||||
)
|
||||
|
||||
var (
|
||||
glOwner string
|
||||
glRepository string
|
||||
glInterval time.Duration
|
||||
glPersonal bool
|
||||
glPrivate bool
|
||||
glHostname string
|
||||
glSSHHostname string
|
||||
glPath flags.SafeRelativePath
|
||||
)
|
||||
type gitlabFlags struct {
|
||||
owner string
|
||||
repository string
|
||||
interval time.Duration
|
||||
personal bool
|
||||
private bool
|
||||
hostname string
|
||||
sshHostname string
|
||||
path flags.SafeRelativePath
|
||||
}
|
||||
|
||||
var gitlabArgs gitlabFlags
|
||||
|
||||
func init() {
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glOwner, "owner", "", "GitLab user or group name")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glRepository, "repository", "", "GitLab repository name")
|
||||
bootstrapGitLabCmd.Flags().BoolVar(&glPersonal, "personal", false, "is personal repository")
|
||||
bootstrapGitLabCmd.Flags().BoolVar(&glPrivate, "private", true, "is private repository")
|
||||
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||
bootstrapGitLabCmd.Flags().Var(&glPath, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.owner, "owner", "", "GitLab user or group name")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.repository, "repository", "", "GitLab repository name")
|
||||
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.personal, "personal", false, "is personal repository")
|
||||
bootstrapGitLabCmd.Flags().BoolVar(&gitlabArgs.private, "private", true, "is private repository")
|
||||
bootstrapGitLabCmd.Flags().DurationVar(&gitlabArgs.interval, "interval", time.Minute, "sync interval")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.hostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&gitlabArgs.sshHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||
bootstrapGitLabCmd.Flags().Var(&gitlabArgs.path, "path", "path relative to the repository root, when specified the cluster sync will be scoped to this path")
|
||||
|
||||
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
|
||||
}
|
||||
@@ -103,54 +105,54 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("%s environment variable not found", git.GitLabTokenName)
|
||||
}
|
||||
|
||||
projectNameIsValid, err := regexp.MatchString(gitlabProjectRegex, glRepository)
|
||||
projectNameIsValid, err := regexp.MatchString(gitlabProjectRegex, gitlabArgs.repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !projectNameIsValid {
|
||||
return fmt.Errorf("%s is an invalid project name for gitlab.\nIt can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.", glRepository)
|
||||
return fmt.Errorf("%s is an invalid project name for gitlab.\nIt can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.", gitlabArgs.repository)
|
||||
}
|
||||
|
||||
if err := bootstrapValidate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, namespace, filepath.ToSlash(glPath.String()))
|
||||
usedPath, bootstrapPathDiffers := checkIfBootstrapPathDiffers(ctx, kubeClient, rootArgs.namespace, filepath.ToSlash(gitlabArgs.path.String()))
|
||||
|
||||
if bootstrapPathDiffers {
|
||||
return fmt.Errorf("cluster already bootstrapped to %v path", usedPath)
|
||||
}
|
||||
|
||||
repository, err := git.NewRepository(glRepository, glOwner, glHostname, glToken, "flux", glOwner+"@users.noreply.gitlab.com")
|
||||
repository, err := git.NewRepository(gitlabArgs.repository, gitlabArgs.owner, gitlabArgs.hostname, glToken, "flux", gitlabArgs.owner+"@users.noreply.gitlab.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if glSSHHostname != "" {
|
||||
repository.SSHHost = glSSHHostname
|
||||
if gitlabArgs.sshHostname != "" {
|
||||
repository.SSHHost = gitlabArgs.sshHostname
|
||||
}
|
||||
|
||||
provider := &git.GitLabProvider{
|
||||
IsPrivate: glPrivate,
|
||||
IsPersonal: glPersonal,
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", namespace)
|
||||
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
provider := &git.GitLabProvider{
|
||||
IsPrivate: gitlabArgs.private,
|
||||
IsPersonal: gitlabArgs.personal,
|
||||
}
|
||||
|
||||
// create GitLab project if doesn't exists
|
||||
logger.Actionf("connecting to %s", glHostname)
|
||||
logger.Actionf("connecting to %s", gitlabArgs.hostname)
|
||||
changed, err := provider.CreateRepository(ctx, repository)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -160,20 +162,20 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// clone repository and checkout the master branch
|
||||
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
|
||||
if err := repository.Checkout(ctx, bootstrapArgs.branch, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("repository cloned")
|
||||
|
||||
// generate install manifests
|
||||
logger.Generatef("generating manifests")
|
||||
installManifest, err := generateInstallManifests(glPath.String(), namespace, tmpDir, bootstrapManifestsPath)
|
||||
installManifest, err := generateInstallManifests(gitlabArgs.path.String(), rootArgs.namespace, tmpDir, bootstrapArgs.manifestsPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stage install manifests
|
||||
changed, err = repository.Commit(ctx, path.Join(glPath.String(), namespace), "Add manifests")
|
||||
changed, err = repository.Commit(ctx, path.Join(gitlabArgs.path.String(), rootArgs.namespace), "Add manifests")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -189,11 +191,11 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// determine if repo synchronization is working
|
||||
isInstall := shouldInstallManifests(ctx, kubeClient, namespace)
|
||||
isInstall := shouldInstallManifests(ctx, kubeClient, rootArgs.namespace)
|
||||
|
||||
if isInstall {
|
||||
// apply install manifests
|
||||
logger.Actionf("installing components in %s namespace", namespace)
|
||||
logger.Actionf("installing components in %s namespace", rootArgs.namespace)
|
||||
if err := applyInstallManifests(ctx, installManifest, bootstrapComponents()); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -202,12 +204,12 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
repoURL := repository.GetURL()
|
||||
|
||||
if bootstrapTokenAuth {
|
||||
if bootstrapArgs.tokenAuth {
|
||||
// setup HTTPS token auth
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
Namespace: namespace,
|
||||
Name: rootArgs.namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"username": "git",
|
||||
@@ -220,21 +222,21 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
// setup SSH deploy key
|
||||
repoURL = repository.GetSSH()
|
||||
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
||||
if shouldCreateDeployKey(ctx, kubeClient, rootArgs.namespace) {
|
||||
logger.Actionf("configuring deploy key")
|
||||
u, err := url.Parse(repoURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
|
||||
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
|
||||
key, err := generateDeployKey(ctx, kubeClient, u, rootArgs.namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating deploy key failed: %w", err)
|
||||
}
|
||||
|
||||
keyName := "flux"
|
||||
if glPath != "" {
|
||||
keyName = fmt.Sprintf("flux-%s", glPath)
|
||||
if gitlabArgs.path != "" {
|
||||
keyName = fmt.Sprintf("flux-%s", gitlabArgs.path)
|
||||
}
|
||||
|
||||
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
|
||||
@@ -247,13 +249,13 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// configure repo synchronization
|
||||
logger.Actionf("generating sync manifests")
|
||||
syncManifests, err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, filepath.ToSlash(glPath.String()), tmpDir, glInterval)
|
||||
syncManifests, err := generateSyncManifests(repoURL, bootstrapArgs.branch, rootArgs.namespace, rootArgs.namespace, filepath.ToSlash(gitlabArgs.path.String()), tmpDir, gitlabArgs.interval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// commit and push manifests
|
||||
if changed, err = repository.Commit(ctx, path.Join(glPath.String(), namespace), "Add manifests"); err != nil {
|
||||
if changed, err = repository.Commit(ctx, path.Join(gitlabArgs.path.String(), rootArgs.namespace), "Add manifests"); err != nil {
|
||||
return err
|
||||
} else if changed {
|
||||
if err := repository.Push(ctx); err != nil {
|
||||
@@ -264,7 +266,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// apply manifests and waiting for sync
|
||||
logger.Actionf("applying sync manifests")
|
||||
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, syncManifests); err != nil {
|
||||
if err := applySyncManifests(ctx, kubeClient, rootArgs.namespace, rootArgs.namespace, syncManifests); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -44,25 +44,27 @@ the local environment is configured correctly and if the installed components ar
|
||||
RunE: runCheckCmd,
|
||||
}
|
||||
|
||||
var (
|
||||
checkPre bool
|
||||
checkComponents []string
|
||||
)
|
||||
type checkFlags struct {
|
||||
pre bool
|
||||
components []string
|
||||
}
|
||||
|
||||
type kubectlVersion struct {
|
||||
ClientVersion *apimachineryversion.Info `json:"clientVersion"`
|
||||
}
|
||||
|
||||
var checkArgs checkFlags
|
||||
|
||||
func init() {
|
||||
checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false,
|
||||
checkCmd.Flags().BoolVarP(&checkArgs.pre, "pre", "", false,
|
||||
"only run pre-installation checks")
|
||||
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaults.Components,
|
||||
checkCmd.Flags().StringSliceVar(&checkArgs.components, "components", rootArgs.defaults.Components,
|
||||
"list of components, accepts comma-separated values")
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
}
|
||||
|
||||
func runCheckCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
logger.Actionf("checking prerequisites")
|
||||
@@ -76,7 +78,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
if checkPre {
|
||||
if checkArgs.pre {
|
||||
if checkFailed {
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -103,7 +105,7 @@ func kubectlCheck(ctx context.Context, version string) bool {
|
||||
}
|
||||
|
||||
kubectlArgs := []string{"version", "--client", "--output", "json"}
|
||||
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...)
|
||||
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
|
||||
if err != nil {
|
||||
logger.Failuref("kubectl version can't be determined")
|
||||
return false
|
||||
@@ -132,7 +134,7 @@ func kubectlCheck(ctx context.Context, version string) bool {
|
||||
}
|
||||
|
||||
func kubernetesCheck(version string) bool {
|
||||
cfg, err := utils.KubeConfig(kubeconfig, kubecontext)
|
||||
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
||||
return false
|
||||
@@ -167,20 +169,20 @@ func kubernetesCheck(version string) bool {
|
||||
}
|
||||
|
||||
func componentsCheck() bool {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
ok := true
|
||||
for _, deployment := range checkComponents {
|
||||
kubectlArgs := []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
||||
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
for _, deployment := range checkArgs.components {
|
||||
kubectlArgs := []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
|
||||
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
|
||||
ok = false
|
||||
} else {
|
||||
logger.Successf("%s is healthy", deployment)
|
||||
}
|
||||
kubectlArgs = []string{"-n", namespace, "get", "deployment", deployment, "-o", "jsonpath=\"{..image}\""}
|
||||
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...); err == nil {
|
||||
kubectlArgs = []string{"-n", rootArgs.namespace, "get", "deployment", deployment, "-o", "jsonpath=\"{..image}\""}
|
||||
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err == nil {
|
||||
logger.Actionf(strings.TrimPrefix(strings.TrimSuffix(output, "\""), "\""))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,16 +38,18 @@ var createCmd = &cobra.Command{
|
||||
Long: "The create sub-commands generate sources and resources.",
|
||||
}
|
||||
|
||||
var (
|
||||
type createFlags struct {
|
||||
interval time.Duration
|
||||
export bool
|
||||
labels []string
|
||||
)
|
||||
}
|
||||
|
||||
var createArgs createFlags
|
||||
|
||||
func init() {
|
||||
createCmd.PersistentFlags().DurationVarP(&interval, "interval", "", time.Minute, "source sync interval")
|
||||
createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in YAML format to stdout")
|
||||
createCmd.PersistentFlags().StringSliceVar(&labels, "label", nil,
|
||||
createCmd.PersistentFlags().DurationVarP(&createArgs.interval, "interval", "", time.Minute, "source sync interval")
|
||||
createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout")
|
||||
createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil,
|
||||
"set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)")
|
||||
rootCmd.AddCommand(createCmd)
|
||||
}
|
||||
@@ -76,7 +78,7 @@ func (names apiType) upsert(ctx context.Context, kubeClient client.Client, objec
|
||||
Name: object.GetName(),
|
||||
}
|
||||
|
||||
op, err := controllerutil.CreateOrUpdate(ctx, kubeClient, object.asRuntimeObject(), mutate)
|
||||
op, err := controllerutil.CreateOrUpdate(ctx, kubeClient, object.asClientObject(), mutate)
|
||||
if err != nil {
|
||||
return nsname, err
|
||||
}
|
||||
@@ -99,10 +101,10 @@ type upsertWaitable interface {
|
||||
// resource, then waiting for it to reconcile. See the note on
|
||||
// `upsert` for how to work with the `mutate` argument.
|
||||
func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext) // NB globals
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext) // NB globals
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,7 +118,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for %s reconciliation", names.kind)
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isReady(ctx, kubeClient, namespacedName, object)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,7 +128,7 @@ func (names apiType) upsertAndWait(object upsertWaitable, mutate func() error) e
|
||||
|
||||
func parseLabels() (map[string]string, error) {
|
||||
result := make(map[string]string)
|
||||
for _, label := range labels {
|
||||
for _, label := range createArgs.labels {
|
||||
// validate key value pair
|
||||
parts := strings.Split(label, "=")
|
||||
if len(parts) != 2 {
|
||||
|
||||
@@ -20,11 +20,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -33,6 +29,9 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
var createAlertCmd = &cobra.Command{
|
||||
@@ -49,16 +48,18 @@ var createAlertCmd = &cobra.Command{
|
||||
RunE: createAlertCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
aProviderRef string
|
||||
aEventSeverity string
|
||||
aEventSources []string
|
||||
)
|
||||
type alertFlags struct {
|
||||
providerRef string
|
||||
eventSeverity string
|
||||
eventSources []string
|
||||
}
|
||||
|
||||
var alertArgs alertFlags
|
||||
|
||||
func init() {
|
||||
createAlertCmd.Flags().StringVar(&aProviderRef, "provider-ref", "", "reference to provider")
|
||||
createAlertCmd.Flags().StringVar(&aEventSeverity, "event-severity", "", "severity of events to send alerts for")
|
||||
createAlertCmd.Flags().StringArrayVar(&aEventSources, "event-source", []string{}, "sources that should generate alerts (<kind>/<name>)")
|
||||
createAlertCmd.Flags().StringVar(&alertArgs.providerRef, "provider-ref", "", "reference to provider")
|
||||
createAlertCmd.Flags().StringVar(&alertArgs.eventSeverity, "event-severity", "", "severity of events to send alerts for")
|
||||
createAlertCmd.Flags().StringArrayVar(&alertArgs.eventSources, "event-source", []string{}, "sources that should generate alerts (<kind>/<name>)")
|
||||
createCmd.AddCommand(createAlertCmd)
|
||||
}
|
||||
|
||||
@@ -68,12 +69,12 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if aProviderRef == "" {
|
||||
if alertArgs.providerRef == "" {
|
||||
return fmt.Errorf("provider ref is required")
|
||||
}
|
||||
|
||||
eventSources := []notificationv1.CrossNamespaceObjectReference{}
|
||||
for _, eventSource := range aEventSources {
|
||||
for _, eventSource := range alertArgs.eventSources {
|
||||
kind, name := utils.ParseObjectKindName(eventSource)
|
||||
if kind == "" {
|
||||
return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", eventSource)
|
||||
@@ -94,34 +95,34 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !export {
|
||||
if !createArgs.export {
|
||||
logger.Generatef("generating Alert")
|
||||
}
|
||||
|
||||
alert := notificationv1.Alert{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: notificationv1.AlertSpec{
|
||||
ProviderRef: corev1.LocalObjectReference{
|
||||
Name: aProviderRef,
|
||||
ProviderRef: meta.LocalObjectReference{
|
||||
Name: alertArgs.providerRef,
|
||||
},
|
||||
EventSeverity: aEventSeverity,
|
||||
EventSeverity: alertArgs.eventSeverity,
|
||||
EventSources: eventSources,
|
||||
Suspend: false,
|
||||
},
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportAlert(alert)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -133,7 +134,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for Alert reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isAlertReady(ctx, kubeClient, namespacedName, &alert)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -29,9 +28,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
var createAlertProviderCmd = &cobra.Command{
|
||||
@@ -54,20 +54,22 @@ var createAlertProviderCmd = &cobra.Command{
|
||||
RunE: createAlertProviderCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
apType string
|
||||
apChannel string
|
||||
apUsername string
|
||||
apAddress string
|
||||
apSecretRef string
|
||||
)
|
||||
type alertProviderFlags struct {
|
||||
alertType string
|
||||
channel string
|
||||
username string
|
||||
address string
|
||||
secretRef string
|
||||
}
|
||||
|
||||
var alertProviderArgs alertProviderFlags
|
||||
|
||||
func init() {
|
||||
createAlertProviderCmd.Flags().StringVar(&apType, "type", "", "type of provider")
|
||||
createAlertProviderCmd.Flags().StringVar(&apChannel, "channel", "", "channel to send messages to in the case of a chat provider")
|
||||
createAlertProviderCmd.Flags().StringVar(&apUsername, "username", "", "bot username used by the provider")
|
||||
createAlertProviderCmd.Flags().StringVar(&apAddress, "address", "", "path to either the git repository, chat provider or webhook")
|
||||
createAlertProviderCmd.Flags().StringVar(&apSecretRef, "secret-ref", "", "name of secret containing authentication token")
|
||||
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.alertType, "type", "", "type of provider")
|
||||
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.channel, "channel", "", "channel to send messages to in the case of a chat provider")
|
||||
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.username, "username", "", "bot username used by the provider")
|
||||
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.address, "address", "", "path to either the git repository, chat provider or webhook")
|
||||
createAlertProviderCmd.Flags().StringVar(&alertProviderArgs.secretRef, "secret-ref", "", "name of secret containing authentication token")
|
||||
createCmd.AddCommand(createAlertProviderCmd)
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if apType == "" {
|
||||
if alertProviderArgs.alertType == "" {
|
||||
return fmt.Errorf("Provider type is required")
|
||||
}
|
||||
|
||||
@@ -86,38 +88,38 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !export {
|
||||
if !createArgs.export {
|
||||
logger.Generatef("generating Provider")
|
||||
}
|
||||
|
||||
provider := notificationv1.Provider{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: notificationv1.ProviderSpec{
|
||||
Type: apType,
|
||||
Channel: apChannel,
|
||||
Username: apUsername,
|
||||
Address: apAddress,
|
||||
Type: alertProviderArgs.alertType,
|
||||
Channel: alertProviderArgs.channel,
|
||||
Username: alertProviderArgs.username,
|
||||
Address: alertProviderArgs.address,
|
||||
},
|
||||
}
|
||||
|
||||
if apSecretRef != "" {
|
||||
provider.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
Name: apSecretRef,
|
||||
if alertProviderArgs.secretRef != "" {
|
||||
provider.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: alertProviderArgs.secretRef,
|
||||
}
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportAlertProvider(provider)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -129,7 +131,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for Provider reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isAlertProviderReady(ctx, kubeClient, namespacedName, &provider)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -98,28 +98,30 @@ var createHelmReleaseCmd = &cobra.Command{
|
||||
RunE: createHelmReleaseCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
hrName string
|
||||
hrSource flags.HelmChartSource
|
||||
hrDependsOn []string
|
||||
hrChart string
|
||||
hrChartVersion string
|
||||
hrTargetNamespace string
|
||||
hrValuesFile string
|
||||
hrValuesFrom flags.HelmReleaseValuesFrom
|
||||
hrSAName string
|
||||
)
|
||||
type helmReleaseFlags struct {
|
||||
name string
|
||||
source flags.HelmChartSource
|
||||
dependsOn []string
|
||||
chart string
|
||||
chartVersion string
|
||||
targetNamespace string
|
||||
valuesFile string
|
||||
valuesFrom flags.HelmReleaseValuesFrom
|
||||
saName string
|
||||
}
|
||||
|
||||
var helmReleaseArgs helmReleaseFlags
|
||||
|
||||
func init() {
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrName, "release-name", "", "name used for the Helm release, defaults to a composition of '[<target-namespace>-]<HelmRelease-name>'")
|
||||
createHelmReleaseCmd.Flags().Var(&hrSource, "source", hrSource.Description())
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrChart, "chart", "", "Helm chart name or path")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrChartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
|
||||
createHelmReleaseCmd.Flags().StringArrayVar(&hrDependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrTargetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrSAName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrValuesFile, "values", "", "local path to the values.yaml file")
|
||||
createHelmReleaseCmd.Flags().Var(&hrValuesFrom, "values-from", hrValuesFrom.Description())
|
||||
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.name, "release-name", "", "name used for the Helm release, defaults to a composition of '[<target-namespace>-]<HelmRelease-name>'")
|
||||
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.source, "source", helmReleaseArgs.source.Description())
|
||||
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chart, "chart", "", "Helm chart name or path")
|
||||
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
|
||||
createHelmReleaseCmd.Flags().StringArrayVar(&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.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
|
||||
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.valuesFile, "values", "", "local path to the values.yaml file")
|
||||
createHelmReleaseCmd.Flags().Var(&helmReleaseArgs.valuesFrom, "values-from", helmReleaseArgs.valuesFrom.Description())
|
||||
createCmd.AddCommand(createHelmReleaseCmd)
|
||||
}
|
||||
|
||||
@@ -129,7 +131,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if hrChart == "" {
|
||||
if helmReleaseArgs.chart == "" {
|
||||
return fmt.Errorf("chart name or path is required")
|
||||
}
|
||||
|
||||
@@ -138,30 +140,30 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !export {
|
||||
if !createArgs.export {
|
||||
logger.Generatef("generating HelmRelease")
|
||||
}
|
||||
|
||||
helmRelease := helmv2.HelmRelease{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: helmv2.HelmReleaseSpec{
|
||||
ReleaseName: hrName,
|
||||
DependsOn: utils.MakeDependsOn(hrDependsOn),
|
||||
ReleaseName: helmReleaseArgs.name,
|
||||
DependsOn: utils.MakeDependsOn(helmReleaseArgs.dependsOn),
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
Duration: createArgs.interval,
|
||||
},
|
||||
TargetNamespace: hrTargetNamespace,
|
||||
TargetNamespace: helmReleaseArgs.targetNamespace,
|
||||
Chart: helmv2.HelmChartTemplate{
|
||||
Spec: helmv2.HelmChartTemplateSpec{
|
||||
Chart: hrChart,
|
||||
Version: hrChartVersion,
|
||||
Chart: helmReleaseArgs.chart,
|
||||
Version: helmReleaseArgs.chartVersion,
|
||||
SourceRef: helmv2.CrossNamespaceObjectReference{
|
||||
Kind: hrSource.Kind,
|
||||
Name: hrSource.Name,
|
||||
Kind: helmReleaseArgs.source.Kind,
|
||||
Name: helmReleaseArgs.source.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -169,39 +171,39 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
},
|
||||
}
|
||||
|
||||
if hrSAName != "" {
|
||||
helmRelease.Spec.ServiceAccountName = hrSAName
|
||||
if helmReleaseArgs.saName != "" {
|
||||
helmRelease.Spec.ServiceAccountName = helmReleaseArgs.saName
|
||||
}
|
||||
|
||||
if hrValuesFile != "" {
|
||||
data, err := ioutil.ReadFile(hrValuesFile)
|
||||
if helmReleaseArgs.valuesFile != "" {
|
||||
data, err := ioutil.ReadFile(helmReleaseArgs.valuesFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading values from %s failed: %w", hrValuesFile, err)
|
||||
return fmt.Errorf("reading values from %s failed: %w", helmReleaseArgs.valuesFile, err)
|
||||
}
|
||||
|
||||
json, err := yaml.YAMLToJSON(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting values to JSON from %s failed: %w", hrValuesFile, err)
|
||||
return fmt.Errorf("converting values to JSON from %s failed: %w", helmReleaseArgs.valuesFile, err)
|
||||
}
|
||||
|
||||
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: json}
|
||||
}
|
||||
|
||||
if hrValuesFrom.String() != "" {
|
||||
if helmReleaseArgs.valuesFrom.String() != "" {
|
||||
helmRelease.Spec.ValuesFrom = []helmv2.ValuesReference{{
|
||||
Kind: hrValuesFrom.Kind,
|
||||
Name: hrValuesFrom.Name,
|
||||
Kind: helmReleaseArgs.valuesFrom.Kind,
|
||||
Name: helmReleaseArgs.valuesFrom.Name,
|
||||
}}
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportHelmRelease(helmRelease)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -213,7 +215,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for HelmRelease reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isHelmReleaseReady(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -38,8 +39,9 @@ the status of the object.`,
|
||||
RunE: createImagePolicyRun}
|
||||
|
||||
type imagePolicyFlags struct {
|
||||
imageRef string
|
||||
semver string
|
||||
imageRef string
|
||||
semver string
|
||||
filterRegex string
|
||||
}
|
||||
|
||||
var imagePolicyArgs = imagePolicyFlags{}
|
||||
@@ -48,6 +50,7 @@ func init() {
|
||||
flags := createImagePolicyCmd.Flags()
|
||||
flags.StringVar(&imagePolicyArgs.imageRef, "image-ref", "", "the name of an image repository object")
|
||||
flags.StringVar(&imagePolicyArgs.semver, "semver", "", "a semver range to apply to tags; e.g., '1.x'")
|
||||
flags.StringVar(&imagePolicyArgs.filterRegex, "filter-regex", "", " regular expression pattern used to filter the image tags")
|
||||
|
||||
createImageCmd.AddCommand(createImagePolicyCmd)
|
||||
}
|
||||
@@ -76,11 +79,11 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
|
||||
var policy = imagev1.ImagePolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: objectName,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: imagev1.ImagePolicySpec{
|
||||
ImageRepositoryRef: corev1.LocalObjectReference{
|
||||
ImageRepositoryRef: meta.LocalObjectReference{
|
||||
Name: imagePolicyArgs.imageRef,
|
||||
},
|
||||
},
|
||||
@@ -95,7 +98,13 @@ func createImagePolicyRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("a policy must be provided with --semver")
|
||||
}
|
||||
|
||||
if export {
|
||||
if imagePolicyArgs.filterRegex != "" {
|
||||
policy.Spec.FilterTags = &imagev1.TagFilter{
|
||||
Pattern: imagePolicyArgs.filterRegex,
|
||||
}
|
||||
}
|
||||
|
||||
if createArgs.export {
|
||||
return printExport(exportImagePolicy(&policy))
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@ import (
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -77,24 +78,24 @@ func createImageRepositoryRun(cmd *cobra.Command, args []string) error {
|
||||
var repo = imagev1.ImageRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: objectName,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: imagev1.ImageRepositorySpec{
|
||||
Image: imageRepoArgs.image,
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Interval: metav1.Duration{Duration: createArgs.interval},
|
||||
},
|
||||
}
|
||||
if imageRepoArgs.timeout != 0 {
|
||||
repo.Spec.Timeout = &metav1.Duration{Duration: imageRepoArgs.timeout}
|
||||
}
|
||||
if imageRepoArgs.secretRef != "" {
|
||||
repo.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
repo.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: imageRepoArgs.secretRef,
|
||||
}
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return printExport(exportImageRepository(&repo))
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -50,7 +51,7 @@ var imageUpdateArgs = imageUpdateFlags{}
|
||||
func init() {
|
||||
flags := createImageUpdateCmd.Flags()
|
||||
flags.StringVar(&imageUpdateArgs.gitRepoRef, "git-repo-ref", "", "the name of a GitRepository resource with details of the upstream git repository")
|
||||
flags.StringVar(&imageUpdateArgs.branch, "branch", "", "the branch to push commits to")
|
||||
flags.StringVar(&imageUpdateArgs.branch, "branch", "", "the branch to checkout and push commits to")
|
||||
flags.StringVar(&imageUpdateArgs.commitTemplate, "commit-template", "", "a template for commit messages")
|
||||
flags.StringVar(&imageUpdateArgs.authorName, "author-name", "", "the name to use for commit author")
|
||||
flags.StringVar(&imageUpdateArgs.authorEmail, "author-email", "", "the email to use for commit author")
|
||||
@@ -68,6 +69,10 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("a reference to a GitRepository is required (--git-repo-ref)")
|
||||
}
|
||||
|
||||
if imageUpdateArgs.branch == "" {
|
||||
return fmt.Errorf("the Git repoistory branch is required (--branch)")
|
||||
}
|
||||
|
||||
labels, err := parseLabels()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -76,20 +81,17 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
|
||||
var update = autov1.ImageUpdateAutomation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: objectName,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: autov1.ImageUpdateAutomationSpec{
|
||||
Checkout: autov1.GitCheckoutSpec{
|
||||
GitRepositoryRef: corev1.LocalObjectReference{
|
||||
GitRepositoryRef: meta.LocalObjectReference{
|
||||
Name: imageUpdateArgs.gitRepoRef,
|
||||
},
|
||||
Branch: imageUpdateArgs.branch,
|
||||
},
|
||||
Interval: metav1.Duration{Duration: interval},
|
||||
Update: autov1.UpdateStrategy{
|
||||
Setters: &autov1.SettersStrategy{},
|
||||
},
|
||||
Interval: metav1.Duration{Duration: createArgs.interval},
|
||||
Commit: autov1.CommitSpec{
|
||||
AuthorName: imageUpdateArgs.authorName,
|
||||
AuthorEmail: imageUpdateArgs.authorEmail,
|
||||
@@ -98,7 +100,7 @@ func createImageUpdateRun(cmd *cobra.Command, args []string) error {
|
||||
},
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return printExport(exportImageUpdate(&update))
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -31,11 +30,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/flags"
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/flags"
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
var createKsCmd = &cobra.Command{
|
||||
@@ -72,53 +72,61 @@ var createKsCmd = &cobra.Command{
|
||||
RunE: createKsCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
ksSource flags.KustomizationSource
|
||||
ksPath flags.SafeRelativePath = "./"
|
||||
ksPrune bool
|
||||
ksDependsOn []string
|
||||
ksValidation string
|
||||
ksHealthCheck []string
|
||||
ksHealthTimeout time.Duration
|
||||
ksSAName string
|
||||
ksDecryptionProvider flags.DecryptionProvider
|
||||
ksDecryptionSecret string
|
||||
ksTargetNamespace string
|
||||
)
|
||||
type kustomizationFlags struct {
|
||||
source flags.KustomizationSource
|
||||
path flags.SafeRelativePath
|
||||
prune bool
|
||||
dependsOn []string
|
||||
validation string
|
||||
healthCheck []string
|
||||
healthTimeout time.Duration
|
||||
saName string
|
||||
decryptionProvider flags.DecryptionProvider
|
||||
decryptionSecret string
|
||||
targetNamespace string
|
||||
}
|
||||
|
||||
var kustomizationArgs = NewKustomizationFlags()
|
||||
|
||||
func init() {
|
||||
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
|
||||
createKsCmd.Flags().Var(&ksPath, "path", "path to the directory containing a kustomization.yaml file")
|
||||
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection")
|
||||
createKsCmd.Flags().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
||||
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
||||
createKsCmd.Flags().StringVar(&ksValidation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
|
||||
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied, supported formats '<name>' and '<namespace>/<name>'")
|
||||
createKsCmd.Flags().StringVar(&ksSAName, "service-account", "", "the name of the service account to impersonate when reconciling this Kustomization")
|
||||
createKsCmd.Flags().Var(&ksDecryptionProvider, "decryption-provider", ksDecryptionProvider.Description())
|
||||
createKsCmd.Flags().StringVar(&ksDecryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
|
||||
createKsCmd.Flags().StringVar(&ksTargetNamespace, "target-namespace", "", "overrides the namespace of all Kustomization objects reconciled by this Kustomization")
|
||||
createKsCmd.Flags().Var(&kustomizationArgs.source, "source", kustomizationArgs.source.Description())
|
||||
createKsCmd.Flags().Var(&kustomizationArgs.path, "path", "path to the directory containing a kustomization.yaml file")
|
||||
createKsCmd.Flags().BoolVar(&kustomizationArgs.prune, "prune", false, "enable garbage collection")
|
||||
createKsCmd.Flags().StringArrayVar(&kustomizationArgs.healthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
||||
createKsCmd.Flags().DurationVar(&kustomizationArgs.healthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
||||
createKsCmd.Flags().StringVar(&kustomizationArgs.validation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
|
||||
createKsCmd.Flags().StringArrayVar(&kustomizationArgs.dependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied, supported formats '<name>' and '<namespace>/<name>'")
|
||||
createKsCmd.Flags().StringVar(&kustomizationArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this Kustomization")
|
||||
createKsCmd.Flags().Var(&kustomizationArgs.decryptionProvider, "decryption-provider", kustomizationArgs.decryptionProvider.Description())
|
||||
createKsCmd.Flags().StringVar(&kustomizationArgs.decryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
|
||||
createKsCmd.Flags().StringVar(&kustomizationArgs.targetNamespace, "target-namespace", "", "overrides the namespace of all Kustomization objects reconciled by this Kustomization")
|
||||
createCmd.AddCommand(createKsCmd)
|
||||
}
|
||||
|
||||
func NewKustomizationFlags() kustomizationFlags {
|
||||
return kustomizationFlags{
|
||||
path: "./",
|
||||
}
|
||||
}
|
||||
|
||||
func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("Kustomization name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if ksPath == "" {
|
||||
if kustomizationArgs.path == "" {
|
||||
return fmt.Errorf("path is required")
|
||||
}
|
||||
if !strings.HasPrefix(ksPath.String(), "./") {
|
||||
if !strings.HasPrefix(kustomizationArgs.path.String(), "./") {
|
||||
return fmt.Errorf("path must begin with ./")
|
||||
}
|
||||
|
||||
if !export {
|
||||
if !createArgs.export {
|
||||
logger.Generatef("generating Kustomization")
|
||||
}
|
||||
|
||||
ksLabels, err := parseLabels()
|
||||
kslabels, err := parseLabels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,29 +134,29 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
kustomization := kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: ksLabels,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: kslabels,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
DependsOn: utils.MakeDependsOn(ksDependsOn),
|
||||
DependsOn: utils.MakeDependsOn(kustomizationArgs.dependsOn),
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
Duration: createArgs.interval,
|
||||
},
|
||||
Path: ksPath.String(),
|
||||
Prune: ksPrune,
|
||||
Path: kustomizationArgs.path.String(),
|
||||
Prune: kustomizationArgs.prune,
|
||||
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||
Kind: ksSource.Kind,
|
||||
Name: ksSource.Name,
|
||||
Kind: kustomizationArgs.source.Kind,
|
||||
Name: kustomizationArgs.source.Name,
|
||||
},
|
||||
Suspend: false,
|
||||
Validation: ksValidation,
|
||||
TargetNamespace: ksTargetNamespace,
|
||||
Validation: kustomizationArgs.validation,
|
||||
TargetNamespace: kustomizationArgs.targetNamespace,
|
||||
},
|
||||
}
|
||||
|
||||
if len(ksHealthCheck) > 0 {
|
||||
healthChecks := make([]kustomizev1.CrossNamespaceObjectReference, 0)
|
||||
for _, w := range ksHealthCheck {
|
||||
if len(kustomizationArgs.healthCheck) > 0 {
|
||||
healthChecks := make([]meta.NamespacedObjectKindReference, 0)
|
||||
for _, w := range kustomizationArgs.healthCheck {
|
||||
kindObj := strings.Split(w, "/")
|
||||
if len(kindObj) != 2 {
|
||||
return fmt.Errorf("invalid health check '%s' must be in the format 'kind/name.namespace' %v", w, kindObj)
|
||||
@@ -170,7 +178,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("invalid health check '%s' must be in the format 'kind/name.namespace'", w)
|
||||
}
|
||||
|
||||
check := kustomizev1.CrossNamespaceObjectReference{
|
||||
check := meta.NamespacedObjectKindReference{
|
||||
Kind: kind,
|
||||
Name: nameNs[0],
|
||||
Namespace: nameNs[1],
|
||||
@@ -183,32 +191,32 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
kustomization.Spec.HealthChecks = healthChecks
|
||||
kustomization.Spec.Timeout = &metav1.Duration{
|
||||
Duration: ksHealthTimeout,
|
||||
Duration: kustomizationArgs.healthTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
if ksSAName != "" {
|
||||
kustomization.Spec.ServiceAccountName = ksSAName
|
||||
if kustomizationArgs.saName != "" {
|
||||
kustomization.Spec.ServiceAccountName = kustomizationArgs.saName
|
||||
}
|
||||
|
||||
if ksDecryptionProvider != "" {
|
||||
if kustomizationArgs.decryptionProvider != "" {
|
||||
kustomization.Spec.Decryption = &kustomizev1.Decryption{
|
||||
Provider: ksDecryptionProvider.String(),
|
||||
Provider: kustomizationArgs.decryptionProvider.String(),
|
||||
}
|
||||
|
||||
if ksDecryptionSecret != "" {
|
||||
kustomization.Spec.Decryption.SecretRef = &corev1.LocalObjectReference{Name: ksDecryptionSecret}
|
||||
if kustomizationArgs.decryptionSecret != "" {
|
||||
kustomization.Spec.Decryption.SecretRef = &meta.LocalObjectReference{Name: kustomizationArgs.decryptionSecret}
|
||||
}
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportKs(kustomization)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -220,7 +228,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for Kustomization reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isKustomizationReady(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -29,9 +28,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
var createReceiverCmd = &cobra.Command{
|
||||
@@ -50,18 +50,20 @@ var createReceiverCmd = &cobra.Command{
|
||||
RunE: createReceiverCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
rcvType string
|
||||
rcvSecretRef string
|
||||
rcvEvents []string
|
||||
rcvResources []string
|
||||
)
|
||||
type receiverFlags struct {
|
||||
receiverType string
|
||||
secretRef string
|
||||
events []string
|
||||
resources []string
|
||||
}
|
||||
|
||||
var receiverArgs receiverFlags
|
||||
|
||||
func init() {
|
||||
createReceiverCmd.Flags().StringVar(&rcvType, "type", "", "")
|
||||
createReceiverCmd.Flags().StringVar(&rcvSecretRef, "secret-ref", "", "")
|
||||
createReceiverCmd.Flags().StringArrayVar(&rcvEvents, "event", []string{}, "")
|
||||
createReceiverCmd.Flags().StringArrayVar(&rcvResources, "resource", []string{}, "")
|
||||
createReceiverCmd.Flags().StringVar(&receiverArgs.receiverType, "type", "", "")
|
||||
createReceiverCmd.Flags().StringVar(&receiverArgs.secretRef, "secret-ref", "", "")
|
||||
createReceiverCmd.Flags().StringArrayVar(&receiverArgs.events, "event", []string{}, "")
|
||||
createReceiverCmd.Flags().StringArrayVar(&receiverArgs.resources, "resource", []string{}, "")
|
||||
createCmd.AddCommand(createReceiverCmd)
|
||||
}
|
||||
|
||||
@@ -71,16 +73,16 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if rcvType == "" {
|
||||
if receiverArgs.receiverType == "" {
|
||||
return fmt.Errorf("Receiver type is required")
|
||||
}
|
||||
|
||||
if rcvSecretRef == "" {
|
||||
if receiverArgs.secretRef == "" {
|
||||
return fmt.Errorf("secret ref is required")
|
||||
}
|
||||
|
||||
resources := []notificationv1.CrossNamespaceObjectReference{}
|
||||
for _, resource := range rcvResources {
|
||||
for _, resource := range receiverArgs.resources {
|
||||
kind, name := utils.ParseObjectKindName(resource)
|
||||
if kind == "" {
|
||||
return fmt.Errorf("invalid event source '%s', must be in format <kind>/<name>", resource)
|
||||
@@ -101,35 +103,35 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !export {
|
||||
if !createArgs.export {
|
||||
logger.Generatef("generating Receiver")
|
||||
}
|
||||
|
||||
receiver := notificationv1.Receiver{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: notificationv1.ReceiverSpec{
|
||||
Type: rcvType,
|
||||
Events: rcvEvents,
|
||||
Type: receiverArgs.receiverType,
|
||||
Events: receiverArgs.events,
|
||||
Resources: resources,
|
||||
SecretRef: corev1.LocalObjectReference{
|
||||
Name: rcvSecretRef,
|
||||
SecretRef: meta.LocalObjectReference{
|
||||
Name: receiverArgs.secretRef,
|
||||
},
|
||||
Suspend: false,
|
||||
},
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportReceiver(receiver)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -141,7 +143,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for Receiver reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isReceiverReady(ctx, kubeClient, namespacedName, &receiver)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -39,6 +39,23 @@ func init() {
|
||||
createCmd.AddCommand(createSecretCmd)
|
||||
}
|
||||
|
||||
func makeSecret(name string) (corev1.Secret, error) {
|
||||
secretLabels, err := parseLabels()
|
||||
if err != nil {
|
||||
return corev1.Secret{}, err
|
||||
}
|
||||
|
||||
return corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: secretLabels,
|
||||
},
|
||||
StringData: map[string]string{},
|
||||
Data: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func upsertSecret(ctx context.Context, kubeClient client.Client, secret corev1.Secret) error {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: secret.GetNamespace(),
|
||||
|
||||
@@ -24,8 +24,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/flags"
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
@@ -71,60 +69,61 @@ For Git over HTTP/S, the provided basic authentication credentials are stored in
|
||||
RunE: createSecretGitCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
secretGitURL string
|
||||
secretGitUsername string
|
||||
secretGitPassword string
|
||||
secretGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
|
||||
secretGitRSABits flags.RSAKeyBits = 2048
|
||||
secretGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
|
||||
)
|
||||
type secretGitFlags struct {
|
||||
url string
|
||||
username string
|
||||
password string
|
||||
keyAlgorithm flags.PublicKeyAlgorithm
|
||||
rsaBits flags.RSAKeyBits
|
||||
ecdsaCurve flags.ECDSACurve
|
||||
}
|
||||
|
||||
var secretGitArgs = NewSecretGitFlags()
|
||||
|
||||
func init() {
|
||||
createSecretGitCmd.Flags().StringVar(&secretGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
|
||||
createSecretGitCmd.Flags().StringVarP(&secretGitUsername, "username", "u", "", "basic authentication username")
|
||||
createSecretGitCmd.Flags().StringVarP(&secretGitPassword, "password", "p", "", "basic authentication password")
|
||||
createSecretGitCmd.Flags().Var(&secretGitKeyAlgorithm, "ssh-key-algorithm", secretGitKeyAlgorithm.Description())
|
||||
createSecretGitCmd.Flags().Var(&secretGitRSABits, "ssh-rsa-bits", secretGitRSABits.Description())
|
||||
createSecretGitCmd.Flags().Var(&secretGitECDSACurve, "ssh-ecdsa-curve", secretGitECDSACurve.Description())
|
||||
createSecretGitCmd.Flags().StringVar(&secretGitArgs.url, "url", "", "git address, e.g. ssh://git@host/org/repository")
|
||||
createSecretGitCmd.Flags().StringVarP(&secretGitArgs.username, "username", "u", "", "basic authentication username")
|
||||
createSecretGitCmd.Flags().StringVarP(&secretGitArgs.password, "password", "p", "", "basic authentication password")
|
||||
createSecretGitCmd.Flags().Var(&secretGitArgs.keyAlgorithm, "ssh-key-algorithm", secretGitArgs.keyAlgorithm.Description())
|
||||
createSecretGitCmd.Flags().Var(&secretGitArgs.rsaBits, "ssh-rsa-bits", secretGitArgs.rsaBits.Description())
|
||||
createSecretGitCmd.Flags().Var(&secretGitArgs.ecdsaCurve, "ssh-ecdsa-curve", secretGitArgs.ecdsaCurve.Description())
|
||||
|
||||
createSecretCmd.AddCommand(createSecretGitCmd)
|
||||
}
|
||||
|
||||
func NewSecretGitFlags() secretGitFlags {
|
||||
return secretGitFlags{
|
||||
keyAlgorithm: "rsa",
|
||||
rsaBits: 2048,
|
||||
ecdsaCurve: flags.ECDSACurve{Curve: elliptic.P384()},
|
||||
}
|
||||
}
|
||||
|
||||
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("secret name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if secretGitURL == "" {
|
||||
return fmt.Errorf("url is required")
|
||||
}
|
||||
|
||||
u, err := url.Parse(secretGitURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
|
||||
secretLabels, err := parseLabels()
|
||||
secret, err := makeSecret(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: secretLabels,
|
||||
},
|
||||
if secretGitArgs.url == "" {
|
||||
return fmt.Errorf("url is required")
|
||||
}
|
||||
|
||||
u, err := url.Parse(secretGitArgs.url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
switch u.Scheme {
|
||||
case "ssh":
|
||||
pair, err := generateKeyPair(ctx, secretGitKeyAlgorithm, secretGitRSABits, secretGitECDSACurve)
|
||||
pair, err := generateKeyPair(ctx, secretGitArgs.keyAlgorithm, secretGitArgs.rsaBits, secretGitArgs.ecdsaCurve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -134,34 +133,34 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
secret.Data = map[string][]byte{
|
||||
"identity": pair.PrivateKey,
|
||||
"identity.pub": pair.PublicKey,
|
||||
"known_hosts": hostKey,
|
||||
secret.StringData = map[string]string{
|
||||
"identity": string(pair.PrivateKey),
|
||||
"identity.pub": string(pair.PublicKey),
|
||||
"known_hosts": string(hostKey),
|
||||
}
|
||||
|
||||
if !export {
|
||||
if !createArgs.export {
|
||||
logger.Generatef("deploy key: %s", string(pair.PublicKey))
|
||||
}
|
||||
case "http", "https":
|
||||
if secretGitUsername == "" || secretGitPassword == "" {
|
||||
if secretGitArgs.username == "" || secretGitArgs.password == "" {
|
||||
return fmt.Errorf("for Git over HTTP/S the username and password are required")
|
||||
}
|
||||
|
||||
// TODO: add cert data when it's implemented in source-controller
|
||||
secret.Data = map[string][]byte{
|
||||
"username": []byte(secretGitUsername),
|
||||
"password": []byte(secretGitPassword),
|
||||
secret.StringData = map[string]string{
|
||||
"username": secretGitArgs.username,
|
||||
"password": secretGitArgs.password,
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportSecret(secret)
|
||||
}
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -169,7 +168,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Actionf("secret '%s' created in '%s' namespace", name, namespace)
|
||||
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -19,11 +19,8 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
@@ -55,21 +52,18 @@ The create secret helm command generates a Kubernetes secret with basic authenti
|
||||
RunE: createSecretHelmCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
secretHelmUsername string
|
||||
secretHelmPassword string
|
||||
secretHelmCertFile string
|
||||
secretHelmKeyFile string
|
||||
secretHelmCAFile string
|
||||
)
|
||||
type secretHelmFlags struct {
|
||||
username string
|
||||
password string
|
||||
secretTLSFlags
|
||||
}
|
||||
|
||||
var secretHelmArgs secretHelmFlags
|
||||
|
||||
func init() {
|
||||
createSecretHelmCmd.Flags().StringVarP(&secretHelmUsername, "username", "u", "", "basic authentication username")
|
||||
createSecretHelmCmd.Flags().StringVarP(&secretHelmPassword, "password", "p", "", "basic authentication password")
|
||||
createSecretHelmCmd.Flags().StringVar(&secretHelmCertFile, "cert-file", "", "TLS authentication cert file path")
|
||||
createSecretHelmCmd.Flags().StringVar(&secretHelmKeyFile, "key-file", "", "TLS authentication key file path")
|
||||
createSecretHelmCmd.Flags().StringVar(&secretHelmCAFile, "ca-file", "", "TLS authentication CA file path")
|
||||
|
||||
createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.username, "username", "u", "", "basic authentication username")
|
||||
createSecretHelmCmd.Flags().StringVarP(&secretHelmArgs.password, "password", "p", "", "basic authentication password")
|
||||
initSecretTLSFlags(createSecretHelmCmd.Flags(), &secretHelmArgs.secretTLSFlags)
|
||||
createSecretCmd.AddCommand(createSecretHelmCmd)
|
||||
}
|
||||
|
||||
@@ -78,56 +72,28 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("secret name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
secretLabels, err := parseLabels()
|
||||
secret, err := makeSecret(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: secretLabels,
|
||||
},
|
||||
StringData: map[string]string{},
|
||||
if secretHelmArgs.username != "" && secretHelmArgs.password != "" {
|
||||
secret.StringData["username"] = secretHelmArgs.username
|
||||
secret.StringData["password"] = secretHelmArgs.password
|
||||
}
|
||||
|
||||
if secretHelmUsername != "" && secretHelmPassword != "" {
|
||||
secret.StringData["username"] = secretHelmUsername
|
||||
secret.StringData["password"] = secretHelmPassword
|
||||
if err = populateSecretTLS(&secret, secretHelmArgs.secretTLSFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if secretHelmCertFile != "" && secretHelmKeyFile != "" {
|
||||
cert, err := ioutil.ReadFile(secretHelmCertFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository cert file '%s': %w", secretHelmCertFile, err)
|
||||
}
|
||||
secret.StringData["certFile"] = string(cert)
|
||||
|
||||
key, err := ioutil.ReadFile(secretHelmKeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository key file '%s': %w", secretHelmKeyFile, err)
|
||||
}
|
||||
secret.StringData["keyFile"] = string(key)
|
||||
}
|
||||
|
||||
if secretHelmCAFile != "" {
|
||||
ca, err := ioutil.ReadFile(secretHelmCAFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository CA file '%s': %w", secretHelmCAFile, err)
|
||||
}
|
||||
secret.StringData["caFile"] = string(ca)
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportSecret(secret)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -135,7 +101,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Actionf("secret '%s' created in '%s' namespace", name, namespace)
|
||||
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
128
cmd/flux/create_secret_tls.go
Normal file
128
cmd/flux/create_secret_tls.go
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright 2020, 2021 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
var createSecretTLSCmd = &cobra.Command{
|
||||
Use: "tls [name]",
|
||||
Short: "Create or update a Kubernetes secret with TLS certificates",
|
||||
Long: `
|
||||
The create secret tls command generates a Kubernetes secret with certificates for use with TLS.`,
|
||||
Example: `
|
||||
# Create a TLS secret on disk and encrypt it with Mozilla SOPS.
|
||||
# Files are expected to be PEM-encoded.
|
||||
flux create secret tls certs \
|
||||
--namespace=my-namespace \
|
||||
--cert-file=./client.crt \
|
||||
--key-file=./client.key \
|
||||
--export > certs.yaml
|
||||
|
||||
sops --encrypt --encrypted-regex '^(data|stringData)$' \
|
||||
--in-place certs.yaml
|
||||
`,
|
||||
RunE: createSecretTLSCmdRun,
|
||||
}
|
||||
|
||||
type secretTLSFlags struct {
|
||||
certFile string
|
||||
keyFile string
|
||||
caFile string
|
||||
}
|
||||
|
||||
var secretTLSArgs secretTLSFlags
|
||||
|
||||
func initSecretTLSFlags(flags *pflag.FlagSet, args *secretTLSFlags) {
|
||||
flags.StringVar(&args.certFile, "cert-file", "", "TLS authentication cert file path")
|
||||
flags.StringVar(&args.keyFile, "key-file", "", "TLS authentication key file path")
|
||||
flags.StringVar(&args.caFile, "ca-file", "", "TLS authentication CA file path")
|
||||
}
|
||||
|
||||
func init() {
|
||||
flags := createSecretTLSCmd.Flags()
|
||||
initSecretTLSFlags(flags, &secretTLSArgs)
|
||||
createSecretCmd.AddCommand(createSecretTLSCmd)
|
||||
}
|
||||
|
||||
func populateSecretTLS(secret *corev1.Secret, args secretTLSFlags) error {
|
||||
if args.certFile != "" && args.keyFile != "" {
|
||||
cert, err := ioutil.ReadFile(args.certFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository cert file '%s': %w", args.certFile, err)
|
||||
}
|
||||
secret.StringData["certFile"] = string(cert)
|
||||
|
||||
key, err := ioutil.ReadFile(args.keyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository key file '%s': %w", args.keyFile, err)
|
||||
}
|
||||
secret.StringData["keyFile"] = string(key)
|
||||
}
|
||||
|
||||
if args.caFile != "" {
|
||||
ca, err := ioutil.ReadFile(args.caFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository CA file '%s': %w", args.caFile, err)
|
||||
}
|
||||
secret.StringData["caFile"] = string(ca)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("secret name is required")
|
||||
}
|
||||
name := args[0]
|
||||
secret, err := makeSecret(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = populateSecretTLS(&secret, secretTLSArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if createArgs.export {
|
||||
return exportSecret(secret)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Actionf("secret '%s' created in '%s' namespace", name, rootArgs.namespace)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -30,9 +30,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/flags"
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var createSourceBucketCmd = &cobra.Command{
|
||||
@@ -61,41 +63,49 @@ For Buckets with static authentication, the credentials are stored in a Kubernet
|
||||
RunE: createSourceBucketCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
sourceBucketName string
|
||||
sourceBucketProvider = flags.SourceBucketProvider(sourcev1.GenericBucketProvider)
|
||||
sourceBucketEndpoint string
|
||||
sourceBucketAccessKey string
|
||||
sourceBucketSecretKey string
|
||||
sourceBucketRegion string
|
||||
sourceBucketInsecure bool
|
||||
sourceBucketSecretRef string
|
||||
)
|
||||
type sourceBucketFlags struct {
|
||||
name string
|
||||
provider flags.SourceBucketProvider
|
||||
endpoint string
|
||||
accessKey string
|
||||
secretKey string
|
||||
region string
|
||||
insecure bool
|
||||
secretRef string
|
||||
}
|
||||
|
||||
var sourceBucketArgs = NewSourceBucketFlags()
|
||||
|
||||
func init() {
|
||||
createSourceBucketCmd.Flags().Var(&sourceBucketProvider, "provider", sourceBucketProvider.Description())
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketName, "bucket-name", "", "the bucket name")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketEndpoint, "endpoint", "", "the bucket endpoint address")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketAccessKey, "access-key", "", "the bucket access key")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketSecretKey, "secret-key", "", "the bucket secret key")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketRegion, "region", "", "the bucket region")
|
||||
createSourceBucketCmd.Flags().BoolVar(&sourceBucketInsecure, "insecure", false, "for when connecting to a non-TLS S3 HTTP endpoint")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketSecretRef, "secret-ref", "", "the name of an existing secret containing credentials")
|
||||
createSourceBucketCmd.Flags().Var(&sourceBucketArgs.provider, "provider", sourceBucketArgs.provider.Description())
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.name, "bucket-name", "", "the bucket name")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.endpoint, "endpoint", "", "the bucket endpoint address")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.accessKey, "access-key", "", "the bucket access key")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.secretKey, "secret-key", "", "the bucket secret key")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.region, "region", "", "the bucket region")
|
||||
createSourceBucketCmd.Flags().BoolVar(&sourceBucketArgs.insecure, "insecure", false, "for when connecting to a non-TLS S3 HTTP endpoint")
|
||||
createSourceBucketCmd.Flags().StringVar(&sourceBucketArgs.secretRef, "secret-ref", "", "the name of an existing secret containing credentials")
|
||||
|
||||
createSourceCmd.AddCommand(createSourceBucketCmd)
|
||||
}
|
||||
|
||||
func NewSourceBucketFlags() sourceBucketFlags {
|
||||
return sourceBucketFlags{
|
||||
provider: flags.SourceBucketProvider(sourcev1.GenericBucketProvider),
|
||||
}
|
||||
}
|
||||
|
||||
func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("Bucket source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if sourceBucketName == "" {
|
||||
if sourceBucketArgs.name == "" {
|
||||
return fmt.Errorf("bucket-name is required")
|
||||
}
|
||||
|
||||
if sourceBucketEndpoint == "" {
|
||||
if sourceBucketArgs.endpoint == "" {
|
||||
return fmt.Errorf("endpoint is required")
|
||||
}
|
||||
|
||||
@@ -113,55 +123,55 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
bucket := &sourcev1.Bucket{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: sourcev1.BucketSpec{
|
||||
BucketName: sourceBucketName,
|
||||
Provider: sourceBucketProvider.String(),
|
||||
Insecure: sourceBucketInsecure,
|
||||
Endpoint: sourceBucketEndpoint,
|
||||
Region: sourceBucketRegion,
|
||||
BucketName: sourceBucketArgs.name,
|
||||
Provider: sourceBucketArgs.provider.String(),
|
||||
Insecure: sourceBucketArgs.insecure,
|
||||
Endpoint: sourceBucketArgs.endpoint,
|
||||
Region: sourceBucketArgs.region,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
Duration: createArgs.interval,
|
||||
},
|
||||
},
|
||||
}
|
||||
if sourceHelmSecretRef != "" {
|
||||
bucket.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
Name: sourceBucketSecretRef,
|
||||
if sourceHelmArgs.secretRef != "" {
|
||||
bucket.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: sourceBucketArgs.secretRef,
|
||||
}
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportBucket(*bucket)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Generatef("generating Bucket source")
|
||||
|
||||
if sourceBucketSecretRef == "" {
|
||||
if sourceBucketArgs.secretRef == "" {
|
||||
secretName := fmt.Sprintf("bucket-%s", name)
|
||||
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
StringData: map[string]string{},
|
||||
}
|
||||
|
||||
if sourceBucketAccessKey != "" && sourceBucketSecretKey != "" {
|
||||
secret.StringData["accesskey"] = sourceBucketAccessKey
|
||||
secret.StringData["secretkey"] = sourceBucketSecretKey
|
||||
if sourceBucketArgs.accessKey != "" && sourceBucketArgs.secretKey != "" {
|
||||
secret.StringData["accesskey"] = sourceBucketArgs.accessKey
|
||||
secret.StringData["secretkey"] = sourceBucketArgs.secretKey
|
||||
}
|
||||
|
||||
if len(secret.StringData) > 0 {
|
||||
@@ -169,7 +179,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
bucket.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
bucket.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: secretName,
|
||||
}
|
||||
logger.Successf("authentication configured")
|
||||
@@ -183,7 +193,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for Bucket source reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isBucketReady(ctx, kubeClient, namespacedName, bucket)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -34,12 +34,28 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/flags"
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/flags"
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
type SourceGitFlags struct {
|
||||
GitURL string
|
||||
GitBranch string
|
||||
GitTag string
|
||||
GitSemver string
|
||||
GitUsername string
|
||||
GitPassword string
|
||||
|
||||
GitKeyAlgorithm flags.PublicKeyAlgorithm
|
||||
GitRSABits flags.RSAKeyBits
|
||||
GitECDSACurve flags.ECDSACurve
|
||||
GitSecretRef string
|
||||
GitImplementation flags.GitImplementation
|
||||
}
|
||||
|
||||
var createSourceGitCmd = &cobra.Command{
|
||||
Use: "git [name]",
|
||||
Short: "Create or update a GitRepository source",
|
||||
@@ -84,44 +100,39 @@ For private Git repositories, the basic authentication credentials are stored in
|
||||
RunE: createSourceGitCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
sourceGitURL string
|
||||
sourceGitBranch string
|
||||
sourceGitTag string
|
||||
sourceGitSemver string
|
||||
sourceGitUsername string
|
||||
sourceGitPassword string
|
||||
|
||||
sourceGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
|
||||
sourceGitRSABits flags.RSAKeyBits = 2048
|
||||
sourceGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
|
||||
sourceGitSecretRef string
|
||||
sourceGitImplementation string
|
||||
)
|
||||
var sourceArgs = NewSourceGitFlags()
|
||||
|
||||
func init() {
|
||||
createSourceGitCmd.Flags().StringVar(&sourceGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceGitBranch, "branch", "master", "git branch")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceGitTag, "tag", "", "git tag")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceGitSemver, "tag-semver", "", "git tag semver range")
|
||||
createSourceGitCmd.Flags().StringVarP(&sourceGitUsername, "username", "u", "", "basic authentication username")
|
||||
createSourceGitCmd.Flags().StringVarP(&sourceGitPassword, "password", "p", "", "basic authentication password")
|
||||
createSourceGitCmd.Flags().Var(&sourceGitKeyAlgorithm, "ssh-key-algorithm", sourceGitKeyAlgorithm.Description())
|
||||
createSourceGitCmd.Flags().Var(&sourceGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description())
|
||||
createSourceGitCmd.Flags().Var(&sourceGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description())
|
||||
createSourceGitCmd.Flags().StringVarP(&sourceGitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceGitImplementation, "git-implementation", "", "the git implementation to use, can be 'go-git' or 'libgit2'")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitBranch, "branch", "master", "git branch")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitTag, "tag", "", "git tag")
|
||||
createSourceGitCmd.Flags().StringVar(&sourceArgs.GitSemver, "tag-semver", "", "git tag semver range")
|
||||
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitUsername, "username", "u", "", "basic authentication username")
|
||||
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitPassword, "password", "p", "", "basic authentication password")
|
||||
createSourceGitCmd.Flags().Var(&sourceArgs.GitKeyAlgorithm, "ssh-key-algorithm", sourceArgs.GitKeyAlgorithm.Description())
|
||||
createSourceGitCmd.Flags().Var(&sourceArgs.GitRSABits, "ssh-rsa-bits", sourceArgs.GitRSABits.Description())
|
||||
createSourceGitCmd.Flags().Var(&sourceArgs.GitECDSACurve, "ssh-ecdsa-curve", sourceArgs.GitECDSACurve.Description())
|
||||
createSourceGitCmd.Flags().StringVarP(&sourceArgs.GitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
|
||||
createSourceGitCmd.Flags().Var(&sourceArgs.GitImplementation, "git-implementation", sourceArgs.GitImplementation.Description())
|
||||
|
||||
createSourceCmd.AddCommand(createSourceGitCmd)
|
||||
}
|
||||
|
||||
func NewSourceGitFlags() SourceGitFlags {
|
||||
return SourceGitFlags{
|
||||
GitKeyAlgorithm: "rsa",
|
||||
GitRSABits: 2048,
|
||||
GitECDSACurve: flags.ECDSACurve{Curve: elliptic.P384()},
|
||||
}
|
||||
}
|
||||
|
||||
func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("GitRepository source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if sourceGitURL == "" {
|
||||
if sourceArgs.GitURL == "" {
|
||||
return fmt.Errorf("url is required")
|
||||
}
|
||||
|
||||
@@ -131,7 +142,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
u, err := url.Parse(sourceGitURL)
|
||||
u, err := url.Parse(sourceArgs.GitURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
@@ -141,58 +152,57 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !utils.ContainsItemString([]string{sourcev1.GoGitImplementation, sourcev1.LibGit2Implementation, ""}, sourceGitImplementation) {
|
||||
return fmt.Errorf("Invalid git implementation %q", sourceGitImplementation)
|
||||
}
|
||||
|
||||
gitRepository := sourcev1.GitRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
URL: sourceGitURL,
|
||||
URL: sourceArgs.GitURL,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
Duration: createArgs.interval,
|
||||
},
|
||||
Reference: &sourcev1.GitRepositoryRef{},
|
||||
GitImplementation: sourceGitImplementation,
|
||||
Reference: &sourcev1.GitRepositoryRef{},
|
||||
},
|
||||
}
|
||||
|
||||
if sourceGitSemver != "" {
|
||||
gitRepository.Spec.Reference.SemVer = sourceGitSemver
|
||||
} else if sourceGitTag != "" {
|
||||
gitRepository.Spec.Reference.Tag = sourceGitTag
|
||||
} else {
|
||||
gitRepository.Spec.Reference.Branch = sourceGitBranch
|
||||
if sourceArgs.GitImplementation != "" {
|
||||
gitRepository.Spec.GitImplementation = sourceArgs.GitImplementation.String()
|
||||
}
|
||||
|
||||
if export {
|
||||
if sourceGitSecretRef != "" {
|
||||
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
Name: sourceGitSecretRef,
|
||||
if sourceArgs.GitSemver != "" {
|
||||
gitRepository.Spec.Reference.SemVer = sourceArgs.GitSemver
|
||||
} else if sourceArgs.GitTag != "" {
|
||||
gitRepository.Spec.Reference.Tag = sourceArgs.GitTag
|
||||
} else {
|
||||
gitRepository.Spec.Reference.Branch = sourceArgs.GitBranch
|
||||
}
|
||||
|
||||
if createArgs.export {
|
||||
if sourceArgs.GitSecretRef != "" {
|
||||
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: sourceArgs.GitSecretRef,
|
||||
}
|
||||
}
|
||||
return exportGit(gitRepository)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
withAuth := false
|
||||
// TODO(hidde): move all auth prep to separate func?
|
||||
if sourceGitSecretRef != "" {
|
||||
if sourceArgs.GitSecretRef != "" {
|
||||
withAuth = true
|
||||
} else if u.Scheme == "ssh" {
|
||||
logger.Generatef("generating deploy key pair")
|
||||
pair, err := generateKeyPair(ctx, sourceGitKeyAlgorithm, sourceGitRSABits, sourceGitECDSACurve)
|
||||
pair, err := generateKeyPair(ctx, sourceArgs.GitKeyAlgorithm, sourceArgs.GitRSABits, sourceArgs.GitECDSACurve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -217,7 +227,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
@@ -230,17 +240,17 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
withAuth = true
|
||||
} else if sourceGitUsername != "" && sourceGitPassword != "" {
|
||||
} else if sourceArgs.GitUsername != "" && sourceArgs.GitPassword != "" {
|
||||
logger.Actionf("applying secret with basic auth credentials")
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"username": sourceGitUsername,
|
||||
"password": sourceGitPassword,
|
||||
"username": sourceArgs.GitUsername,
|
||||
"password": sourceArgs.GitPassword,
|
||||
},
|
||||
}
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
@@ -257,10 +267,10 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if withAuth {
|
||||
secretName := name
|
||||
if sourceGitSecretRef != "" {
|
||||
secretName = sourceGitSecretRef
|
||||
if sourceArgs.GitSecretRef != "" {
|
||||
secretName = sourceArgs.GitSecretRef
|
||||
}
|
||||
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
gitRepository.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: secretName,
|
||||
}
|
||||
}
|
||||
@@ -272,7 +282,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for GitRepository source reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, namespacedName, &gitRepository)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -33,8 +33,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
)
|
||||
|
||||
var createSourceHelmCmd = &cobra.Command{
|
||||
@@ -64,24 +65,26 @@ For private Helm repositories, the basic authentication credentials are stored i
|
||||
RunE: createSourceHelmCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
sourceHelmURL string
|
||||
sourceHelmUsername string
|
||||
sourceHelmPassword string
|
||||
sourceHelmCertFile string
|
||||
sourceHelmKeyFile string
|
||||
sourceHelmCAFile string
|
||||
sourceHelmSecretRef string
|
||||
)
|
||||
type sourceHelmFlags struct {
|
||||
url string
|
||||
username string
|
||||
password string
|
||||
certFile string
|
||||
keyFile string
|
||||
caFile string
|
||||
secretRef string
|
||||
}
|
||||
|
||||
var sourceHelmArgs sourceHelmFlags
|
||||
|
||||
func init() {
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmURL, "url", "", "Helm repository address")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmUsername, "username", "u", "", "basic authentication username")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmPassword, "password", "p", "", "basic authentication password")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmCertFile, "cert-file", "", "TLS authentication cert file path")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmKeyFile, "key-file", "", "TLS authentication key file path")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmCAFile, "ca-file", "", "TLS authentication CA file path")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmSecretRef, "secret-ref", "", "", "the name of an existing secret containing TLS or basic auth credentials")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.url, "url", "", "Helm repository address")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmArgs.username, "username", "u", "", "basic authentication username")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmArgs.password, "password", "p", "", "basic authentication password")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.certFile, "cert-file", "", "TLS authentication cert file path")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.keyFile, "key-file", "", "TLS authentication key file path")
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmArgs.caFile, "ca-file", "", "TLS authentication CA file path")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmArgs.secretRef, "secret-ref", "", "", "the name of an existing secret containing TLS or basic auth credentials")
|
||||
|
||||
createSourceCmd.AddCommand(createSourceHelmCmd)
|
||||
}
|
||||
@@ -92,7 +95,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if sourceHelmURL == "" {
|
||||
if sourceHelmArgs.url == "" {
|
||||
return fmt.Errorf("url is required")
|
||||
}
|
||||
|
||||
@@ -107,78 +110,78 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if _, err := url.Parse(sourceHelmURL); err != nil {
|
||||
if _, err := url.Parse(sourceHelmArgs.url); err != nil {
|
||||
return fmt.Errorf("url parse failed: %w", err)
|
||||
}
|
||||
|
||||
helmRepository := &sourcev1.HelmRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
Spec: sourcev1.HelmRepositorySpec{
|
||||
URL: sourceHelmURL,
|
||||
URL: sourceHelmArgs.url,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
Duration: createArgs.interval,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if sourceHelmSecretRef != "" {
|
||||
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
Name: sourceHelmSecretRef,
|
||||
if sourceHelmArgs.secretRef != "" {
|
||||
helmRepository.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: sourceHelmArgs.secretRef,
|
||||
}
|
||||
}
|
||||
|
||||
if export {
|
||||
if createArgs.export {
|
||||
return exportHelmRepository(*helmRepository)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Generatef("generating HelmRepository source")
|
||||
if sourceHelmSecretRef == "" {
|
||||
if sourceHelmArgs.secretRef == "" {
|
||||
secretName := fmt.Sprintf("helm-%s", name)
|
||||
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Labels: sourceLabels,
|
||||
},
|
||||
StringData: map[string]string{},
|
||||
}
|
||||
|
||||
if sourceHelmUsername != "" && sourceHelmPassword != "" {
|
||||
secret.StringData["username"] = sourceHelmUsername
|
||||
secret.StringData["password"] = sourceHelmPassword
|
||||
if sourceHelmArgs.username != "" && sourceHelmArgs.password != "" {
|
||||
secret.StringData["username"] = sourceHelmArgs.username
|
||||
secret.StringData["password"] = sourceHelmArgs.password
|
||||
}
|
||||
|
||||
if sourceHelmCertFile != "" && sourceHelmKeyFile != "" {
|
||||
cert, err := ioutil.ReadFile(sourceHelmCertFile)
|
||||
if sourceHelmArgs.certFile != "" && sourceHelmArgs.keyFile != "" {
|
||||
cert, err := ioutil.ReadFile(sourceHelmArgs.certFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository cert file '%s': %w", sourceHelmCertFile, err)
|
||||
return fmt.Errorf("failed to read repository cert file '%s': %w", sourceHelmArgs.certFile, err)
|
||||
}
|
||||
secret.StringData["certFile"] = string(cert)
|
||||
|
||||
key, err := ioutil.ReadFile(sourceHelmKeyFile)
|
||||
key, err := ioutil.ReadFile(sourceHelmArgs.keyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository key file '%s': %w", sourceHelmKeyFile, err)
|
||||
return fmt.Errorf("failed to read repository key file '%s': %w", sourceHelmArgs.keyFile, err)
|
||||
}
|
||||
secret.StringData["keyFile"] = string(key)
|
||||
}
|
||||
|
||||
if sourceHelmCAFile != "" {
|
||||
ca, err := ioutil.ReadFile(sourceHelmCAFile)
|
||||
if sourceHelmArgs.caFile != "" {
|
||||
ca, err := ioutil.ReadFile(sourceHelmArgs.caFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read repository CA file '%s': %w", sourceHelmCAFile, err)
|
||||
return fmt.Errorf("failed to read repository CA file '%s': %w", sourceHelmArgs.caFile, err)
|
||||
}
|
||||
secret.StringData["caFile"] = string(ca)
|
||||
}
|
||||
@@ -188,7 +191,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
helmRepository.Spec.SecretRef = &meta.LocalObjectReference{
|
||||
Name: secretName,
|
||||
}
|
||||
logger.Successf("authentication configured")
|
||||
@@ -202,7 +205,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for HelmRepository source reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isHelmRepositoryReady(ctx, kubeClient, namespacedName, helmRepository)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -58,14 +58,16 @@ const (
|
||||
tenantLabel = "toolkit.fluxcd.io/tenant"
|
||||
)
|
||||
|
||||
var (
|
||||
tenantNamespaces []string
|
||||
tenantClusterRole string
|
||||
)
|
||||
type tenantFlags struct {
|
||||
namespaces []string
|
||||
clusterRole string
|
||||
}
|
||||
|
||||
var tenantArgs tenantFlags
|
||||
|
||||
func init() {
|
||||
createTenantCmd.Flags().StringSliceVar(&tenantNamespaces, "with-namespace", nil, "namespace belonging to this tenant")
|
||||
createTenantCmd.Flags().StringVar(&tenantClusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
|
||||
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")
|
||||
createCmd.AddCommand(createTenantCmd)
|
||||
}
|
||||
|
||||
@@ -78,11 +80,11 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("invalid tenant name '%s': %v", tenant, err)
|
||||
}
|
||||
|
||||
if tenantClusterRole == "" {
|
||||
if tenantArgs.clusterRole == "" {
|
||||
return fmt.Errorf("cluster-role is required")
|
||||
}
|
||||
|
||||
if tenantNamespaces == nil {
|
||||
if tenantArgs.namespaces == nil {
|
||||
return fmt.Errorf("with-namespace is required")
|
||||
}
|
||||
|
||||
@@ -90,7 +92,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
||||
var accounts []corev1.ServiceAccount
|
||||
var roleBindings []rbacv1.RoleBinding
|
||||
|
||||
for _, ns := range tenantNamespaces {
|
||||
for _, ns := range tenantArgs.namespaces {
|
||||
if err := validation.IsQualifiedName(ns); len(err) > 0 {
|
||||
return fmt.Errorf("invalid namespace '%s': %v", ns, err)
|
||||
}
|
||||
@@ -141,14 +143,14 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
Kind: "ClusterRole",
|
||||
Name: tenantClusterRole,
|
||||
Name: tenantArgs.clusterRole,
|
||||
},
|
||||
}
|
||||
roleBindings = append(roleBindings, roleBinding)
|
||||
}
|
||||
|
||||
if export {
|
||||
for i, _ := range tenantNamespaces {
|
||||
if createArgs.export {
|
||||
for i, _ := range tenantArgs.namespaces {
|
||||
if err := exportTenant(namespaces[i], accounts[i], roleBindings[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -156,15 +158,15 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, _ := range tenantNamespaces {
|
||||
for i, _ := range tenantArgs.namespaces {
|
||||
logger.Actionf("applying namespace %s", namespaces[i].Name)
|
||||
if err := upsertNamespace(ctx, kubeClient, namespaces[i]); err != nil {
|
||||
return err
|
||||
|
||||
@@ -33,12 +33,14 @@ var deleteCmd = &cobra.Command{
|
||||
Long: "The delete sub-commands delete sources and resources.",
|
||||
}
|
||||
|
||||
var (
|
||||
deleteSilent bool
|
||||
)
|
||||
type deleteFlags struct {
|
||||
silent bool
|
||||
}
|
||||
|
||||
var deleteArgs deleteFlags
|
||||
|
||||
func init() {
|
||||
deleteCmd.PersistentFlags().BoolVarP(&deleteSilent, "silent", "s", false,
|
||||
deleteCmd.PersistentFlags().BoolVarP(&deleteArgs.silent, "silent", "s", false,
|
||||
"delete resource without asking for confirmation")
|
||||
|
||||
rootCmd.AddCommand(deleteCmd)
|
||||
@@ -55,25 +57,25 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, del.object.asRuntimeObject())
|
||||
err = kubeClient.Get(ctx, namespacedName, del.object.asClientObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !deleteArgs.silent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this " + del.humanKind,
|
||||
IsConfirm: true,
|
||||
@@ -83,8 +85,8 @@ func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, namespace)
|
||||
err = kubeClient.Delete(ctx, del.object.asRuntimeObject())
|
||||
logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, rootArgs.namespace)
|
||||
err = kubeClient.Delete(ctx, del.object.asClientObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -48,16 +48,16 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !deleteArgs.silent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this Alert",
|
||||
IsConfirm: true,
|
||||
@@ -77,7 +77,7 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting alert %s in %s namespace", name, namespace)
|
||||
logger.Actionf("deleting alert %s in %s namespace", name, rootArgs.namespace)
|
||||
err = kubeClient.Delete(ctx, &alert)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -48,16 +48,16 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !deleteArgs.silent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this Provider",
|
||||
IsConfirm: true,
|
||||
@@ -77,7 +77,7 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting provider %s in %s namespace", name, namespace)
|
||||
logger.Actionf("deleting provider %s in %s namespace", name, rootArgs.namespace)
|
||||
err = kubeClient.Delete(ctx, &alertProvider)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,15 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var deleteHelmReleaseCmd = &cobra.Command{
|
||||
@@ -36,57 +29,12 @@ var deleteHelmReleaseCmd = &cobra.Command{
|
||||
Example: ` # Delete a Helm release and the Kubernetes resources created by it
|
||||
flux delete hr podinfo
|
||||
`,
|
||||
RunE: deleteHelmReleaseCmdRun,
|
||||
RunE: deleteCommand{
|
||||
apiType: helmReleaseType,
|
||||
object: universalAdapter{&helmv2.HelmRelease{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
deleteCmd.AddCommand(deleteHelmReleaseCmd)
|
||||
}
|
||||
|
||||
func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("release name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !helmRelease.Spec.Suspend {
|
||||
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s Helm release!", name)
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this Helm release",
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
return fmt.Errorf("aborting")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting release %s in %s namespace", name, namespace)
|
||||
err = kubeClient.Delete(ctx, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("release deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,14 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var deleteKsCmd = &cobra.Command{
|
||||
@@ -35,57 +29,12 @@ var deleteKsCmd = &cobra.Command{
|
||||
Example: ` # Delete a kustomization and the Kubernetes resources created by it
|
||||
flux delete kustomization podinfo
|
||||
`,
|
||||
RunE: deleteKsCmdRun,
|
||||
RunE: deleteCommand{
|
||||
apiType: kustomizationType,
|
||||
object: universalAdapter{&kustomizev1.Kustomization{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
deleteCmd.AddCommand(deleteKsCmd)
|
||||
}
|
||||
|
||||
func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("kustomization name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var kustomization kustomizev1.Kustomization
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !kustomization.Spec.Suspend {
|
||||
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name)
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this kustomization",
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
return fmt.Errorf("aborting")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting kustomization %s in %s namespace", name, namespace)
|
||||
err = kubeClient.Delete(ctx, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("kustomization deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -48,16 +48,16 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !deleteArgs.silent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this Receiver",
|
||||
IsConfirm: true,
|
||||
@@ -77,7 +77,7 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting receiver %s in %s namespace", name, namespace)
|
||||
logger.Actionf("deleting receiver %s in %s namespace", name, rootArgs.namespace)
|
||||
err = kubeClient.Delete(ctx, &receiver)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,14 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var deleteSourceBucketCmd = &cobra.Command{
|
||||
@@ -34,54 +28,12 @@ var deleteSourceBucketCmd = &cobra.Command{
|
||||
Example: ` # Delete a Bucket source
|
||||
flux delete source bucket podinfo
|
||||
`,
|
||||
RunE: deleteSourceBucketCmdRun,
|
||||
RunE: deleteCommand{
|
||||
apiType: bucketType,
|
||||
object: universalAdapter{&sourcev1.Bucket{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
deleteSourceCmd.AddCommand(deleteSourceBucketCmd)
|
||||
}
|
||||
|
||||
func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var bucket sourcev1.Bucket
|
||||
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this source",
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
return fmt.Errorf("aborting")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting source %s in %s namespace", name, namespace)
|
||||
err = kubeClient.Delete(ctx, &bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,14 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var deleteSourceGitCmd = &cobra.Command{
|
||||
@@ -34,54 +28,12 @@ var deleteSourceGitCmd = &cobra.Command{
|
||||
Example: ` # Delete a Git repository
|
||||
flux delete source git podinfo
|
||||
`,
|
||||
RunE: deleteSourceGitCmdRun,
|
||||
RunE: deleteCommand{
|
||||
apiType: gitRepositoryType,
|
||||
object: universalAdapter{&sourcev1.GitRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
deleteSourceCmd.AddCommand(deleteSourceGitCmd)
|
||||
}
|
||||
|
||||
func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("git name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var git sourcev1.GitRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &git)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this source",
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
return fmt.Errorf("aborting")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting source %s in %s namespace", name, namespace)
|
||||
err = kubeClient.Delete(ctx, &git)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ var deleteSourceHelmCmd = &cobra.Command{
|
||||
Example: ` # Delete a Helm repository
|
||||
flux delete source helm podinfo
|
||||
`,
|
||||
RunE: deleteSourceHelmCmdRun,
|
||||
RunE: deleteCommand{
|
||||
apiType: helmRepositoryType,
|
||||
object: universalAdapter{&sourcev1.HelmRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -47,16 +50,16 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -66,7 +69,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !deleteArgs.silent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this source",
|
||||
IsConfirm: true,
|
||||
@@ -76,7 +79,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting source %s in %s namespace", name, namespace)
|
||||
logger.Actionf("deleting source %s in %s namespace", name, rootArgs.namespace)
|
||||
err = kubeClient.Delete(ctx, &helmRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -35,12 +35,14 @@ var exportCmd = &cobra.Command{
|
||||
Long: "The export sub-commands export resources in YAML format.",
|
||||
}
|
||||
|
||||
var (
|
||||
exportAll bool
|
||||
)
|
||||
type exportFlags struct {
|
||||
all bool
|
||||
}
|
||||
|
||||
var exportArgs exportFlags
|
||||
|
||||
func init() {
|
||||
exportCmd.PersistentFlags().BoolVar(&exportAll, "all", false, "select all resources")
|
||||
exportCmd.PersistentFlags().BoolVar(&exportArgs.all, "all", false, "select all resources")
|
||||
|
||||
rootCmd.AddCommand(exportCmd)
|
||||
}
|
||||
@@ -55,8 +57,7 @@ type exportable interface {
|
||||
// exportableList represents a type that has a list of values, each of
|
||||
// which is exportable.
|
||||
type exportableList interface {
|
||||
adapter
|
||||
len() int
|
||||
listAdapter
|
||||
exportItem(i int) interface{}
|
||||
}
|
||||
|
||||
@@ -66,26 +67,26 @@ type exportCommand struct {
|
||||
}
|
||||
|
||||
func (export exportCommand) run(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
err = kubeClient.List(ctx, export.list.asRuntimeObject(), client.InNamespace(namespace))
|
||||
if exportArgs.all {
|
||||
err = kubeClient.List(ctx, export.list.asClientList(), client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if export.list.len() == 0 {
|
||||
logger.Failuref("no objects found in %s namespace", namespace)
|
||||
logger.Failuref("no objects found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -97,10 +98,10 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
err = kubeClient.Get(ctx, namespacedName, export.object.asRuntimeObject())
|
||||
err = kubeClient.Get(ctx, namespacedName, export.object.asClientObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -48,27 +48,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list notificationv1.AlertList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no alerts found in %s namespace", namespace)
|
||||
logger.Failuref("no alerts found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var alert notificationv1.Alert
|
||||
|
||||
@@ -48,27 +48,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list notificationv1.ProviderList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no alertproviders found in %s namespace", namespace)
|
||||
logger.Failuref("no alertproviders found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var alertProvider notificationv1.Provider
|
||||
|
||||
@@ -49,27 +49,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list helmv2.HelmReleaseList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no helmrelease found in %s namespace", namespace)
|
||||
logger.Failuref("no helmrelease found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var helmRelease helmv2.HelmRelease
|
||||
|
||||
@@ -49,27 +49,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("kustomization name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list kustomizev1.KustomizationList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no kustomizations found in %s namespace", namespace)
|
||||
logger.Failuref("no kustomizations found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
|
||||
@@ -48,27 +48,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list notificationv1.ReceiverList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no receivers found in %s namespace", namespace)
|
||||
logger.Failuref("no receivers found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var receiver notificationv1.Receiver
|
||||
|
||||
@@ -49,27 +49,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list sourcev1.BucketList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no source found in %s namespace", namespace)
|
||||
logger.Failuref("no source found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var bucket sourcev1.Bucket
|
||||
|
||||
@@ -49,27 +49,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list sourcev1.GitRepositoryList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no source found in %s namespace", namespace)
|
||||
logger.Failuref("no source found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.GitRepository
|
||||
|
||||
@@ -49,27 +49,27 @@ func init() {
|
||||
}
|
||||
|
||||
func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
if !exportArgs.all && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
if exportArgs.all {
|
||||
var list sourcev1.HelmRepositoryList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no source found in %s namespace", namespace)
|
||||
logger.Failuref("no source found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.HelmRepository
|
||||
|
||||
@@ -36,17 +36,20 @@ var getCmd = &cobra.Command{
|
||||
Long: "The get sub-commands print the statuses of sources and resources.",
|
||||
}
|
||||
|
||||
var allNamespaces bool
|
||||
type GetFlags struct {
|
||||
allNamespaces bool
|
||||
}
|
||||
|
||||
var getArgs GetFlags
|
||||
|
||||
func init() {
|
||||
getCmd.PersistentFlags().BoolVarP(&allNamespaces, "all-namespaces", "A", false,
|
||||
getCmd.PersistentFlags().BoolVarP(&getArgs.allNamespaces, "all-namespaces", "A", false,
|
||||
"list the requested object(s) across all namespaces")
|
||||
rootCmd.AddCommand(getCmd)
|
||||
}
|
||||
|
||||
type summarisable interface {
|
||||
adapter
|
||||
len() int
|
||||
listAdapter
|
||||
summariseItem(i int, includeNamespace bool) []string
|
||||
headers(includeNamespace bool) []string
|
||||
}
|
||||
@@ -75,32 +78,32 @@ type getCommand struct {
|
||||
}
|
||||
|
||||
func (get getCommand) run(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
if !getArgs.allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
|
||||
}
|
||||
err = kubeClient.List(ctx, get.list.asRuntimeObject(), listOpts...)
|
||||
err = kubeClient.List(ctx, get.list.asClientList(), listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if get.list.len() == 0 {
|
||||
logger.Failuref("no %s objects found in %s namespace", get.kind, namespace)
|
||||
logger.Failuref("no %s objects found in %s namespace", get.kind, rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := get.list.headers(allNamespaces)
|
||||
header := get.list.headers(getArgs.allNamespaces)
|
||||
var rows [][]string
|
||||
for i := 0; i < get.list.len(); i++ {
|
||||
row := get.list.summariseItem(i, allNamespaces)
|
||||
row := get.list.summariseItem(i, getArgs.allNamespaces)
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
|
||||
@@ -47,17 +47,17 @@ func init() {
|
||||
}
|
||||
|
||||
func getAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
if !getArgs.allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
|
||||
}
|
||||
var list notificationv1.AlertList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
@@ -66,12 +66,12 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no alerts found in %s namespace", namespace)
|
||||
logger.Failuref("no alerts found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Suspended"}
|
||||
if allNamespaces {
|
||||
if getArgs.allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
@@ -92,7 +92,7 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
if getArgs.allNamespaces {
|
||||
row = append([]string{alert.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
|
||||
@@ -45,17 +45,17 @@ func init() {
|
||||
}
|
||||
|
||||
func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
if !getArgs.allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
|
||||
}
|
||||
var list notificationv1.ProviderList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
@@ -64,12 +64,12 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no providers found in %s namespace", namespace)
|
||||
logger.Failuref("no providers found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message"}
|
||||
if allNamespaces {
|
||||
if getArgs.allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
@@ -88,7 +88,7 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
"waiting to be reconciled",
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
if getArgs.allNamespaces {
|
||||
row = append([]string{provider.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
|
||||
@@ -17,20 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var getHelmReleaseCmd = &cobra.Command{
|
||||
@@ -41,66 +32,28 @@ var getHelmReleaseCmd = &cobra.Command{
|
||||
Example: ` # List all Helm releases and their status
|
||||
flux get helmreleases
|
||||
`,
|
||||
RunE: getHelmReleaseCmdRun,
|
||||
RunE: getCommand{
|
||||
apiType: helmReleaseType,
|
||||
list: &helmReleaseListAdapter{&helmv2.HelmReleaseList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getCmd.AddCommand(getHelmReleaseCmd)
|
||||
}
|
||||
|
||||
func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
}
|
||||
var list helmv2.HelmReleaseList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no releases found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
for _, helmRelease := range list.Items {
|
||||
row := []string{}
|
||||
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
row = []string{
|
||||
helmRelease.GetName(),
|
||||
string(c.Status),
|
||||
c.Message,
|
||||
helmRelease.Status.LastAppliedRevision,
|
||||
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
helmRelease.GetName(),
|
||||
string(metav1.ConditionFalse),
|
||||
"waiting to be reconciled",
|
||||
helmRelease.Status.LastAppliedRevision,
|
||||
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
row = append([]string{helmRelease.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
return nil
|
||||
func (a helmReleaseListAdapter) summariseItem(i int, includeNamespace bool) []string {
|
||||
item := a.Items[i]
|
||||
revision := item.Status.LastAppliedRevision
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace),
|
||||
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
|
||||
}
|
||||
|
||||
func (a helmReleaseListAdapter) headers(includeNamespace bool) []string {
|
||||
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if includeNamespace {
|
||||
headers = append([]string{"Namespace"}, headers...)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -17,19 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var getKsCmd = &cobra.Command{
|
||||
@@ -40,66 +32,28 @@ var getKsCmd = &cobra.Command{
|
||||
Example: ` # List all kustomizations and their status
|
||||
flux get kustomizations
|
||||
`,
|
||||
RunE: getKsCmdRun,
|
||||
RunE: getCommand{
|
||||
apiType: kustomizationType,
|
||||
list: &kustomizationListAdapter{&kustomizev1.KustomizationList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getCmd.AddCommand(getKsCmd)
|
||||
}
|
||||
|
||||
func getKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
}
|
||||
var list kustomizev1.KustomizationList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no kustomizations found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
for _, kustomization := range list.Items {
|
||||
row := []string{}
|
||||
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
row = []string{
|
||||
kustomization.GetName(),
|
||||
string(c.Status),
|
||||
c.Message,
|
||||
kustomization.Status.LastAppliedRevision,
|
||||
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
kustomization.GetName(),
|
||||
string(metav1.ConditionFalse),
|
||||
"waiting to be reconciled",
|
||||
kustomization.Status.LastAppliedRevision,
|
||||
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
row = append([]string{kustomization.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
return nil
|
||||
func (a kustomizationListAdapter) summariseItem(i int, includeNamespace bool) []string {
|
||||
item := a.Items[i]
|
||||
revision := item.Status.LastAppliedRevision
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace),
|
||||
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
|
||||
}
|
||||
|
||||
func (a kustomizationListAdapter) headers(includeNamespace bool) []string {
|
||||
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if includeNamespace {
|
||||
headers = append([]string{"Namespace"}, headers...)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -47,17 +47,17 @@ func init() {
|
||||
}
|
||||
|
||||
func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
if !getArgs.allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(rootArgs.namespace))
|
||||
}
|
||||
var list notificationv1.ReceiverList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
@@ -66,12 +66,12 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no receivers found in %s namespace", namespace)
|
||||
logger.Failuref("no receivers found in %s namespace", rootArgs.namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Suspended"}
|
||||
if allNamespaces {
|
||||
if getArgs.allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
|
||||
@@ -17,19 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var getSourceBucketCmd = &cobra.Command{
|
||||
@@ -42,70 +34,31 @@ var getSourceBucketCmd = &cobra.Command{
|
||||
# List buckets from all namespaces
|
||||
flux get sources helm --all-namespaces
|
||||
`,
|
||||
RunE: getSourceBucketCmdRun,
|
||||
RunE: getCommand{
|
||||
apiType: bucketType,
|
||||
list: &bucketListAdapter{&sourcev1.BucketList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getSourceCmd.AddCommand(getSourceBucketCmd)
|
||||
}
|
||||
|
||||
func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
func (a *bucketListAdapter) summariseItem(i int, includeNamespace bool) []string {
|
||||
item := a.Items[i]
|
||||
var revision string
|
||||
if item.GetArtifact() != nil {
|
||||
revision = item.GetArtifact().Revision
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
}
|
||||
var list sourcev1.BucketList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no bucket sources found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
for _, source := range list.Items {
|
||||
var row []string
|
||||
var revision string
|
||||
if source.GetArtifact() != nil {
|
||||
revision = source.GetArtifact().Revision
|
||||
}
|
||||
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(c.Status),
|
||||
c.Message,
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(metav1.ConditionFalse),
|
||||
"waiting to be reconciled",
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
row = append([]string{source.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
return nil
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace),
|
||||
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
|
||||
}
|
||||
|
||||
func (a bucketListAdapter) headers(includeNamespace bool) []string {
|
||||
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if includeNamespace {
|
||||
headers = append([]string{"Namespace"}, headers...)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -17,19 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var getSourceHelmChartCmd = &cobra.Command{
|
||||
@@ -42,70 +34,31 @@ var getSourceHelmChartCmd = &cobra.Command{
|
||||
# List Helm charts from all namespaces
|
||||
flux get sources chart --all-namespaces
|
||||
`,
|
||||
RunE: getSourceHelmChartCmdRun,
|
||||
RunE: getCommand{
|
||||
apiType: helmChartType,
|
||||
list: &helmChartListAdapter{&sourcev1.HelmChartList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getSourceCmd.AddCommand(getSourceHelmChartCmd)
|
||||
}
|
||||
|
||||
func getSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
func (a *helmChartListAdapter) summariseItem(i int, includeNamespace bool) []string {
|
||||
item := a.Items[i]
|
||||
var revision string
|
||||
if item.GetArtifact() != nil {
|
||||
revision = item.GetArtifact().Revision
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
}
|
||||
var list sourcev1.HelmChartList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no chart sources found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
for _, source := range list.Items {
|
||||
var row []string
|
||||
var revision string
|
||||
if source.GetArtifact() != nil {
|
||||
revision = source.GetArtifact().Revision
|
||||
}
|
||||
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(c.Status),
|
||||
c.Message,
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(metav1.ConditionFalse),
|
||||
"waiting to be reconciled",
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
row = append([]string{source.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
return nil
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace),
|
||||
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
|
||||
}
|
||||
|
||||
func (a helmChartListAdapter) headers(includeNamespace bool) []string {
|
||||
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if includeNamespace {
|
||||
headers = append([]string{"Namespace"}, headers...)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -17,19 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var getSourceGitCmd = &cobra.Command{
|
||||
@@ -42,70 +34,31 @@ var getSourceGitCmd = &cobra.Command{
|
||||
# List Git repositories from all namespaces
|
||||
flux get sources git --all-namespaces
|
||||
`,
|
||||
RunE: getSourceGitCmdRun,
|
||||
RunE: getCommand{
|
||||
apiType: gitRepositoryType,
|
||||
list: &gitRepositoryListAdapter{&sourcev1.GitRepositoryList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getSourceCmd.AddCommand(getSourceGitCmd)
|
||||
}
|
||||
|
||||
func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
func (a *gitRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
|
||||
item := a.Items[i]
|
||||
var revision string
|
||||
if item.GetArtifact() != nil {
|
||||
revision = item.GetArtifact().Revision
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
}
|
||||
var list sourcev1.GitRepositoryList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no git sources found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
for _, source := range list.Items {
|
||||
var row []string
|
||||
var revision string
|
||||
if source.GetArtifact() != nil {
|
||||
revision = source.GetArtifact().Revision
|
||||
}
|
||||
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(c.Status),
|
||||
c.Message,
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(metav1.ConditionFalse),
|
||||
"waiting to be reconciled",
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
row = append([]string{source.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
return nil
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace),
|
||||
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
|
||||
}
|
||||
|
||||
func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string {
|
||||
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if includeNamespace {
|
||||
headers = append([]string{"Namespace"}, headers...)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
@@ -17,19 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var getSourceHelmCmd = &cobra.Command{
|
||||
@@ -42,70 +34,31 @@ var getSourceHelmCmd = &cobra.Command{
|
||||
# List Helm repositories from all namespaces
|
||||
flux get sources helm --all-namespaces
|
||||
`,
|
||||
RunE: getSourceHelmCmdRun,
|
||||
RunE: getCommand{
|
||||
apiType: helmRepositoryType,
|
||||
list: &helmRepositoryListAdapter{&sourcev1.HelmRepositoryList{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getSourceCmd.AddCommand(getSourceHelmCmd)
|
||||
}
|
||||
|
||||
func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
func (a *helmRepositoryListAdapter) summariseItem(i int, includeNamespace bool) []string {
|
||||
item := a.Items[i]
|
||||
var revision string
|
||||
if item.GetArtifact() != nil {
|
||||
revision = item.GetArtifact().Revision
|
||||
}
|
||||
|
||||
var listOpts []client.ListOption
|
||||
if !allNamespaces {
|
||||
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||
}
|
||||
var list sourcev1.HelmRepositoryList
|
||||
err = kubeClient.List(ctx, &list, listOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no helm sources found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if allNamespaces {
|
||||
header = append([]string{"Namespace"}, header...)
|
||||
}
|
||||
var rows [][]string
|
||||
for _, source := range list.Items {
|
||||
var row []string
|
||||
var revision string
|
||||
if source.GetArtifact() != nil {
|
||||
revision = source.GetArtifact().Revision
|
||||
}
|
||||
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(c.Status),
|
||||
c.Message,
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
source.GetName(),
|
||||
string(metav1.ConditionFalse),
|
||||
"waiting to be reconciled",
|
||||
revision,
|
||||
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||
}
|
||||
}
|
||||
if allNamespaces {
|
||||
row = append([]string{source.Namespace}, row...)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
return nil
|
||||
status, msg := statusAndMessage(item.Status.Conditions)
|
||||
return append(nameColumns(&item, includeNamespace),
|
||||
status, msg, revision, strings.Title(strconv.FormatBool(item.Spec.Suspend)))
|
||||
}
|
||||
|
||||
func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string {
|
||||
headers := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||
if includeNamespace {
|
||||
headers = append([]string{"Namespace"}, headers...)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
51
cmd/flux/helmrelease.go
Normal file
51
cmd/flux/helmrelease.go
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2021 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// helmv2.HelmRelease
|
||||
|
||||
var helmReleaseType = apiType{
|
||||
kind: helmv2.HelmReleaseKind,
|
||||
humanKind: "helmreleases",
|
||||
}
|
||||
|
||||
type helmReleaseAdapter struct {
|
||||
*helmv2.HelmRelease
|
||||
}
|
||||
|
||||
func (h helmReleaseAdapter) asClientObject() client.Object {
|
||||
return h.HelmRelease
|
||||
}
|
||||
|
||||
// helmv2.HelmReleaseList
|
||||
|
||||
type helmReleaseListAdapter struct {
|
||||
*helmv2.HelmReleaseList
|
||||
}
|
||||
|
||||
func (h helmReleaseListAdapter) asClientList() client.ObjectList {
|
||||
return h.HelmReleaseList
|
||||
}
|
||||
|
||||
func (h helmReleaseListAdapter) len() int {
|
||||
return len(h.HelmReleaseList.Items)
|
||||
}
|
||||
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
|
||||
@@ -38,7 +38,7 @@ type imageRepositoryAdapter struct {
|
||||
*imagev1.ImageRepository
|
||||
}
|
||||
|
||||
func (a imageRepositoryAdapter) asRuntimeObject() runtime.Object {
|
||||
func (a imageRepositoryAdapter) asClientObject() client.Object {
|
||||
return a.ImageRepository
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ type imageRepositoryListAdapter struct {
|
||||
*imagev1.ImageRepositoryList
|
||||
}
|
||||
|
||||
func (a imageRepositoryListAdapter) asRuntimeObject() runtime.Object {
|
||||
func (a imageRepositoryListAdapter) asClientList() client.ObjectList {
|
||||
return a.ImageRepositoryList
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ type imagePolicyAdapter struct {
|
||||
*imagev1.ImagePolicy
|
||||
}
|
||||
|
||||
func (a imagePolicyAdapter) asRuntimeObject() runtime.Object {
|
||||
func (a imagePolicyAdapter) asClientObject() client.Object {
|
||||
return a.ImagePolicy
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ type imagePolicyListAdapter struct {
|
||||
*imagev1.ImagePolicyList
|
||||
}
|
||||
|
||||
func (a imagePolicyListAdapter) asRuntimeObject() runtime.Object {
|
||||
func (a imagePolicyListAdapter) asClientList() client.ObjectList {
|
||||
return a.ImagePolicyList
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ type imageUpdateAutomationAdapter struct {
|
||||
*autov1.ImageUpdateAutomation
|
||||
}
|
||||
|
||||
func (a imageUpdateAutomationAdapter) asRuntimeObject() runtime.Object {
|
||||
func (a imageUpdateAutomationAdapter) asClientObject() client.Object {
|
||||
return a.ImageUpdateAutomation
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ type imageUpdateAutomationListAdapter struct {
|
||||
*autov1.ImageUpdateAutomationList
|
||||
}
|
||||
|
||||
func (a imageUpdateAutomationListAdapter) asRuntimeObject() runtime.Object {
|
||||
func (a imageUpdateAutomationListAdapter) asClientList() client.ObjectList {
|
||||
return a.ImageUpdateAutomationList
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ var (
|
||||
installImagePullSecret string
|
||||
installWatchAllNamespaces bool
|
||||
installNetworkPolicy bool
|
||||
installArch = flags.Arch(defaults.Arch)
|
||||
installLogLevel = flags.LogLevel(defaults.LogLevel)
|
||||
installArch flags.Arch
|
||||
installLogLevel = flags.LogLevel(rootArgs.defaults.LogLevel)
|
||||
installClusterDomain string
|
||||
)
|
||||
|
||||
@@ -72,33 +72,34 @@ func init() {
|
||||
"write the install manifests to stdout and exit")
|
||||
installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false,
|
||||
"only print the object that would be applied")
|
||||
installCmd.Flags().StringVarP(&installVersion, "version", "v", defaults.Version,
|
||||
installCmd.Flags().StringVarP(&installVersion, "version", "v", rootArgs.defaults.Version,
|
||||
"toolkit version")
|
||||
installCmd.Flags().StringSliceVar(&installDefaultComponents, "components", defaults.Components,
|
||||
installCmd.Flags().StringSliceVar(&installDefaultComponents, "components", rootArgs.defaults.Components,
|
||||
"list of components, accepts comma-separated values")
|
||||
installCmd.Flags().StringSliceVar(&installExtraComponents, "components-extra", nil,
|
||||
"list of components in addition to those supplied or defaulted, accepts comma-separated values")
|
||||
installCmd.Flags().StringVar(&installManifestsPath, "manifests", "", "path to the manifest directory")
|
||||
installCmd.Flags().MarkHidden("manifests")
|
||||
installCmd.Flags().StringVar(&installRegistry, "registry", defaults.Registry,
|
||||
installCmd.Flags().StringVar(&installRegistry, "registry", rootArgs.defaults.Registry,
|
||||
"container registry where the toolkit images are published")
|
||||
installCmd.Flags().StringVar(&installImagePullSecret, "image-pull-secret", "",
|
||||
"Kubernetes secret name used for pulling the toolkit images from a private registry")
|
||||
installCmd.Flags().Var(&installArch, "arch", installArch.Description())
|
||||
installCmd.Flags().BoolVar(&installWatchAllNamespaces, "watch-all-namespaces", defaults.WatchAllNamespaces,
|
||||
installCmd.Flags().BoolVar(&installWatchAllNamespaces, "watch-all-namespaces", rootArgs.defaults.WatchAllNamespaces,
|
||||
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
|
||||
installCmd.Flags().Var(&installLogLevel, "log-level", installLogLevel.Description())
|
||||
installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", defaults.NetworkPolicy,
|
||||
installCmd.Flags().BoolVar(&installNetworkPolicy, "network-policy", rootArgs.defaults.NetworkPolicy,
|
||||
"deny ingress access to the toolkit controllers from other namespaces using network policies")
|
||||
installCmd.Flags().StringVar(&installClusterDomain, "cluster-domain", defaults.ClusterDomain, "internal cluster domain")
|
||||
installCmd.Flags().StringVar(&installClusterDomain, "cluster-domain", rootArgs.defaults.ClusterDomain, "internal cluster domain")
|
||||
installCmd.Flags().MarkHidden("manifests")
|
||||
installCmd.Flags().MarkDeprecated("arch", "multi-arch container image is now available for AMD64, ARMv7 and ARM64")
|
||||
rootCmd.AddCommand(installCmd)
|
||||
}
|
||||
|
||||
func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", namespace)
|
||||
tmpDir, err := ioutil.TempDir("", rootArgs.namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -117,17 +118,16 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
opts := install.Options{
|
||||
BaseURL: installManifestsPath,
|
||||
Version: installVersion,
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Components: components,
|
||||
Registry: installRegistry,
|
||||
ImagePullSecret: installImagePullSecret,
|
||||
Arch: installArch.String(),
|
||||
WatchAllNamespaces: installWatchAllNamespaces,
|
||||
NetworkPolicy: installNetworkPolicy,
|
||||
LogLevel: installLogLevel.String(),
|
||||
NotificationController: defaults.NotificationController,
|
||||
ManifestFile: fmt.Sprintf("%s.yaml", namespace),
|
||||
Timeout: timeout,
|
||||
NotificationController: rootArgs.defaults.NotificationController,
|
||||
ManifestFile: fmt.Sprintf("%s.yaml", rootArgs.namespace),
|
||||
Timeout: rootArgs.timeout,
|
||||
ClusterDomain: installClusterDomain,
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("install failed: %w", err)
|
||||
}
|
||||
|
||||
if verbose {
|
||||
if rootArgs.verbose {
|
||||
fmt.Print(manifest.Content)
|
||||
} else if installExport {
|
||||
fmt.Println("---")
|
||||
@@ -156,9 +156,9 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
logger.Successf("manifests build completed")
|
||||
logger.Actionf("installing components in %s namespace", namespace)
|
||||
logger.Actionf("installing components in %s namespace", rootArgs.namespace)
|
||||
applyOutput := utils.ModeStderrOS
|
||||
if verbose {
|
||||
if rootArgs.verbose {
|
||||
applyOutput = utils.ModeOS
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
kubectlArgs = append(kubectlArgs, "--dry-run=client")
|
||||
applyOutput = utils.ModeOS
|
||||
}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
}
|
||||
|
||||
@@ -180,8 +180,8 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("verifying installation")
|
||||
for _, deployment := range components {
|
||||
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
kubectlArgs = []string{"-n", rootArgs.namespace, "rollout", "status", "deployment", deployment, "--timeout", rootArgs.timeout.String()}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
} else {
|
||||
logger.Successf("%s ready", deployment)
|
||||
|
||||
51
cmd/flux/kustomization.go
Normal file
51
cmd/flux/kustomization.go
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// kustomizev1.Kustomization
|
||||
|
||||
var kustomizationType = apiType{
|
||||
kind: kustomizev1.KustomizationKind,
|
||||
humanKind: "kustomizations",
|
||||
}
|
||||
|
||||
type kustomizationAdapter struct {
|
||||
*kustomizev1.Kustomization
|
||||
}
|
||||
|
||||
func (a kustomizationAdapter) asClientObject() client.Object {
|
||||
return a.Kustomization
|
||||
}
|
||||
|
||||
// kustomizev1.KustomizationList
|
||||
|
||||
type kustomizationListAdapter struct {
|
||||
*kustomizev1.KustomizationList
|
||||
}
|
||||
|
||||
func (a kustomizationListAdapter) asClientList() client.ObjectList {
|
||||
return a.KustomizationList
|
||||
}
|
||||
|
||||
func (a kustomizationListAdapter) len() int {
|
||||
return len(a.KustomizationList.Items)
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"github.com/spf13/cobra/doc"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
|
||||
fluxlog "github.com/fluxcd/flux2/pkg/log"
|
||||
"github.com/fluxcd/flux2/pkg/manifestgen/install"
|
||||
)
|
||||
|
||||
@@ -94,22 +93,32 @@ var rootCmd = &cobra.Command{
|
||||
`,
|
||||
}
|
||||
|
||||
var (
|
||||
var logger = stderrLogger{stderr: os.Stderr}
|
||||
|
||||
type rootFlags struct {
|
||||
kubeconfig string
|
||||
kubecontext string
|
||||
namespace string
|
||||
timeout time.Duration
|
||||
verbose bool
|
||||
pollInterval = 2 * time.Second
|
||||
logger fluxlog.Logger = stderrLogger{stderr: os.Stderr}
|
||||
defaults = install.MakeDefaultOptions()
|
||||
)
|
||||
pollInterval time.Duration
|
||||
defaults install.Options
|
||||
}
|
||||
|
||||
var rootArgs = NewRootFlags()
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", defaults.Namespace, "the namespace scope for this operation")
|
||||
rootCmd.PersistentFlags().DurationVar(&timeout, "timeout", 5*time.Minute, "timeout for this operation")
|
||||
rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "print generated objects")
|
||||
rootCmd.PersistentFlags().StringVarP(&kubecontext, "context", "", "", "kubernetes context to use")
|
||||
rootCmd.PersistentFlags().StringVarP(&rootArgs.namespace, "namespace", "n", rootArgs.defaults.Namespace, "the namespace scope for this operation")
|
||||
rootCmd.PersistentFlags().DurationVar(&rootArgs.timeout, "timeout", 5*time.Minute, "timeout for this operation")
|
||||
rootCmd.PersistentFlags().BoolVar(&rootArgs.verbose, "verbose", false, "print generated objects")
|
||||
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubecontext, "context", "", "", "kubernetes context to use")
|
||||
}
|
||||
|
||||
func NewRootFlags() rootFlags {
|
||||
return rootFlags{
|
||||
pollInterval: 2 * time.Second,
|
||||
defaults: install.MakeDefaultOptions(),
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -124,22 +133,22 @@ func main() {
|
||||
|
||||
func kubeconfigFlag() {
|
||||
if home := homeDir(); home != "" {
|
||||
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", filepath.Join(home, ".kube", "config"),
|
||||
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", filepath.Join(home, ".kube", "config"),
|
||||
"path to the kubeconfig file")
|
||||
} else {
|
||||
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", "",
|
||||
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", "",
|
||||
"absolute path to the kubeconfig file")
|
||||
}
|
||||
|
||||
if len(os.Getenv("KUBECONFIG")) > 0 {
|
||||
kubeconfig = os.Getenv("KUBECONFIG")
|
||||
rootArgs.kubeconfig = os.Getenv("KUBECONFIG")
|
||||
}
|
||||
}
|
||||
|
||||
func generateDocs() {
|
||||
args := os.Args[1:]
|
||||
if len(args) > 0 && args[0] == "docgen" {
|
||||
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", "~/.kube/config",
|
||||
rootCmd.PersistentFlags().StringVarP(&rootArgs.kubeconfig, "kubeconfig", "", "~/.kube/config",
|
||||
"path to the kubeconfig file")
|
||||
rootCmd.DisableAutoGenTag = true
|
||||
err := doc.GenMarkdownTree(rootCmd, "./docs/cmd")
|
||||
|
||||
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// Most commands need one or both of the kind (e.g.,
|
||||
@@ -35,16 +35,24 @@ type apiType struct {
|
||||
// use values of the wrapper with `client.Client`, which only deals
|
||||
// with types that have been added to the schema.
|
||||
type adapter interface {
|
||||
asRuntimeObject() runtime.Object
|
||||
asClientObject() client.Object
|
||||
}
|
||||
|
||||
// universalAdapter is an adapter for any runtime.Object. Use this if
|
||||
// listAdapater is the analogue to adapter, but for lists; the
|
||||
// controller runtime distinguishes between methods dealing with
|
||||
// objects and lists.
|
||||
type listAdapter interface {
|
||||
asClientList() client.ObjectList
|
||||
len() int
|
||||
}
|
||||
|
||||
// universalAdapter is an adapter for any client.Object. Use this if
|
||||
// there are no other methods needed.
|
||||
type universalAdapter struct {
|
||||
obj runtime.Object
|
||||
obj client.Object
|
||||
}
|
||||
|
||||
func (c universalAdapter) asRuntimeObject() runtime.Object {
|
||||
func (c universalAdapter) asClientObject() client.Object {
|
||||
return c.obj
|
||||
}
|
||||
|
||||
|
||||
@@ -69,20 +69,20 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, reconcile.object.asRuntimeObject())
|
||||
err = kubeClient.Get(ctx, namespacedName, reconcile.object.asClientObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -91,7 +91,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, namespace)
|
||||
logger.Actionf("annotating %s %s in %s namespace", reconcile.kind, name, rootArgs.namespace)
|
||||
if err := requestReconciliation(ctx, kubeClient, namespacedName, reconcile.object); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -99,7 +99,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
|
||||
|
||||
lastHandledReconcileAt := reconcile.object.lastHandledReconcileRequest()
|
||||
logger.Waitingf("waiting for %s reconciliation", reconcile.kind)
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
reconciliationHandled(ctx, kubeClient, namespacedName, reconcile.object, lastHandledReconcileAt)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -115,7 +115,7 @@ func (reconcile reconcileCommand) run(cmd *cobra.Command, args []string) error {
|
||||
func reconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, obj reconcilable, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, obj.asRuntimeObject())
|
||||
err := kubeClient.Get(ctx, namespacedName, obj.asClientObject())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -126,17 +126,17 @@ func reconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||
func requestReconciliation(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, obj reconcilable) error {
|
||||
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||
if err := kubeClient.Get(ctx, namespacedName, obj.asRuntimeObject()); err != nil {
|
||||
if err := kubeClient.Get(ctx, namespacedName, obj.asClientObject()); err != nil {
|
||||
return err
|
||||
}
|
||||
if ann := obj.GetAnnotations(); ann == nil {
|
||||
obj.SetAnnotations(map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
})
|
||||
} else {
|
||||
ann[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
ann[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
obj.SetAnnotations(ann)
|
||||
}
|
||||
return kubeClient.Update(ctx, obj.asRuntimeObject())
|
||||
return kubeClient.Update(ctx, obj.asClientObject())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,16 +51,16 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -74,13 +74,13 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
logger.Actionf("annotating Alert %s in %s namespace", name, namespace)
|
||||
logger.Actionf("annotating Alert %s in %s namespace", name, rootArgs.namespace)
|
||||
if alert.Annotations == nil {
|
||||
alert.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
alert.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
alert.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
if err := kubeClient.Update(ctx, &alert); err != nil {
|
||||
@@ -89,7 +89,7 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
logger.Successf("Alert annotated")
|
||||
|
||||
logger.Waitingf("waiting for reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isAlertReady(ctx, kubeClient, namespacedName, &alert)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -51,20 +51,20 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
logger.Actionf("annotating Provider %s in %s namespace", name, namespace)
|
||||
logger.Actionf("annotating Provider %s in %s namespace", name, rootArgs.namespace)
|
||||
var alertProvider notificationv1.Provider
|
||||
err = kubeClient.Get(ctx, namespacedName, &alertProvider)
|
||||
if err != nil {
|
||||
@@ -73,10 +73,10 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if alertProvider.Annotations == nil {
|
||||
alertProvider.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
alertProvider.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
alertProvider.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &alertProvider); err != nil {
|
||||
return err
|
||||
@@ -84,7 +84,7 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
||||
logger.Successf("Provider annotated")
|
||||
|
||||
logger.Waitingf("waiting for reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isAlertProviderReady(ctx, kubeClient, namespacedName, &alertProvider)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -51,12 +51,14 @@ The reconcile kustomization command triggers a reconciliation of a HelmRelease r
|
||||
RunE: reconcileHrCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
type reconcileHelmReleaseFlags struct {
|
||||
syncHrWithSource bool
|
||||
)
|
||||
}
|
||||
|
||||
var rhrArgs reconcileHelmReleaseFlags
|
||||
|
||||
func init() {
|
||||
reconcileHrCmd.Flags().BoolVar(&syncHrWithSource, "with-source", false, "reconcile HelmRelease source")
|
||||
reconcileHrCmd.Flags().BoolVar(&rhrArgs.syncHrWithSource, "with-source", false, "reconcile HelmRelease source")
|
||||
|
||||
reconcileCmd.AddCommand(reconcileHrCmd)
|
||||
}
|
||||
@@ -67,16 +69,16 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -90,29 +92,43 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
if syncHrWithSource {
|
||||
if rhrArgs.syncHrWithSource {
|
||||
nsCopy := rootArgs.namespace
|
||||
if helmRelease.Spec.Chart.Spec.SourceRef.Namespace != "" {
|
||||
rootArgs.namespace = helmRelease.Spec.Chart.Spec.SourceRef.Namespace
|
||||
}
|
||||
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
|
||||
case sourcev1.HelmRepositoryKind:
|
||||
err = reconcileSourceHelmCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
|
||||
err = reconcileCommand{
|
||||
apiType: helmRepositoryType,
|
||||
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
|
||||
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
|
||||
case sourcev1.GitRepositoryKind:
|
||||
err = reconcileSourceGitCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
|
||||
err = reconcileCommand{
|
||||
apiType: gitRepositoryType,
|
||||
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
|
||||
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
|
||||
case sourcev1.BucketKind:
|
||||
err = reconcileSourceBucketCmdRun(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
|
||||
err = reconcileCommand{
|
||||
apiType: bucketType,
|
||||
object: bucketAdapter{&sourcev1.Bucket{}},
|
||||
}.run(nil, []string{helmRelease.Spec.Chart.Spec.SourceRef.Name})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rootArgs.namespace = nsCopy
|
||||
}
|
||||
|
||||
lastHandledReconcileAt := helmRelease.Status.LastHandledReconcileAt
|
||||
logger.Actionf("annotating HelmRelease %s in %s namespace", name, namespace)
|
||||
logger.Actionf("annotating HelmRelease %s in %s namespace", name, rootArgs.namespace)
|
||||
if err := requestHelmReleaseReconciliation(ctx, kubeClient, namespacedName, &helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease annotated")
|
||||
|
||||
logger.Waitingf("waiting for HelmRelease reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
helmReleaseReconciliationHandled(ctx, kubeClient, namespacedName, &helmRelease, lastHandledReconcileAt),
|
||||
); err != nil {
|
||||
return err
|
||||
@@ -153,10 +169,10 @@ func requestHelmReleaseReconciliation(ctx context.Context, kubeClient client.Cli
|
||||
}
|
||||
if helmRelease.Annotations == nil {
|
||||
helmRelease.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
helmRelease.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
helmRelease.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
return kubeClient.Update(ctx, helmRelease)
|
||||
})
|
||||
|
||||
@@ -50,12 +50,14 @@ The reconcile kustomization command triggers a reconciliation of a Kustomization
|
||||
RunE: reconcileKsCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
type reconcileKsFlags struct {
|
||||
syncKsWithSource bool
|
||||
)
|
||||
}
|
||||
|
||||
var rksArgs reconcileKsFlags
|
||||
|
||||
func init() {
|
||||
reconcileKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "reconcile Kustomization source")
|
||||
reconcileKsCmd.Flags().BoolVar(&rksArgs.syncKsWithSource, "with-source", false, "reconcile Kustomization source")
|
||||
|
||||
reconcileCmd.AddCommand(reconcileKsCmd)
|
||||
}
|
||||
@@ -66,16 +68,16 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
@@ -88,20 +90,31 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
if syncKsWithSource {
|
||||
if rksArgs.syncKsWithSource {
|
||||
nsCopy := rootArgs.namespace
|
||||
if kustomization.Spec.SourceRef.Namespace != "" {
|
||||
rootArgs.namespace = kustomization.Spec.SourceRef.Namespace
|
||||
}
|
||||
switch kustomization.Spec.SourceRef.Kind {
|
||||
case sourcev1.GitRepositoryKind:
|
||||
err = reconcileSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
|
||||
err = reconcileCommand{
|
||||
apiType: gitRepositoryType,
|
||||
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
|
||||
}.run(nil, []string{kustomization.Spec.SourceRef.Name})
|
||||
case sourcev1.BucketKind:
|
||||
err = reconcileSourceBucketCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
|
||||
err = reconcileCommand{
|
||||
apiType: bucketType,
|
||||
object: bucketAdapter{&sourcev1.Bucket{}},
|
||||
}.run(nil, []string{kustomization.Spec.SourceRef.Name})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rootArgs.namespace = nsCopy
|
||||
}
|
||||
|
||||
lastHandledReconcileAt := kustomization.Status.LastHandledReconcileAt
|
||||
logger.Actionf("annotating Kustomization %s in %s namespace", name, namespace)
|
||||
logger.Actionf("annotating Kustomization %s in %s namespace", name, rootArgs.namespace)
|
||||
if err := requestKustomizeReconciliation(ctx, kubeClient, namespacedName, &kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -109,7 +122,7 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
logger.Waitingf("waiting for Kustomization reconciliation")
|
||||
if err := wait.PollImmediate(
|
||||
pollInterval, timeout,
|
||||
rootArgs.pollInterval, rootArgs.timeout,
|
||||
kustomizeReconciliationHandled(ctx, kubeClient, namespacedName, &kustomization, lastHandledReconcileAt),
|
||||
); err != nil {
|
||||
return err
|
||||
@@ -142,10 +155,10 @@ func requestKustomizeReconciliation(ctx context.Context, kubeClient client.Clien
|
||||
}
|
||||
if kustomization.Annotations == nil {
|
||||
kustomization.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
kustomization.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
kustomization.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
return kubeClient.Update(ctx, kustomization)
|
||||
})
|
||||
|
||||
@@ -51,16 +51,16 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
@@ -74,13 +74,13 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
logger.Actionf("annotating Receiver %s in %s namespace", name, namespace)
|
||||
logger.Actionf("annotating Receiver %s in %s namespace", name, rootArgs.namespace)
|
||||
if receiver.Annotations == nil {
|
||||
receiver.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
meta.ReconcileRequestAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
receiver.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
receiver.Annotations[meta.ReconcileRequestAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &receiver); err != nil {
|
||||
return err
|
||||
@@ -88,7 +88,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
logger.Successf("Receiver annotated")
|
||||
|
||||
logger.Waitingf("waiting for Receiver reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isReceiverReady(ctx, kubeClient, namespacedName, &receiver)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -19,13 +19,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"k8s.io/client-go/util/retry"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -43,64 +37,16 @@ var reconcileSourceBucketCmd = &cobra.Command{
|
||||
Example: ` # Trigger a reconciliation for an existing source
|
||||
flux reconcile source bucket podinfo
|
||||
`,
|
||||
RunE: reconcileSourceBucketCmdRun,
|
||||
RunE: reconcileCommand{
|
||||
apiType: bucketType,
|
||||
object: bucketAdapter{&sourcev1.Bucket{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileSourceCmd.AddCommand(reconcileSourceBucketCmd)
|
||||
}
|
||||
|
||||
func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var bucket sourcev1.Bucket
|
||||
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bucket.Spec.Suspend {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
lastHandledReconcileAt := bucket.Status.LastHandledReconcileAt
|
||||
logger.Actionf("annotating Bucket source %s in %s namespace", name, namespace)
|
||||
if err := requestBucketReconciliation(ctx, kubeClient, namespacedName, &bucket); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Bucket source annotated")
|
||||
|
||||
logger.Waitingf("waiting for Bucket source reconciliation")
|
||||
if err := wait.PollImmediate(
|
||||
pollInterval, timeout,
|
||||
bucketReconciliationHandled(ctx, kubeClient, namespacedName, &bucket, lastHandledReconcileAt),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Bucket source reconciliation completed")
|
||||
|
||||
if apimeta.IsStatusConditionFalse(bucket.Status.Conditions, meta.ReadyCondition) {
|
||||
return fmt.Errorf("Bucket source reconciliation failed")
|
||||
}
|
||||
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBucketReady(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
@@ -126,30 +72,10 @@ func isBucketReady(ctx context.Context, kubeClient client.Client,
|
||||
}
|
||||
}
|
||||
|
||||
func bucketReconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, bucket *sourcev1.Bucket, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, bucket)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return bucket.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
|
||||
}
|
||||
func (obj bucketAdapter) lastHandledReconcileRequest() string {
|
||||
return obj.Status.GetLastHandledReconcileRequest()
|
||||
}
|
||||
|
||||
func requestBucketReconciliation(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) error {
|
||||
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||
if err := kubeClient.Get(ctx, namespacedName, bucket); err != nil {
|
||||
return err
|
||||
}
|
||||
if bucket.Annotations == nil {
|
||||
bucket.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
bucket.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
return kubeClient.Update(ctx, bucket)
|
||||
})
|
||||
func (obj bucketAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
@@ -17,21 +17,9 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/client-go/util/retry"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var reconcileSourceGitCmd = &cobra.Command{
|
||||
@@ -41,86 +29,20 @@ var reconcileSourceGitCmd = &cobra.Command{
|
||||
Example: ` # Trigger a git pull for an existing source
|
||||
flux reconcile source git podinfo
|
||||
`,
|
||||
RunE: reconcileSourceGitCmdRun,
|
||||
RunE: reconcileCommand{
|
||||
apiType: gitRepositoryType,
|
||||
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileSourceCmd.AddCommand(reconcileSourceGitCmd)
|
||||
}
|
||||
|
||||
func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.GitRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if repository.Spec.Suspend {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
logger.Actionf("annotating GitRepository source %s in %s namespace", name, namespace)
|
||||
if err := requestGitRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("GitRepository source annotated")
|
||||
|
||||
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
|
||||
logger.Waitingf("waiting for GitRepository source reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
gitRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("GitRepository source reconciliation completed")
|
||||
|
||||
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
|
||||
return fmt.Errorf("GitRepository source reconciliation failed")
|
||||
}
|
||||
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||
return nil
|
||||
func (obj gitRepositoryAdapter) lastHandledReconcileRequest() string {
|
||||
return obj.Status.GetLastHandledReconcileRequest()
|
||||
}
|
||||
|
||||
func gitRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, repository *sourcev1.GitRepository, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
|
||||
}
|
||||
}
|
||||
|
||||
func requestGitRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) error {
|
||||
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
|
||||
return err
|
||||
}
|
||||
if repository.Annotations == nil {
|
||||
repository.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
return kubeClient.Update(ctx, repository)
|
||||
})
|
||||
func (obj gitRepositoryAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
@@ -17,22 +17,9 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"k8s.io/client-go/util/retry"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var reconcileSourceHelmCmd = &cobra.Command{
|
||||
@@ -42,86 +29,20 @@ var reconcileSourceHelmCmd = &cobra.Command{
|
||||
Example: ` # Trigger a reconciliation for an existing source
|
||||
flux reconcile source helm podinfo
|
||||
`,
|
||||
RunE: reconcileSourceHelmCmdRun,
|
||||
RunE: reconcileCommand{
|
||||
apiType: helmRepositoryType,
|
||||
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileSourceCmd.AddCommand(reconcileSourceHelmCmd)
|
||||
}
|
||||
|
||||
func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("HelmRepository source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.HelmRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if repository.Spec.Suspend {
|
||||
return fmt.Errorf("resource is suspended")
|
||||
}
|
||||
|
||||
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, namespace)
|
||||
if err := requestHelmRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRepository source annotated")
|
||||
|
||||
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
|
||||
logger.Waitingf("waiting for HelmRepository source reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
helmRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRepository source reconciliation completed")
|
||||
|
||||
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
|
||||
return fmt.Errorf("HelmRepository source reconciliation failed")
|
||||
}
|
||||
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||
return nil
|
||||
func (obj helmRepositoryAdapter) lastHandledReconcileRequest() string {
|
||||
return obj.Status.GetLastHandledReconcileRequest()
|
||||
}
|
||||
|
||||
func helmRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
|
||||
}
|
||||
}
|
||||
|
||||
func requestHelmRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) error {
|
||||
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
|
||||
return err
|
||||
}
|
||||
if repository.Annotations == nil {
|
||||
repository.Annotations = map[string]string{
|
||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
return kubeClient.Update(ctx, repository)
|
||||
})
|
||||
func (obj helmRepositoryAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
@@ -55,33 +55,33 @@ func (resume resumeCommand) run(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, resume.object.asRuntimeObject())
|
||||
err = kubeClient.Get(ctx, namespacedName, resume.object.asClientObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, name, namespace)
|
||||
logger.Actionf("resuming %s %s in %s namespace", resume.humanKind, name, rootArgs.namespace)
|
||||
resume.object.setUnsuspended()
|
||||
if err := kubeClient.Update(ctx, resume.object.asRuntimeObject()); err != nil {
|
||||
if err := kubeClient.Update(ctx, resume.object.asClientObject()); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("%s resumed", resume.humanKind)
|
||||
|
||||
logger.Waitingf("waiting for %s reconciliation", resume.kind)
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isReady(ctx, kubeClient, namespacedName, resume.object)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -54,16 +54,16 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var alert notificationv1.Alert
|
||||
@@ -72,7 +72,7 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming Alert %s in %s namespace", name, namespace)
|
||||
logger.Actionf("resuming Alert %s in %s namespace", name, rootArgs.namespace)
|
||||
alert.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &alert); err != nil {
|
||||
return err
|
||||
@@ -80,7 +80,7 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
logger.Successf("Alert resumed")
|
||||
|
||||
logger.Waitingf("waiting for Alert reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isAlertResumed(ctx, kubeClient, namespacedName, &alert)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,20 +17,9 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var resumeHrCmd = &cobra.Command{
|
||||
@@ -42,76 +31,24 @@ finish the apply.`,
|
||||
Example: ` # Resume reconciliation for an existing Helm release
|
||||
flux resume hr podinfo
|
||||
`,
|
||||
RunE: resumeHrCmdRun,
|
||||
RunE: resumeCommand{
|
||||
apiType: helmReleaseType,
|
||||
object: helmReleaseAdapter{&helmv2.HelmRelease{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeCmd.AddCommand(resumeHrCmd)
|
||||
}
|
||||
|
||||
func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("HelmRelease name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming HelmRelease %s in %s namespace", name, namespace)
|
||||
helmRelease.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease resumed")
|
||||
|
||||
logger.Waitingf("waiting for HelmRelease reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmReleaseResumed(ctx, kubeClient, namespacedName, &helmRelease)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease reconciliation completed")
|
||||
|
||||
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
|
||||
return nil
|
||||
func (obj helmReleaseAdapter) getObservedGeneration() int64 {
|
||||
return obj.HelmRelease.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, helmRelease *helmv2.HelmRelease) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, helmRelease)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if helmRelease.Generation != helmRelease.Status.ObservedGeneration {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
func (obj helmReleaseAdapter) setUnsuspended() {
|
||||
obj.HelmRelease.Spec.Suspend = false
|
||||
}
|
||||
|
||||
func (obj helmReleaseAdapter) successMessage() string {
|
||||
return fmt.Sprintf("applied revision %s", obj.Status.LastAppliedRevision)
|
||||
}
|
||||
|
||||
@@ -17,19 +17,10 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var resumeKsCmd = &cobra.Command{
|
||||
@@ -41,76 +32,24 @@ finish the apply.`,
|
||||
Example: ` # Resume reconciliation for an existing Kustomization
|
||||
flux resume ks podinfo
|
||||
`,
|
||||
RunE: resumeKsCmdRun,
|
||||
RunE: resumeCommand{
|
||||
apiType: kustomizationType,
|
||||
object: kustomizationAdapter{&kustomizev1.Kustomization{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeCmd.AddCommand(resumeKsCmd)
|
||||
}
|
||||
|
||||
func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("Kustomization name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming Kustomization %s in %s namespace", name, namespace)
|
||||
kustomization.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Kustomization resumed")
|
||||
|
||||
logger.Waitingf("waiting for Kustomization reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isKustomizationResumed(ctx, kubeClient, namespacedName, &kustomization)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Kustomization reconciliation completed")
|
||||
|
||||
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
|
||||
return nil
|
||||
func (obj kustomizationAdapter) getObservedGeneration() int64 {
|
||||
return obj.Kustomization.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func isKustomizationResumed(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, kustomization *kustomizev1.Kustomization) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, kustomization)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if kustomization.Generation != kustomization.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
func (obj kustomizationAdapter) setUnsuspended() {
|
||||
obj.Kustomization.Spec.Suspend = false
|
||||
}
|
||||
|
||||
func (obj kustomizationAdapter) successMessage() string {
|
||||
return fmt.Sprintf("applied revision %s", obj.Status.LastAppliedRevision)
|
||||
}
|
||||
|
||||
@@ -54,16 +54,16 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var receiver notificationv1.Receiver
|
||||
@@ -72,7 +72,7 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming Receiver %s in %s namespace", name, namespace)
|
||||
logger.Actionf("resuming Receiver %s in %s namespace", name, rootArgs.namespace)
|
||||
receiver.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &receiver); err != nil {
|
||||
return err
|
||||
@@ -80,7 +80,7 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
logger.Successf("Receiver resumed")
|
||||
|
||||
logger.Waitingf("waiting for Receiver reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
if err := wait.PollImmediate(rootArgs.pollInterval, rootArgs.timeout,
|
||||
isReceiverResumed(ctx, kubeClient, namespacedName, &receiver)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -17,20 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var resumeSourceBucketCmd = &cobra.Command{
|
||||
@@ -40,76 +28,20 @@ var resumeSourceBucketCmd = &cobra.Command{
|
||||
Example: ` # Resume reconciliation for an existing Bucket
|
||||
flux resume source bucket podinfo
|
||||
`,
|
||||
RunE: resumeSourceBucketCmdRun,
|
||||
RunE: resumeCommand{
|
||||
apiType: bucketType,
|
||||
object: &bucketAdapter{&sourcev1.Bucket{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeSourceCmd.AddCommand(resumeSourceBucketCmd)
|
||||
}
|
||||
|
||||
func resumeSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var bucket sourcev1.Bucket
|
||||
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||
bucket.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &bucket); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source resumed")
|
||||
|
||||
logger.Waitingf("waiting for Bucket reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isBucketResumed(ctx, kubeClient, namespacedName, &bucket)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("Bucket reconciliation completed")
|
||||
|
||||
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
|
||||
return nil
|
||||
func (obj bucketAdapter) getObservedGeneration() int64 {
|
||||
return obj.Bucket.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func isBucketResumed(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, bucket)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if bucket.Generation != bucket.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
func (obj bucketAdapter) setUnsuspended() {
|
||||
obj.Bucket.Spec.Suspend = false
|
||||
}
|
||||
|
||||
@@ -17,20 +17,10 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var resumeSourceHelmChartCmd = &cobra.Command{
|
||||
@@ -40,76 +30,24 @@ var resumeSourceHelmChartCmd = &cobra.Command{
|
||||
Example: ` # Resume reconciliation for an existing HelmChart
|
||||
flux resume source chart podinfo
|
||||
`,
|
||||
RunE: resumeSourceHelmChartCmdRun,
|
||||
RunE: resumeCommand{
|
||||
apiType: helmChartType,
|
||||
object: &helmChartAdapter{&sourcev1.HelmChart{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeSourceCmd.AddCommand(resumeSourceHelmChartCmd)
|
||||
}
|
||||
|
||||
func resumeSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.HelmChart
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||
repository.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source resumed")
|
||||
|
||||
logger.Waitingf("waiting for HelmChart reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmChartResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmChart reconciliation completed")
|
||||
|
||||
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||
return nil
|
||||
func (obj helmChartAdapter) getObservedGeneration() int64 {
|
||||
return obj.HelmChart.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func isHelmChartResumed(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, chart *sourcev1.HelmChart) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, chart)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if chart.Generation != chart.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(chart.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
func (obj helmChartAdapter) setUnsuspended() {
|
||||
obj.HelmChart.Spec.Suspend = false
|
||||
}
|
||||
|
||||
func (obj helmChartAdapter) successMessage() string {
|
||||
return fmt.Sprintf("fetched revision %s", obj.Status.Artifact.Revision)
|
||||
}
|
||||
|
||||
@@ -17,20 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var resumeSourceGitCmd = &cobra.Command{
|
||||
@@ -40,76 +28,20 @@ var resumeSourceGitCmd = &cobra.Command{
|
||||
Example: ` # Resume reconciliation for an existing GitRepository
|
||||
flux resume source git podinfo
|
||||
`,
|
||||
RunE: resumeSourceGitCmdRun,
|
||||
RunE: resumeCommand{
|
||||
apiType: gitRepositoryType,
|
||||
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeSourceCmd.AddCommand(resumeSourceGitCmd)
|
||||
}
|
||||
|
||||
func resumeSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.GitRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||
repository.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source resumed")
|
||||
|
||||
logger.Waitingf("waiting for GitRepository reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isGitRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("GitRepository reconciliation completed")
|
||||
|
||||
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||
return nil
|
||||
func (obj gitRepositoryAdapter) getObservedGeneration() int64 {
|
||||
return obj.GitRepository.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func isGitRepositoryResumed(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if repository.Generation != repository.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(repository.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
func (obj gitRepositoryAdapter) setUnsuspended() {
|
||||
obj.GitRepository.Spec.Suspend = false
|
||||
}
|
||||
|
||||
@@ -17,20 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var resumeSourceHelmCmd = &cobra.Command{
|
||||
@@ -40,76 +28,20 @@ var resumeSourceHelmCmd = &cobra.Command{
|
||||
Example: ` # Resume reconciliation for an existing HelmRepository
|
||||
flux resume source helm bitnami
|
||||
`,
|
||||
RunE: resumeSourceHelmCmdRun,
|
||||
RunE: resumeCommand{
|
||||
apiType: helmRepositoryType,
|
||||
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeSourceCmd.AddCommand(resumeSourceHelmCmd)
|
||||
}
|
||||
|
||||
func resumeSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.HelmRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||
repository.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source resumed")
|
||||
|
||||
logger.Waitingf("waiting for HelmRepository reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRepository reconciliation completed")
|
||||
|
||||
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||
return nil
|
||||
func (obj helmRepositoryAdapter) getObservedGeneration() int64 {
|
||||
return obj.HelmRepository.Status.ObservedGeneration
|
||||
}
|
||||
|
||||
func isHelmRepositoryResumed(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Confirm the state we are observing is for the current generation
|
||||
if repository.Generation != repository.Status.ObservedGeneration {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c := apimeta.FindStatusCondition(repository.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||
switch c.Status {
|
||||
case metav1.ConditionTrue:
|
||||
return true, nil
|
||||
case metav1.ConditionFalse:
|
||||
return false, fmt.Errorf(c.Message)
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
func (obj helmRepositoryAdapter) setUnsuspended() {
|
||||
obj.HelmRepository.Spec.Suspend = false
|
||||
}
|
||||
|
||||
143
cmd/flux/source.go
Normal file
143
cmd/flux/source.go
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright 2021 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
// These are general-purpose adapters for attaching methods to, for
|
||||
// the various commands. The *List adapters implement len(), since
|
||||
// it's used in at least a couple of commands.
|
||||
|
||||
// sourcev1.Bucket
|
||||
|
||||
var bucketType = apiType{
|
||||
kind: sourcev1.BucketKind,
|
||||
humanKind: "source bucket",
|
||||
}
|
||||
|
||||
type bucketAdapter struct {
|
||||
*sourcev1.Bucket
|
||||
}
|
||||
|
||||
func (a bucketAdapter) asClientObject() client.Object {
|
||||
return a.Bucket
|
||||
}
|
||||
|
||||
// sourcev1.BucketList
|
||||
|
||||
type bucketListAdapter struct {
|
||||
*sourcev1.BucketList
|
||||
}
|
||||
|
||||
func (a bucketListAdapter) asClientList() client.ObjectList {
|
||||
return a.BucketList
|
||||
}
|
||||
|
||||
func (a bucketListAdapter) len() int {
|
||||
return len(a.BucketList.Items)
|
||||
}
|
||||
|
||||
// sourcev1.HelmChart
|
||||
|
||||
var helmChartType = apiType{
|
||||
kind: sourcev1.HelmChartKind,
|
||||
humanKind: "source chart",
|
||||
}
|
||||
|
||||
type helmChartAdapter struct {
|
||||
*sourcev1.HelmChart
|
||||
}
|
||||
|
||||
func (a helmChartAdapter) asClientObject() client.Object {
|
||||
return a.HelmChart
|
||||
}
|
||||
|
||||
// sourcev1.ImagePolicyList
|
||||
|
||||
type helmChartListAdapter struct {
|
||||
*sourcev1.HelmChartList
|
||||
}
|
||||
|
||||
func (a helmChartListAdapter) asClientList() client.ObjectList {
|
||||
return a.HelmChartList
|
||||
}
|
||||
|
||||
func (a helmChartListAdapter) len() int {
|
||||
return len(a.HelmChartList.Items)
|
||||
}
|
||||
|
||||
// sourcev1.GitRepository
|
||||
|
||||
var gitRepositoryType = apiType{
|
||||
kind: sourcev1.GitRepositoryKind,
|
||||
humanKind: "source git",
|
||||
}
|
||||
|
||||
type gitRepositoryAdapter struct {
|
||||
*sourcev1.GitRepository
|
||||
}
|
||||
|
||||
func (a gitRepositoryAdapter) asClientObject() client.Object {
|
||||
return a.GitRepository
|
||||
}
|
||||
|
||||
// sourcev1.GitRepositoryList
|
||||
|
||||
type gitRepositoryListAdapter struct {
|
||||
*sourcev1.GitRepositoryList
|
||||
}
|
||||
|
||||
func (a gitRepositoryListAdapter) asClientList() client.ObjectList {
|
||||
return a.GitRepositoryList
|
||||
}
|
||||
|
||||
func (a gitRepositoryListAdapter) len() int {
|
||||
return len(a.GitRepositoryList.Items)
|
||||
}
|
||||
|
||||
// sourcev1.HelmRepository
|
||||
|
||||
var helmRepositoryType = apiType{
|
||||
kind: sourcev1.HelmRepositoryKind,
|
||||
humanKind: "source helm",
|
||||
}
|
||||
|
||||
type helmRepositoryAdapter struct {
|
||||
*sourcev1.HelmRepository
|
||||
}
|
||||
|
||||
func (a helmRepositoryAdapter) asClientObject() client.Object {
|
||||
return a.HelmRepository
|
||||
}
|
||||
|
||||
// sourcev1.HelmRepositoryList
|
||||
|
||||
type helmRepositoryListAdapter struct {
|
||||
*sourcev1.HelmRepositoryList
|
||||
}
|
||||
|
||||
func (a helmRepositoryListAdapter) asClientList() client.ObjectList {
|
||||
return a.HelmRepositoryList
|
||||
}
|
||||
|
||||
func (a helmRepositoryListAdapter) len() int {
|
||||
return len(a.HelmRepositoryList.Items)
|
||||
}
|
||||
@@ -42,7 +42,7 @@ type statusable interface {
|
||||
func isReady(ctx context.Context, kubeClient client.Client,
|
||||
namespacedName types.NamespacedName, object statusable) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
err := kubeClient.Get(ctx, namespacedName, object.asRuntimeObject())
|
||||
err := kubeClient.Get(ctx, namespacedName, object.asClientObject())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -53,26 +53,26 @@ func (suspend suspendCommand) run(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
err = kubeClient.Get(ctx, namespacedName, suspend.object.asRuntimeObject())
|
||||
err = kubeClient.Get(ctx, namespacedName, suspend.object.asClientObject())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, name, namespace)
|
||||
logger.Actionf("suspending %s %s in %s namespace", suspend.humanKind, name, rootArgs.namespace)
|
||||
suspend.object.setSuspended()
|
||||
if err := kubeClient.Update(ctx, suspend.object.asRuntimeObject()); err != nil {
|
||||
if err := kubeClient.Update(ctx, suspend.object.asClientObject()); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("%s suspended", suspend.humanKind)
|
||||
|
||||
@@ -47,16 +47,16 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var alert notificationv1.Alert
|
||||
@@ -65,7 +65,7 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending Alert %s in %s namespace", name, namespace)
|
||||
logger.Actionf("suspending Alert %s in %s namespace", name, rootArgs.namespace)
|
||||
alert.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &alert); err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,14 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var suspendHrCmd = &cobra.Command{
|
||||
@@ -35,43 +29,20 @@ var suspendHrCmd = &cobra.Command{
|
||||
Example: ` # Suspend reconciliation for an existing Helm release
|
||||
flux suspend hr podinfo
|
||||
`,
|
||||
RunE: suspendHrCmdRun,
|
||||
RunE: suspendCommand{
|
||||
apiType: helmReleaseType,
|
||||
object: &helmReleaseAdapter{&helmv2.HelmRelease{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendCmd.AddCommand(suspendHrCmd)
|
||||
}
|
||||
|
||||
func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("HelmRelease name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending HelmRelease %s in %s namespace", name, namespace)
|
||||
helmRelease.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease suspended")
|
||||
|
||||
return nil
|
||||
func (obj helmReleaseAdapter) isSuspended() bool {
|
||||
return obj.HelmRelease.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj helmReleaseAdapter) setSuspended() {
|
||||
obj.HelmRelease.Spec.Suspend = true
|
||||
}
|
||||
|
||||
@@ -17,13 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var suspendKsCmd = &cobra.Command{
|
||||
@@ -34,43 +29,20 @@ var suspendKsCmd = &cobra.Command{
|
||||
Example: ` # Suspend reconciliation for an existing Kustomization
|
||||
flux suspend ks podinfo
|
||||
`,
|
||||
RunE: suspendKsCmdRun,
|
||||
RunE: suspendCommand{
|
||||
apiType: kustomizationType,
|
||||
object: kustomizationAdapter{&kustomizev1.Kustomization{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendCmd.AddCommand(suspendKsCmd)
|
||||
}
|
||||
|
||||
func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("kustomization name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending kustomization %s in %s namespace", name, namespace)
|
||||
kustomization.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("kustomization suspended")
|
||||
|
||||
return nil
|
||||
func (obj kustomizationAdapter) isSuspended() bool {
|
||||
return obj.Kustomization.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj kustomizationAdapter) setSuspended() {
|
||||
obj.Kustomization.Spec.Suspend = true
|
||||
}
|
||||
|
||||
@@ -47,16 +47,16 @@ func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
var receiver notificationv1.Receiver
|
||||
@@ -65,7 +65,7 @@ func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending Receiver %s in %s namespace", name, namespace)
|
||||
logger.Actionf("suspending Receiver %s in %s namespace", name, rootArgs.namespace)
|
||||
receiver.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &receiver); err != nil {
|
||||
return err
|
||||
|
||||
@@ -17,13 +17,8 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var suspendSourceBucketCmd = &cobra.Command{
|
||||
@@ -33,43 +28,20 @@ var suspendSourceBucketCmd = &cobra.Command{
|
||||
Example: ` # Suspend reconciliation for an existing Bucket
|
||||
flux suspend source bucket podinfo
|
||||
`,
|
||||
RunE: suspendSourceBucketCmdRun,
|
||||
RunE: suspendCommand{
|
||||
apiType: bucketType,
|
||||
object: bucketAdapter{&sourcev1.Bucket{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendSourceCmd.AddCommand(suspendSourceBucketCmd)
|
||||
}
|
||||
|
||||
func suspendSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var bucket sourcev1.Bucket
|
||||
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||
bucket.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &bucket); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source suspended")
|
||||
|
||||
return nil
|
||||
func (obj bucketAdapter) isSuspended() bool {
|
||||
return obj.Bucket.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj bucketAdapter) setSuspended() {
|
||||
obj.Bucket.Spec.Suspend = true
|
||||
}
|
||||
|
||||
@@ -17,13 +17,9 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var suspendSourceHelmChartCmd = &cobra.Command{
|
||||
@@ -33,43 +29,20 @@ var suspendSourceHelmChartCmd = &cobra.Command{
|
||||
Example: ` # Suspend reconciliation for an existing HelmChart
|
||||
flux suspend source chart podinfo
|
||||
`,
|
||||
RunE: suspendSourceHelmChartCmdRun,
|
||||
RunE: suspendCommand{
|
||||
apiType: helmChartType,
|
||||
object: helmChartAdapter{&sourcev1.HelmChart{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendSourceCmd.AddCommand(suspendSourceHelmChartCmd)
|
||||
}
|
||||
|
||||
func suspendSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var chart sourcev1.HelmChart
|
||||
err = kubeClient.Get(ctx, namespacedName, &chart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||
chart.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &chart); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source suspended")
|
||||
|
||||
return nil
|
||||
func (obj helmChartAdapter) isSuspended() bool {
|
||||
return obj.HelmChart.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj helmChartAdapter) setSuspended() {
|
||||
obj.HelmChart.Spec.Suspend = true
|
||||
}
|
||||
|
||||
@@ -17,13 +17,9 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var suspendSourceGitCmd = &cobra.Command{
|
||||
@@ -33,43 +29,20 @@ var suspendSourceGitCmd = &cobra.Command{
|
||||
Example: ` # Suspend reconciliation for an existing GitRepository
|
||||
flux suspend source git podinfo
|
||||
`,
|
||||
RunE: suspendSourceGitCmdRun,
|
||||
RunE: suspendCommand{
|
||||
apiType: gitRepositoryType,
|
||||
object: gitRepositoryAdapter{&sourcev1.GitRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendSourceCmd.AddCommand(suspendSourceGitCmd)
|
||||
}
|
||||
|
||||
func suspendSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.GitRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||
repository.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source suspended")
|
||||
|
||||
return nil
|
||||
func (obj gitRepositoryAdapter) isSuspended() bool {
|
||||
return obj.GitRepository.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj gitRepositoryAdapter) setSuspended() {
|
||||
obj.GitRepository.Spec.Suspend = true
|
||||
}
|
||||
|
||||
@@ -17,13 +17,9 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var suspendSourceHelmCmd = &cobra.Command{
|
||||
@@ -33,43 +29,20 @@ var suspendSourceHelmCmd = &cobra.Command{
|
||||
Example: ` # Suspend reconciliation for an existing HelmRepository
|
||||
flux suspend source helm bitnami
|
||||
`,
|
||||
RunE: suspendSourceHelmCmdRun,
|
||||
RunE: suspendCommand{
|
||||
apiType: helmRepositoryType,
|
||||
object: helmRepositoryAdapter{&sourcev1.HelmRepository{}},
|
||||
}.run,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendSourceCmd.AddCommand(suspendSourceHelmCmd)
|
||||
}
|
||||
|
||||
func suspendSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.HelmRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||
repository.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source suspended")
|
||||
|
||||
return nil
|
||||
func (obj helmRepositoryAdapter) isSuspended() bool {
|
||||
return obj.HelmRepository.Spec.Suspend
|
||||
}
|
||||
|
||||
func (obj helmRepositoryAdapter) setSuspended() {
|
||||
obj.HelmRepository.Spec.Suspend = true
|
||||
}
|
||||
|
||||
@@ -45,38 +45,40 @@ var uninstallCmd = &cobra.Command{
|
||||
RunE: uninstallCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
uninstallCRDs bool
|
||||
uninstallResources bool
|
||||
uninstallDryRun bool
|
||||
uninstallSilent bool
|
||||
)
|
||||
type uninstallFlags struct {
|
||||
crds bool
|
||||
resources bool
|
||||
dryRun bool
|
||||
silent bool
|
||||
}
|
||||
|
||||
var uninstallArgs uninstallFlags
|
||||
|
||||
func init() {
|
||||
uninstallCmd.Flags().BoolVar(&uninstallResources, "resources", true,
|
||||
uninstallCmd.Flags().BoolVar(&uninstallArgs.resources, "resources", true,
|
||||
"removes custom resources such as Kustomizations, GitRepositories and HelmRepositories")
|
||||
uninstallCmd.Flags().BoolVar(&uninstallCRDs, "crds", false,
|
||||
uninstallCmd.Flags().BoolVar(&uninstallArgs.crds, "crds", false,
|
||||
"removes all CRDs previously installed")
|
||||
uninstallCmd.Flags().BoolVar(&uninstallDryRun, "dry-run", false,
|
||||
uninstallCmd.Flags().BoolVar(&uninstallArgs.dryRun, "dry-run", false,
|
||||
"only print the object that would be deleted")
|
||||
uninstallCmd.Flags().BoolVarP(&uninstallSilent, "silent", "s", false,
|
||||
uninstallCmd.Flags().BoolVarP(&uninstallArgs.silent, "silent", "s", false,
|
||||
"delete components without asking for confirmation")
|
||||
|
||||
rootCmd.AddCommand(uninstallCmd)
|
||||
}
|
||||
|
||||
func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !uninstallDryRun && !uninstallSilent {
|
||||
if !uninstallArgs.dryRun && !uninstallArgs.silent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: fmt.Sprintf("Are you sure you want to delete the %s namespace", namespace),
|
||||
Label: fmt.Sprintf("Are you sure you want to delete the %s namespace", rootArgs.namespace),
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
@@ -85,7 +87,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
dryRun := "--dry-run=server"
|
||||
deleteResources := uninstallResources || uninstallCRDs
|
||||
deleteResources := uninstallArgs.resources || uninstallArgs.crds
|
||||
|
||||
// known kinds with finalizers
|
||||
namespacedKinds := []string{
|
||||
@@ -96,8 +98,8 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// suspend bootstrap kustomization to avoid finalizers deadlock
|
||||
kustomizationName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: namespace,
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: rootArgs.namespace,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
err = kubeClient.Get(ctx, kustomizationName, &kustomization)
|
||||
@@ -113,21 +115,21 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// add HelmRelease kind to deletion list if exists
|
||||
var list helmv2.HelmReleaseList
|
||||
if err := kubeClient.List(ctx, &list, client.InNamespace(namespace)); err == nil {
|
||||
if err := kubeClient.List(ctx, &list, client.InNamespace(rootArgs.namespace)); err == nil {
|
||||
namespacedKinds = append(namespacedKinds, helmv2.HelmReleaseKind)
|
||||
}
|
||||
|
||||
if deleteResources {
|
||||
logger.Actionf("uninstalling custom resources")
|
||||
for _, kind := range namespacedKinds {
|
||||
if err := deleteAll(ctx, kind, uninstallDryRun); err != nil {
|
||||
if err := deleteAll(ctx, kind, uninstallArgs.dryRun); err != nil {
|
||||
logger.Failuref("kubectl: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var kinds []string
|
||||
if uninstallCRDs {
|
||||
if uninstallArgs.crds {
|
||||
kinds = append(kinds, "crds")
|
||||
}
|
||||
|
||||
@@ -138,13 +140,13 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
||||
for _, kind := range kinds {
|
||||
kubectlArgs := []string{
|
||||
"delete", kind,
|
||||
"-l", fmt.Sprintf("app.kubernetes.io/instance=%s", namespace),
|
||||
"--ignore-not-found", "--timeout", timeout.String(),
|
||||
"-l", fmt.Sprintf("app.kubernetes.io/instance=%s", rootArgs.namespace),
|
||||
"--ignore-not-found", "--timeout", rootArgs.timeout.String(),
|
||||
}
|
||||
if uninstallDryRun {
|
||||
if uninstallArgs.dryRun {
|
||||
kubectlArgs = append(kubectlArgs, dryRun)
|
||||
}
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...); err != nil {
|
||||
return fmt.Errorf("uninstall failed: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -157,13 +159,13 @@ func deleteAll(ctx context.Context, kind string, dryRun bool) error {
|
||||
kubectlArgs := []string{
|
||||
"delete", kind, "--ignore-not-found",
|
||||
"--all", "--all-namespaces",
|
||||
"--timeout", timeout.String(),
|
||||
"--timeout", rootArgs.timeout.String(),
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
kubectlArgs = append(kubectlArgs, "--dry-run=server")
|
||||
}
|
||||
|
||||
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...)
|
||||
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, rootArgs.kubeconfig, rootArgs.kubecontext, kubectlArgs...)
|
||||
return err
|
||||
}
|
||||
|
||||
BIN
docs/_files/commit-status-flow.png
Normal file
BIN
docs/_files/commit-status-flow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
docs/_files/commit-status-github-failure.png
Normal file
BIN
docs/_files/commit-status-github-failure.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/_files/commit-status-github-overview.png
Normal file
BIN
docs/_files/commit-status-github-overview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/_files/commit-status-github-success.png
Normal file
BIN
docs/_files/commit-status-github-success.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
docs/_files/commit-status-gitlab-failure.png
Normal file
BIN
docs/_files/commit-status-gitlab-failure.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/_files/commit-status-gitlab-success.png
Normal file
BIN
docs/_files/commit-status-gitlab-success.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user