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

Compare commits

..

86 Commits

Author SHA1 Message Date
Stefan Prodan
13dba62b8d Merge pull request #128 from fluxcd/container-registry
Add container registry and image pull secret as install options
2020-07-23 15:34:27 +03:00
stefanprodan
c2ff169c08 Add image pull secret arg to install/bootstrap 2020-07-23 13:38:32 +03:00
stefanprodan
57a1dbfc6d Add container registry option to install/bootstrap 2020-07-23 13:07:34 +03:00
Stefan Prodan
efb39d6fc6 Merge pull request #127 from fluxcd/node-selector
Add linux/amd64 node selector to controllers
2020-07-23 12:44:34 +03:00
Stefan Prodan
b784234430 Merge pull request #126 from fluxcd/uninstall-crs
Delete custom resources during uninstall
2020-07-23 12:44:18 +03:00
stefanprodan
aebad92426 Add linux/amd64 node selector to controllers
Set nodeSelector to linux/amd64 for clusters with mixed nodes (linux, windows, amd64, arm).
2020-07-23 09:59:45 +03:00
stefanprodan
8e67cfd5c9 Delete custom resources during uninstall
Remove Kustomizations, GitRepositories and HelmRepositories before deleting the toolkit controllers and CRDs.
2020-07-23 09:26:10 +03:00
Stefan Prodan
10cc6d7e08 Merge pull request #124 from fluxcd/helm-beta.4
Update helm-controller to v0.0.1-beta.4
2020-07-22 16:49:11 +03:00
stefanprodan
83c236c829 Update helm-controller to v0.0.1-beta.4 2020-07-22 16:36:59 +03:00
Stefan Prodan
b6ab37691f Merge pull request #120 from fluxcd/sealed-secrets
Add sealed secrets guide
2020-07-22 15:45:00 +03:00
stefanprodan
c85af78025 Add sealed secrets guide 2020-07-22 14:43:55 +03:00
Stefan Prodan
2c2fc6dd97 Merge pull request #123 from fluxcd/optional-notifications
Make notification component optional
2020-07-22 14:41:40 +03:00
stefanprodan
3620b76139 Make notification component optional 2020-07-22 14:30:39 +03:00
Stefan Prodan
ca5732e586 Merge pull request #121 from fluxcd/helm-beta.3
Update helm-controller to v0.0.1-beta.3
2020-07-21 20:31:31 +03:00
stefanprodan
2463d72f3b Update helm-controller to v0.0.1-beta.3 2020-07-21 20:18:23 +03:00
stefanprodan
d6f7474200 Add get/export HelmRelease e2e tests 2020-07-21 14:25:31 +03:00
stefanprodan
0b2bc7ab3f Implement get/export HelmRelease for Helm releases 2020-07-21 14:22:20 +03:00
Stefan Prodan
0a4fac61d4 Merge pull request #118 from fluxcd/hr-cmd
Implement create/delete for Helm releases
2020-07-21 14:10:45 +03:00
stefanprodan
797aec5528 Add create/delete HelmRelease e2e tests 2020-07-21 14:02:29 +03:00
stefanprodan
5f0b95dc59 Implement create/delete for Helm releases 2020-07-21 12:20:41 +03:00
Stefan Prodan
b384c5f14c Merge pull request #116 from fluxcd/helm-repo-cmd
Implement Helm repository commands
2020-07-21 11:09:31 +03:00
stefanprodan
5254dca9d9 Add Helm repository cmd docs 2020-07-21 10:42:05 +03:00
stefanprodan
8534ccbf37 Implement Helm repository commands 2020-07-21 10:39:17 +03:00
stefanprodan
9af874d810 Add examples to all tk commands 2020-07-21 10:38:44 +03:00
Stefan Prodan
4e3dee15ce Merge pull request #114 from fluxcd/fix-kustomize-cmd
Rename kustomization arg from validate to validation
2020-07-20 15:30:00 +03:00
stefanprodan
aaad618e20 Rename kustomization arg from validate to validation
Fix `tk create kustomization` command args inconsistency with the Kustomize API
2020-07-20 15:10:33 +03:00
Stefan Prodan
10bb50bd82 Merge pull request #113 from fluxcd/crd-v1
Drop support for Kubernetes <1.16
2020-07-20 14:56:45 +03:00
stefanprodan
6d2ff6e019 Update controllers and APIs 2020-07-20 14:41:23 +03:00
stefanprodan
670070a879 Drop support for Kubernetes <1.16 2020-07-20 14:37:50 +03:00
Stefan Prodan
dcec8007d4 Merge pull request #88 from luxas/go_git_provider
Add go-git-providers proposal
2020-07-20 11:53:36 +03:00
Michael Bridgen
3abf4a49cd Merge pull request #108 from fluxcd/link-to-image-update-discussion
Link to image update discussion
2020-07-17 13:03:03 +01:00
Michael Bridgen
38825bf96a Cosmetic: indent sublist 2020-07-17 12:55:24 +01:00
Michael Bridgen
faa69da28d Link to image update discussion
.. and rearrange the line items a little. I removed the mention of source-controller because it doesn't feature in the design as drafted.
2020-07-17 12:08:42 +01:00
Hidde Beydals
5cf524e2fd Merge pull request #106 from fluxcd/docs/update-helm-roadmap
Make nested list work correctly in roadmap
2020-07-17 12:45:44 +02:00
Hidde Beydals
88802a44e7 Make nested list work correctly in roadmap 2020-07-17 12:34:16 +02:00
Stefan Prodan
94498d862d Merge pull request #105 from fluxcd/static-manifests
Use semver manifests as kustomize base
2020-07-17 13:27:51 +03:00
Hidde Beydals
9418b24e8f Merge pull request #104 from fluxcd/docs/update-helm-roadmap
Update "Helm Operator v2" roadmap
2020-07-17 12:11:57 +02:00
stefanprodan
b92cbcd7e7 Use semver manifests as kustomize base
Instead of cloning the components repositories to download the base manifests, we build them in CI at release time and download them in tk install/bootstrap based on the provided semver. This speeds up the manifests generation from minutes to milliseconds.
2020-07-17 13:10:19 +03:00
Hidde Beydals
9ef2ff92df Update "Helm Operator v2" roadmap 2020-07-17 12:04:09 +02:00
stefanprodan
422724bd2d Publish manifests as release assets 2020-07-17 12:00:15 +03:00
Stefan Prodan
6cb7897f25 Merge pull request #99 from fluxcd/export-install-manifests
Add export option to tk install
2020-07-16 16:07:13 +03:00
stefanprodan
499ba15004 Add export option to tk install 2020-07-16 15:56:05 +03:00
Stefan Prodan
b04abe989e Merge pull request #97 from fluxcd/helm-webhooks
Add webhook receivers section to Helm guide
2020-07-16 12:46:49 +03:00
stefanprodan
ea576179f9 Add webhook receivers section to Helm guide 2020-07-16 12:39:53 +03:00
Stefan Prodan
116d53a978 Merge pull request #95 from fluxcd/docs/helm-controller-notifications
Document helm-controller notifications in guide
2020-07-16 11:56:15 +03:00
Stefan Prodan
32adbf2ec8 Merge pull request #96 from fluxcd/prep-release-v0.0.5
Update controllers and go modules
2020-07-16 11:39:36 +03:00
stefanprodan
c664484fda Update controllers and go modules
- update source-controller to v0.0.5
- update kustomize-controller to v0.0.4
- update notification-controller to v0.0.4
- update helm-controller to v0.0.1-alpha.2
2020-07-16 11:30:45 +03:00
Hidde Beydals
06906eba4c Document helm-controller notifications in guide 2020-07-16 09:50:59 +02:00
Hidde Beydals
d387ebf32d Merge pull request #92 from fluxcd/docs/helmrelease-guide
Add "Manging Helm releases" guide to menu
2020-07-14 16:12:00 +02:00
Hidde Beydals
f75556f33c Add "Manging Helm releases" guide to menu 2020-07-14 16:05:48 +02:00
Hidde Beydals
2cf09e4de6 Merge pull request #86 from fluxcd/docs/helmrelease-guide 2020-07-14 16:02:50 +02:00
Hidde Beydals
a5a3a9c586 Make existence of HelmChart visible 2020-07-14 15:55:23 +02:00
Hidde Beydals
746dfbd955 Managing Helm releases guide 2020-07-14 15:55:19 +02:00
Lucas Käldström
b1993d2fb7 Add Reconcile methods and TeamAccess struct. Mention ErrNotFound and ErrAlreadyExists. Add List() to TeamAccess. Rename GetTitle() to GetName() 2020-07-14 16:39:31 +03:00
Lucas Käldström
e8096dec88 Rename the Repository Teams and Credential clients 2020-07-14 16:39:25 +03:00
Lucas Käldström
39eee51ec8 Add extra goals of best practices 2020-07-14 16:39:14 +03:00
Lucas Käldström
7bb3a10795 Remove the URLParser, and Provider from the *Ref types 2020-07-14 16:39:02 +03:00
Stefan Prodan
a8cbe4b05f Merge pull request #91 from fluxcd/notification-v0.0.3
Update notification-controller to v0.0.3
2020-07-14 15:36:02 +03:00
stefanprodan
fe86da0cde Update notification-controller to v0.0.3 2020-07-14 15:26:10 +03:00
Stefan Prodan
4c86a2c191 Merge pull request #90 from fluxcd/helm-suspend
Add helm suspend/resume commands
2020-07-14 15:05:21 +03:00
stefanprodan
8dc5db17ac Add helm suspend/resume commands 2020-07-14 14:00:59 +03:00
Stefan Prodan
549c3a190e Merge pull request #87 from fluxcd/helm-reconcile
Add reconcile helm commands
2020-07-14 13:40:41 +03:00
stefanprodan
7a68c4ccf3 Add reconcile helm commands 2020-07-14 13:34:00 +03:00
Lucas Käldström
4c684df653 Add go-git-providers proposal 2020-07-14 12:49:29 +03:00
Stefan Prodan
bf8831b833 Merge pull request #85 from fluxcd/reconcile-cmd
Rename sync cmd to reconcile
2020-07-14 11:58:38 +03:00
stefanprodan
394227571f Rename sync cmd to reconcile 2020-07-14 11:45:15 +03:00
Stefan Prodan
bf67577073 Merge pull request #84 from fluxcd/default-components
Refactor install defaults
2020-07-14 11:19:31 +03:00
stefanprodan
e180611024 Refactor defaults
- add dedicated components flag for bootstrap/install/check
- extract defaults to vars
- update CLI docs
2020-07-14 11:02:37 +03:00
Hidde Beydals
43cfc55368 Merge pull request #83 from fluxcd/build/hc-api-spec
build: use correct v2alpha1 HelmRelease spec URL
2020-07-14 09:29:28 +02:00
Hidde Beydals
c03b7ea15d build: use correct v2alpha1 HelmRelease spec URL 2020-07-14 09:22:51 +02:00
Stefan Prodan
ddfedfb590 Merge pull request #82 from fluxcd/helm-controller
Add helm-controller installer and docs
2020-07-14 10:12:09 +03:00
stefanprodan
24418370f1 Add helm-controller docs 2020-07-14 09:33:52 +03:00
stefanprodan
02521b6964 Add helm-controller to installer 2020-07-13 18:44:54 +03:00
Stefan Prodan
16f693148b Merge pull request #81 from fluxcd/docs-source-watcher
Add source watcher dev guide
2020-07-09 09:17:51 +03:00
stefanprodan
0bf46cb63f Add source watcher dev guide 2020-07-08 17:23:09 +03:00
Stefan Prodan
2e38855396 Merge pull request #80 from fluxcd/docs-webhook-receivers
Add webhook receivers guide to docs
2020-07-07 13:20:38 +03:00
stefanprodan
97592a1387 Add webhook receivers guide to docs 2020-07-07 13:15:24 +03:00
Stefan Prodan
c61bf76c80 Merge pull request #79 from fluxcd/notification-controller-v0.0.1
Update notification controller to v0.0.1
2020-07-07 10:13:34 +03:00
stefanprodan
e95b137011 Mark events forwarding task as completed 2020-07-07 10:04:42 +03:00
stefanprodan
ad655183e0 Update notification-controller to v0.0.1 2020-07-07 10:03:34 +03:00
stefanprodan
789fd34c4a Update fluxcd/pkg to v0.0.2 2020-07-07 10:02:54 +03:00
Daniel Holbach
87bbbaa475 Merge pull request #77 from dholbach/understanding-toolkit
explain a bit more about Flux Toolkit
2020-07-03 14:18:06 +02:00
Daniel Holbach
a4ca813cf5 add symlink and make it work 2020-07-03 14:09:30 +02:00
Daniel Holbach
e8eef73212 explain a bit more about Flux Toolkit 2020-07-03 11:40:59 +02:00
Stefan Prodan
512d4a43cb Merge pull request #76 from fluxcd/source-events
Enable notifications for source events
2020-07-03 11:29:41 +03:00
stefanprodan
b9f7b1d175 Enable notifications for source events 2020-07-03 11:15:34 +03:00
114 changed files with 4477 additions and 651 deletions

View File

@@ -14,16 +14,29 @@ jobs:
uses: actions/checkout@v1
- name: Copy assets
run: |
cp install/tk.sh docs/install.sh
# source-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/api/source.md > docs/components/source/api.md
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/gitrepositories.md > docs/components/source/gitrepositories.md
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/helmrepositories.md > docs/components/source/helmrepositories.md
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/helmcharts.md > docs/components/source/helmcharts.md
# kustomize-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/kustomize-controller/master/docs/api/kustomize.md > docs/components/kustomize/api.md
curl https://raw.githubusercontent.com/fluxcd/kustomize-controller/master/docs/spec/v1alpha1/kustomization.md > docs/components/kustomize/kustomization.md
# helm-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/helm-controller/master/docs/api/helmrelease.md > docs/components/helm/api.md
curl https://raw.githubusercontent.com/fluxcd/helm-controller/master/docs/spec/v2alpha1/helmreleases.md > docs/components/helm/helmreleases.md
# notification-controller CRDs
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/api/notification.md > docs/components/notification/api.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/event.md > docs/components/notification/event.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/alert.md > docs/components/notification/alert.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/provider.md > docs/components/notification/provider.md
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/receiver.md > docs/components/notification/receiver.md
# install script
cp install/tk.sh docs/install.sh
- name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@master
env:

View File

@@ -24,7 +24,9 @@ jobs:
with:
go-version: 1.14.x
- name: Setup Kubernetes
uses: engineerd/setup-kind@v0.3.0
uses: engineerd/setup-kind@v0.4.0
with:
image: kindest/node:v1.16.9
- name: Run test
run: make test
- name: Check if working tree is dirty
@@ -63,13 +65,13 @@ jobs:
--path="./deploy/overlays/dev" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--health-check="Deployment/frontend.dev" \
--health-check="Deployment/backend.dev" \
--health-check-timeout=3m
- name: tk sync kustomization --with-source
run: |
./bin/tk sync kustomization podinfo --with-source
./bin/tk reconcile kustomization podinfo --with-source
- name: tk get kustomizations
run: |
./bin/tk get kustomizations
@@ -89,6 +91,29 @@ jobs:
- name: tk delete source git
run: |
./bin/tk delete source git podinfo --silent
- name: tk create source helm
run: |
./bin/tk create source helm podinfo \
--url https://stefanprodan.github.io/podinfo
- name: tk create helmrelease
run: |
./bin/tk create hr podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=">4.0.0 <5.0.0"
- name: tk get helmreleases
run: |
./bin/tk get helmreleases
- name: tk export helmrelease
run: |
./bin/tk export hr --all
- name: tk delete helmrelease
run: |
./bin/tk delete hr podinfo --silent
- name: tk delete source helm
run: |
./bin/tk delete source helm podinfo --silent
- name: tk check
run: |
./bin/tk check

View File

@@ -14,7 +14,7 @@ jobs:
- name: Unshallow
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@v2-beta
uses: actions/setup-go@v2
with:
go-version: 1.14.x
- name: Download release notes utility
@@ -25,10 +25,60 @@ jobs:
run: |
echo 'CHANGELOG' > /tmp/release.txt
github-release-notes -org fluxcd -repo toolkit -since-latest-release >> /tmp/release.txt
- name: Setup Kustomize
uses: ./.github/actions/kustomize
- name: Generate manifests tarball
run: |
mkdir -p ./output
files=""
# build controllers
for controller in ./manifests/bases/*/; do
output_path="./output/$(basename $controller).yaml"
echo "building $controller to $output_path"
kustomize build $controller > $output_path
files+=" $(basename $output_path)"
done
# build rbac
rbac_path="./manifests/rbac"
rbac_output_path="./output/rbac.yaml"
echo "building $rbac_path to $rbac_output_path"
kustomize build $rbac_path > $rbac_output_path
files+=" $(basename $rbac_output_path)"
# build policies
policies_path="./manifests/policies"
policies_output_path="./output/policies.yaml"
echo "building $policies_path to $policies_output_path"
kustomize build $policies_path > $policies_output_path
files+=" $(basename $policies_output_path)"
# create tarball
cd ./output && tar -cvzf manifests.tar.gz $files
- name: Create release
id: create_release
uses: actions/create-release@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
- name: Upload artifacts
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/manifests.tar.gz
asset_name: manifests.tar.gz
asset_content_type: application/gzip
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1
with:
version: latest
args: release --release-notes=/tmp/release.txt
args: release --release-notes=/tmp/release.txt --skip-validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore vendored
View File

@@ -13,4 +13,5 @@
# Dependency directories (remove the comment below to include it)
# vendor/
bin/
bin/
output/

View File

@@ -1,8 +1,8 @@
# Contributing
FluxCD toolkit is [Apache 2.0 licensed](LICENSE) and accepts contributions
via GitHub pull requests. This document outlines some of the conventions on
to make it easier to get your contribution accepted.
The GitOps Toolkit is [Apache 2.0 licensed](https://github.com/fluxcd/toolkit/blob/master/LICENSE)
and accepts contributions via GitHub pull requests. This document outlines
some of the conventions on to make it easier to get your contribution accepted.
We gratefully welcome improvements to issues and documentation as well as to
code.
@@ -14,13 +14,13 @@ Origin (DCO). This document was created by the Linux Kernel community and is a
simple statement that you, as a contributor, have the legal right to make the
contribution. No action from you is required, but it's a good idea to see the
[DCO](DCO) file for details before you start contributing code to FluxCD
toolkit.
organization.
## Communications
The project uses Slack: To join the conversation, simply join the
[CNCF](https://slack.cncf.io/) Slack workspace and use the
[#flux](https://cloud-native.slack.com/messages/flux/) channel.
[#flux-dev](https://cloud-native.slack.com/messages/flux-dev/) channel.
The developers use a mailing list to discuss development as well.
Simply subscribe to [flux-dev on cncf.io](https://lists.cncf.io/g/cncf-flux-dev)
@@ -57,7 +57,7 @@ get asked to resubmit the PR or divide the changes into more than one PR.
### Format of the Commit Message
For Source Controller we prefer the following rules for good commit messages:
For the GitOps Toolkit controllers we prefer the following rules for good commit messages:
- Limit the subject to 50 characters and write as the continuation
of the sentence "If applied, this commit will ..."
@@ -66,3 +66,16 @@ For Source Controller we prefer the following rules for good commit messages:
The [following article](https://chris.beams.io/posts/git-commit/#seven-rules)
has some more helpful advice on documenting your work.
## Understanding the GitOps Toolkit
If you are entirely new to the GitOps Toolkit,
you might want to take a look at the [introductory talk and demo](https://www.youtube.com/watch?v=qQBtSkgl7tI).
This project is composed of:
- [/f/toolkit](https://github.com/fluxcd/toolkit): The GitOps Toolkit CLI
- [/f/source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources
- [/f/kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
- [/f/helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
- [/f/notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events

View File

@@ -1,4 +1,4 @@
# toolkit
# GitOps Toolkit
[![e2e](https://github.com/fluxcd/toolkit/workflows/e2e/badge.svg)](https://github.com/fluxcd/toolkit/actions)
[![report](https://goreportcard.com/badge/github.com/fluxcd/toolkit)](https://goreportcard.com/report/github.com/fluxcd/toolkit)

View File

@@ -45,7 +45,10 @@ var bootstrapCmd = &cobra.Command{
}
var (
bootstrapVersion string
bootstrapVersion string
bootstrapComponents []string
bootstrapRegistry string
bootstrapImagePullSecret string
)
const (
@@ -56,8 +59,14 @@ const (
)
func init() {
bootstrapCmd.PersistentFlags().StringVar(&bootstrapVersion, "version", "master", "toolkit tag or branch")
bootstrapCmd.PersistentFlags().StringVarP(&bootstrapVersion, "version", "v", defaultVersion,
"toolkit version")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapComponents, "components", defaultComponents,
"list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapRegistry, "registry", "docker.io/fluxcd",
"container registry where the toolkit images are published")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapImagePullSecret, "image-pull-secret", "",
"Kubernetes secret name used for pulling the toolkit images from a private registry")
rootCmd.AddCommand(bootstrapCmd)
}
@@ -69,7 +78,7 @@ func generateInstallManifests(targetPath, namespace, tmpDir string) (string, err
return "", fmt.Errorf("generating manifests failed: %w", err)
}
if err := genInstallManifests(bootstrapVersion, namespace, components, tkDir); err != nil {
if err := genInstallManifests(bootstrapVersion, namespace, bootstrapComponents, bootstrapRegistry, bootstrapImagePullSecret, tkDir); err != nil {
return "", fmt.Errorf("generating manifests failed: %w", err)
}
@@ -137,7 +146,6 @@ func generateSyncManifests(url, name, namespace, targetPath, tmpDir string, inte
}
gvk = kustomizev1.GroupVersion.WithKind("Kustomization")
emptyAPIGroup := ""
kustomization := kustomizev1.Kustomization{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
@@ -153,10 +161,9 @@ func generateSyncManifests(url, name, namespace, targetPath, tmpDir string, inte
},
Path: fmt.Sprintf("./%s", strings.TrimPrefix(targetPath, "./")),
Prune: true,
SourceRef: corev1.TypedLocalObjectReference{
APIGroup: &emptyAPIGroup,
Kind: "GitRepository",
Name: name,
SourceRef: kustomizev1.CrossNamespaceObjectReference{
Kind: sourcev1.GitRepositoryKind,
Name: name,
},
},
}

View File

@@ -42,19 +42,19 @@ the bootstrap command will perform an upgrade if needed.`,
export GITHUB_TOKEN=<my-token>
# Run bootstrap for a private repo owned by a GitHub organization
bootstrap github --owner=<organization> --repository=<repo name>
tk bootstrap github --owner=<organization> --repository=<repo name>
# Run bootstrap for a private repo and assign organization teams to it
bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
tk bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
# Run bootstrap for a repository path
bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
tk bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
tk bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
# Run bootstrap for a private repo hosted on GitHub Enterprise
bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
tk bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
`,
RunE: bootstrapGitHubCmdRun,
}
@@ -175,7 +175,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if isInstall {
// apply install manifests
logger.Actionf("installing components in %s namespace", namespace)
if err := applyInstallManifests(ctx, manifest, components); err != nil {
if err := applyInstallManifests(ctx, manifest, bootstrapComponents); err != nil {
return err
}
logger.Successf("install completed")

View File

@@ -42,16 +42,16 @@ the bootstrap command will perform an upgrade if needed.`,
export GITLAB_TOKEN=<my-token>
# Run bootstrap for a private repo owned by a GitLab group
bootstrap gitlab --owner=<group> --repository=<repo name>
tk bootstrap gitlab --owner=<group> --repository=<repo name>
# Run bootstrap for a repository path
bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
tk bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
tk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
# Run bootstrap for a private repo hosted on a GitLab server
bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
tk bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
`,
RunE: bootstrapGitLabCmdRun,
}
@@ -153,7 +153,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
if isInstall {
// apply install manifests
logger.Actionf("installing components in %s namespace", namespace)
if err := applyInstallManifests(ctx, manifest, components); err != nil {
if err := applyInstallManifests(ctx, manifest, bootstrapComponents); err != nil {
return err
}
logger.Successf("install completed")

View File

@@ -35,22 +35,24 @@ var checkCmd = &cobra.Command{
Long: `The check command will perform a series of checks to validate that
the local environment is configured correctly and if the installed components are healthy.`,
Example: ` # Run pre-installation checks
check --pre
tk check --pre
# Run installation checks
check
tk check
`,
RunE: runCheckCmd,
}
var (
checkPre bool
checkPre bool
checkComponents []string
)
func init() {
checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false,
"only run pre-installation checks")
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaultComponents,
"list of components, accepts comma-separated values")
rootCmd.AddCommand(checkCmd)
}
@@ -65,7 +67,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
checkFailed = true
}
if !kubernetesCheck(">=1.14.0") {
if !kubernetesCheck(">=1.16.0") {
checkFailed = true
}
@@ -158,7 +160,7 @@ func componentsCheck() bool {
defer cancel()
ok := true
for _, deployment := range components {
for _, deployment := range checkComponents {
command := fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
namespace, deployment, timeout.String())
if output, err := utils.execCommand(ctx, ModeCapture, command); err != nil {

View File

@@ -0,0 +1,256 @@
/*
Copyright 2020 The Flux CD contributors.
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"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
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"
"sigs.k8s.io/yaml"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
)
var createHelmReleaseCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Create or update a HelmRelease resource",
Long: "The helmrelease create command generates a HelmRelease resource for a given HelmRepository source.",
Example: ` # Create a HelmRelease from a source
tk create hr podinfo \
--interval=10m \
--release-name=podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=">4.0.0"
# Create a HelmRelease with values for a local YAML file
tk create hr podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=4.0.5 \
--values=./my-values.yaml
# Create a HelmRelease definition on disk without applying it on the cluster
tk create hr podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=4.0.5 \
--values=./values.yaml \
--export > podinfo-release.yaml
`,
RunE: createHelmReleaseCmdRun,
}
var (
hrName string
hrSource string
hrDependsOn []string
hrChartName string
hrChartVersion string
hrTargetNamespace string
hrValuesFile string
)
func init() {
createHelmReleaseCmd.Flags().StringVar(&hrName, "release-name", "", "name used for the Helm release, defaults to a composition of '<target-namespace>-<hr-name>'")
createHelmReleaseCmd.Flags().StringVar(&hrSource, "source", "", "HelmRepository name")
createHelmReleaseCmd.Flags().StringVar(&hrChartName, "chart-name", "", "Helm chart name")
createHelmReleaseCmd.Flags().StringVar(&hrChartVersion, "chart-version", "", "Helm chart version, accepts semver range")
createHelmReleaseCmd.Flags().StringArrayVar(&hrDependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed")
createHelmReleaseCmd.Flags().StringVar(&hrTargetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().StringVar(&hrValuesFile, "values", "", "local path to the values.yaml file")
createCmd.AddCommand(createHelmReleaseCmd)
}
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("release name is required")
}
name := args[0]
if hrSource == "" {
return fmt.Errorf("source is required")
}
if hrChartName == "" {
return fmt.Errorf("chart name is required")
}
if hrChartVersion == "" {
return fmt.Errorf("chart version is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
if err != nil {
return err
}
if !export {
logger.Generatef("generating release")
}
helmRelease := helmv2.HelmRelease{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: helmv2.HelmReleaseSpec{
ReleaseName: hrName,
DependsOn: hrDependsOn,
Interval: metav1.Duration{
Duration: interval,
},
TargetNamespace: hrTargetNamespace,
Chart: helmv2.HelmChartTemplate{
Name: hrChartName,
Version: hrChartVersion,
SourceRef: helmv2.CrossNamespaceObjectReference{
Kind: sourcev1.HelmRepositoryKind,
Name: hrSource,
},
},
Suspend: false,
},
}
if hrValuesFile != "" {
data, err := ioutil.ReadFile(hrValuesFile)
if err != nil {
return fmt.Errorf("reading values from %s failed: %w", hrValuesFile, err)
}
json, err := yaml.YAMLToJSON(data)
if err != nil {
return fmt.Errorf("converting values to JSON from %s failed: %w", hrValuesFile, err)
}
helmRelease.Spec.Values = apiextensionsv1.JSON{Raw: json}
}
if export {
return exportHelmRelease(helmRelease)
}
logger.Actionf("applying release")
if err := upsertHelmRelease(ctx, kubeClient, helmRelease); err != nil {
return err
}
logger.Waitingf("waiting for reconciliation")
chartName := fmt.Sprintf("%s-%s", namespace, name)
if err := wait.PollImmediate(pollInterval, timeout,
isHelmChartReady(ctx, kubeClient, chartName, namespace)); err != nil {
return err
}
if err := wait.PollImmediate(pollInterval, timeout,
isHelmReleaseReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("release %s is ready", name)
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return fmt.Errorf("release failed: %w", err)
}
if helmRelease.Status.LastAppliedRevision != "" {
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
} else {
return fmt.Errorf("reconciliation failed")
}
return nil
}
func upsertHelmRelease(ctx context.Context, kubeClient client.Client, helmRelease helmv2.HelmRelease) error {
namespacedName := types.NamespacedName{
Namespace: helmRelease.GetNamespace(),
Name: helmRelease.GetName(),
}
var existing helmv2.HelmRelease
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &helmRelease); err != nil {
return err
} else {
logger.Successf("release created")
return nil
}
}
return err
}
existing.Spec = helmRelease.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
}
logger.Successf("release updated")
return nil
}
func isHelmChartReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
return func() (bool, error) {
var helmChart sourcev1.HelmChart
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &helmChart)
if err != nil {
if apierrors.IsNotFound(err) {
return false, nil
}
return false, err
}
for _, condition := range helmChart.Status.Conditions {
if condition.Type == helmv2.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
return false, fmt.Errorf(condition.Message)
}
}
}
return false, nil
}
}

View File

@@ -40,32 +40,32 @@ var createKsCmd = &cobra.Command{
Short: "Create or update a Kustomization resource",
Long: "The kustomization source create command generates a Kustomize resource for a given GitRepository source.",
Example: ` # Create a Kustomization resource from a source at a given path
create kustomization contour \
tk create kustomization contour \
--source=contour \
--path="./examples/contour/" \
--prune=true \
--interval=10m \
--validate=client \
--validation=client \
--health-check="Deployment/contour.projectcontour" \
--health-check="DaemonSet/envoy.projectcontour" \
--health-check-timeout=3m
# Create a Kustomization resource that depends on the previous one
create kustomization webapp \
tk create kustomization webapp \
--depends-on=contour \
--source=webapp \
--path="./deploy/overlays/dev" \
--prune=true \
--interval=5m \
--validate=client
--validation=client
# Create a Kustomization resource that runs under a service account
create kustomization webapp \
tk create kustomization webapp \
--source=webapp \
--path="./deploy/overlays/staging" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--sa-name=reconclier \
--sa-namespace=staging
`,
@@ -77,7 +77,7 @@ var (
ksPath string
ksPrune bool
ksDependsOn []string
ksValidate string
ksValidation string
ksHealthCheck []string
ksHealthTimeout time.Duration
ksSAName string
@@ -90,7 +90,7 @@ func init() {
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(&ksValidate, "validate", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
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")
createKsCmd.Flags().StringVar(&ksSAName, "sa-name", "", "service account name")
createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace")
@@ -125,7 +125,6 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
logger.Generatef("generating kustomization")
}
emptyAPIGroup := ""
kustomization := kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: name,
@@ -138,13 +137,12 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
},
Path: ksPath,
Prune: ksPrune,
SourceRef: corev1.TypedLocalObjectReference{
APIGroup: &emptyAPIGroup,
Kind: "GitRepository",
Name: ksSource,
SourceRef: kustomizev1.CrossNamespaceObjectReference{
Kind: sourcev1.GitRepositoryKind,
Name: ksSource,
},
Suspend: false,
Validation: ksValidate,
Validation: ksValidation,
},
}

View File

@@ -46,35 +46,35 @@ The create source git command generates a GitRepository resource and waits for i
For Git over SSH, host and SSH keys are automatically generated and stored in a Kubernetes secret.
For private Git repositories, the basic authentication credentials are stored in a Kubernetes secret.`,
Example: ` # Create a source from a public Git repository master branch
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--branch=master
# Create a source from a Git repository pinned to specific git tag
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--tag="3.2.3"
# Create a source from a public Git repository tag that matches a semver range
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--tag-semver=">=3.2.0 <3.3.0"
# Create a source from a Git repository using SSH authentication
create source git podinfo \
tk create source git podinfo \
--url=ssh://git@github.com/stefanprodan/podinfo \
--branch=master
# Create a source from a Git repository using SSH authentication and an
# ECDSA P-521 curve public key
create source git podinfo \
tk create source git podinfo \
--url=ssh://git@github.com/stefanprodan/podinfo \
--branch=master \
--ssh-key-algorithm=ecdsa \
--ssh-ecdsa-curve=p521
# Create a source from a Git repository using basic authentication
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--username=username \
--password=password
@@ -115,7 +115,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
name := args[0]
if sourceGitURL == "" {
return fmt.Errorf("git-url is required")
return fmt.Errorf("url is required")
}
tmpDir, err := ioutil.TempDir("", name)

View File

@@ -0,0 +1,229 @@
/*
Copyright 2020 The Flux CD contributors.
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"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/spf13/cobra"
"io/ioutil"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"net/url"
"os"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)
var createSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Create or update a HelmRepository source",
Long: `
The create source helm command generates a HelmRepository resource and waits for it to fetch the index.
For private Helm repositories, the basic authentication credentials are stored in a Kubernetes secret.`,
Example: ` # Create a source from a public Helm repository
tk create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--interval=10m
# Create a source from a Helm repository using basic authentication
tk create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--username=username \
--password=password
`,
RunE: createSourceHelmCmdRun,
}
var (
sourceHelmURL string
sourceHelmUsername string
sourceHelmPassword string
)
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")
createSourceCmd.AddCommand(createSourceHelmCmd)
}
func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("source name is required")
}
name := args[0]
secretName := fmt.Sprintf("helm-%s", name)
if sourceHelmURL == "" {
return fmt.Errorf("url is required")
}
tmpDir, err := ioutil.TempDir("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if _, err := url.Parse(sourceHelmURL); err != nil {
return fmt.Errorf("url parse failed: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
if err != nil {
return err
}
helmRepository := sourcev1.HelmRepository{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: sourcev1.HelmRepositorySpec{
URL: sourceHelmURL,
Interval: metav1.Duration{
Duration: interval,
},
},
}
if export {
return exportHelmRepository(helmRepository)
}
withAuth := false
if sourceHelmUsername != "" && sourceHelmPassword != "" {
logger.Actionf("applying secret with basic auth credentials")
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
},
StringData: map[string]string{
"username": sourceHelmUsername,
"password": sourceHelmPassword,
},
}
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
return err
}
withAuth = true
}
if withAuth {
logger.Successf("authentication configured")
}
logger.Generatef("generating source")
if withAuth {
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
Name: secretName,
}
}
logger.Actionf("applying source")
if err := upsertHelmRepository(ctx, kubeClient, helmRepository); err != nil {
return err
}
logger.Waitingf("waiting for index download")
if err := wait.PollImmediate(pollInterval, timeout,
isHelmRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("index download completed")
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
if err != nil {
return fmt.Errorf("helm index failed: %w", err)
}
if helmRepository.Status.Artifact != nil {
logger.Successf("fetched revision: %s", helmRepository.Status.Artifact.Revision)
} else {
return fmt.Errorf("index download failed, artifact not found")
}
return nil
}
func upsertHelmRepository(ctx context.Context, kubeClient client.Client, helmRepository sourcev1.HelmRepository) error {
namespacedName := types.NamespacedName{
Namespace: helmRepository.GetNamespace(),
Name: helmRepository.GetName(),
}
var existing sourcev1.HelmRepository
err := kubeClient.Get(ctx, namespacedName, &existing)
if err != nil {
if errors.IsNotFound(err) {
if err := kubeClient.Create(ctx, &helmRepository); err != nil {
return err
} else {
logger.Successf("source created")
return nil
}
}
return err
}
existing.Spec = helmRepository.Spec
if err := kubeClient.Update(ctx, &existing); err != nil {
return err
}
logger.Successf("source updated")
return nil
}
func exportHelmRepository(source sourcev1.HelmRepository) error {
gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)
export := sourcev1.HelmRepository{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: source.Name,
Namespace: source.Namespace,
},
Spec: source.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(string(data))
return nil
}

View File

@@ -0,0 +1,91 @@
/*
Copyright 2020 The Flux CD contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
)
var deleteHelmReleaseCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Delete a HelmRelease resource",
Long: "The delete helmrelease command removes the given HelmRelease from the cluster.",
Example: ` # Delete a Helm release and the Kubernetes resources created by it
tk delete hr podinfo
`,
RunE: deleteHelmReleaseCmdRun,
}
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)
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
}

View File

@@ -31,7 +31,10 @@ var deleteKsCmd = &cobra.Command{
Aliases: []string{"ks"},
Short: "Delete a Kustomization resource",
Long: "The delete kustomization command deletes the given Kustomization from the cluster.",
RunE: deleteKsCmdRun,
Example: ` # Delete a kustomization and the Kubernetes resources created by it
tk delete kustomization podinfo
`,
RunE: deleteKsCmdRun,
}
func init() {

View File

@@ -30,7 +30,10 @@ var deleteSourceGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Delete a GitRepository source",
Long: "The delete source git command deletes the given GitRepository from the cluster.",
RunE: deleteSourceGitCmdRun,
Example: ` # Delete a Git repository
tk delete source git podinfo
`,
RunE: deleteSourceGitCmdRun,
}
func init() {

View File

@@ -0,0 +1,86 @@
/*
Copyright 2020 The Flux CD contributors.
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"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
)
var deleteSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Delete a HelmRepository source",
Long: "The delete source helm command deletes the given HelmRepository from the cluster.",
Example: ` # Delete a Helm repository
tk delete source helm podinfo
`,
RunE: deleteSourceHelmCmdRun,
}
func init() {
deleteSourceCmd.AddCommand(deleteSourceHelmCmd)
}
func deleteSourceHelmCmdRun(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)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRepository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
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, &helmRepository)
if err != nil {
return err
}
logger.Successf("source deleted")
return nil
}

View File

@@ -0,0 +1,118 @@
/*
Copyright 2020 The Flux CD contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
)
var exportHelmReleaseCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Export HelmRelease resources in YAML format",
Long: "The export helmrelease command exports one or all HelmRelease resources in YAML format.",
Example: ` # Export all HelmRelease resources
tk export helmrelease --all > kustomizations.yaml
# Export a HelmRelease
tk export hr my-app > app-release.yaml
`,
RunE: exportHelmReleaseCmdRun,
}
func init() {
exportCmd.AddCommand(exportHelmReleaseCmd)
}
func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
if err != nil {
return err
}
if exportAll {
var list helmv2.HelmReleaseList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no kustomizations found in %s namespace", namespace)
return nil
}
for _, helmRelease := range list.Items {
if err := exportHelmRelease(helmRelease); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var helmRelease helmv2.HelmRelease
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
return exportHelmRelease(helmRelease)
}
return nil
}
func exportHelmRelease(helmRelease helmv2.HelmRelease) error {
gvk := helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)
export := helmv2.HelmRelease{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: helmRelease.Name,
Namespace: helmRelease.Namespace,
},
Spec: helmRelease.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(string(data))
return nil
}

View File

@@ -34,10 +34,10 @@ var exportKsCmd = &cobra.Command{
Short: "Export Kustomization resources in YAML format",
Long: "The export kustomization command exports one or all Kustomization resources in YAML format.",
Example: ` # Export all Kustomization resources
export kustomization --all > kustomizations.yaml
tk export kustomization --all > kustomizations.yaml
# Export a Kustomization
export kustomization my-app > kustomization.yaml
tk export kustomization my-app > kustomization.yaml
`,
RunE: exportKsCmdRun,
}

View File

@@ -34,10 +34,10 @@ var exportSourceGitCmd = &cobra.Command{
Short: "Export GitRepository sources in YAML format",
Long: "The export source git command exports on or all GitRepository sources in YAML format.",
Example: ` # Export all GitRepository sources
export source git --all > sources.yaml
tk export source git --all > sources.yaml
# Export a GitRepository source including the SSH key pair or basic auth credentials
export source git my-private-repo --with-credentials > source.yaml
tk export source git my-private-repo --with-credentials > source.yaml
`,
RunE: exportSourceGitCmdRun,
}
@@ -48,7 +48,7 @@ func init() {
func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("kustomization name is required")
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
@@ -103,7 +103,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
}
func exportGit(source sourcev1.GitRepository) error {
gvk := sourcev1.GroupVersion.WithKind("GitRepository")
gvk := sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind)
export := sourcev1.GitRepository{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,

View File

@@ -0,0 +1,139 @@
/*
Copyright 2020 The Flux CD contributors.
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"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
)
var exportSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Export HelmRepository sources in YAML format",
Long: "The export source git command exports on or all HelmRepository sources in YAML format.",
Example: ` # Export all HelmRepository sources
tk export source helm --all > sources.yaml
# Export a HelmRepository source including the basic auth credentials
tk export source helm my-private-repo --with-credentials > source.yaml
`,
RunE: exportSourceHelmCmdRun,
}
func init() {
exportSourceCmd.AddCommand(exportSourceHelmCmd)
}
func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.kubeClient(kubeconfig)
if err != nil {
return err
}
if exportAll {
var list sourcev1.HelmRepositoryList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no source found in %s namespace", namespace)
return nil
}
for _, repository := range list.Items {
if err := exportHelmRepository(repository); err != nil {
return err
}
if exportSourceWithCred {
if err := exportHelmCredentials(ctx, kubeClient, repository); err != nil {
return err
}
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var repository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &repository)
if err != nil {
return err
}
if err := exportHelmRepository(repository); err != nil {
return err
}
if exportSourceWithCred {
return exportHelmCredentials(ctx, kubeClient, repository)
}
}
return nil
}
func exportHelmCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.HelmRepository) error {
if source.Spec.SecretRef != nil {
namespacedName := types.NamespacedName{
Namespace: source.Namespace,
Name: source.Spec.SecretRef.Name,
}
var cred corev1.Secret
err := kubeClient.Get(ctx, namespacedName, &cred)
if err != nil {
return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err)
}
exported := corev1.Secret{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Secret",
},
ObjectMeta: metav1.ObjectMeta{
Name: namespacedName.Name,
Namespace: namespacedName.Namespace,
},
Data: cred.Data,
Type: cred.Type,
}
data, err := yaml.Marshal(exported)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(string(data))
}
return nil
}

90
cmd/tk/get_helmrelease.go Normal file
View File

@@ -0,0 +1,90 @@
/*
Copyright 2020 The Flux CD contributors.
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"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
)
var getHelmReleaseCmd = &cobra.Command{
Use: "helmreleases",
Aliases: []string{"hr"},
Short: "Get HelmRelease statuses",
Long: "The get helmreleases command prints the statuses of the resources.",
Example: ` # List all Helm releases and their status
tk get helmreleases
`,
RunE: getHelmReleaseCmdRun,
}
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)
if err != nil {
return err
}
var list helmv2.HelmReleaseList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no releases found in %s namespace", namespace)
return nil
}
for _, helmRelease := range list.Items {
if helmRelease.Spec.Suspend {
logger.Successf("%s is suspended", helmRelease.GetName())
continue
}
isInitialized := false
for _, condition := range helmRelease.Status.Conditions {
if condition.Type == helmv2.ReadyCondition {
if condition.Status != corev1.ConditionFalse {
if helmRelease.Status.LastAppliedRevision != "" {
logger.Successf("%s last applied revision %s", helmRelease.GetName(), helmRelease.Status.LastAppliedRevision)
} else {
logger.Successf("%s reconciling", helmRelease.GetName())
}
} else {
logger.Failuref("%s %s", helmRelease.GetName(), condition.Message)
}
isInitialized = true
break
}
}
if !isInitialized {
logger.Failuref("%s is not ready", helmRelease.GetName())
}
}
return nil
}

View File

@@ -28,9 +28,12 @@ import (
var getKsCmd = &cobra.Command{
Use: "kustomizations",
Aliases: []string{"ks"},
Short: "Get Kustomization source statuses",
Short: "Get Kustomization statuses",
Long: "The get kustomizations command prints the statuses of the resources.",
RunE: getKsCmdRun,
Example: ` # List all kustomizations and their status
tk get kustomizations
`,
RunE: getKsCmdRun,
}
func init() {

View File

@@ -29,7 +29,10 @@ var getSourceGitCmd = &cobra.Command{
Use: "git",
Short: "Get GitRepository source statuses",
Long: "The get sources git command prints the status of the GitRepository sources.",
RunE: getSourceGitCmdRun,
Example: ` # List all Git repositories and their status
tk get sources git
`,
RunE: getSourceGitCmdRun,
}
func init() {

80
cmd/tk/get_source_helm.go Normal file
View File

@@ -0,0 +1,80 @@
/*
Copyright 2020 The Flux CD contributors.
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"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var getSourceHelmCmd = &cobra.Command{
Use: "helm",
Short: "Get HelmRepository source statuses",
Long: "The get sources helm command prints the status of the HelmRepository sources.",
Example: ` # List all Helm repositories and their status
tk get sources helm
`,
RunE: getSourceHelmCmdRun,
}
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)
if err != nil {
return err
}
var list sourcev1.HelmRepositoryList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no sources found in %s namespace", namespace)
return nil
}
for _, source := range list.Items {
isInitialized := false
for _, condition := range source.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition {
if condition.Status != corev1.ConditionFalse {
logger.Successf("%s last fetched revision: %s", source.GetName(), source.Status.Artifact.Revision)
} else {
logger.Failuref("%s %s", source.GetName(), condition.Message)
}
isInitialized = true
break
}
}
if !isInitialized {
logger.Failuref("%s is not ready", source.GetName())
}
}
return nil
}

View File

@@ -19,11 +19,14 @@ package main
import (
"context"
"fmt"
"github.com/fluxcd/pkg/untar"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys"
@@ -36,30 +39,45 @@ var installCmd = &cobra.Command{
Long: `The install command deploys the toolkit components in the specified namespace.
If a previous version is installed, then an in-place upgrade will be performed.`,
Example: ` # Install the latest version in the gitops-systems namespace
install --version=master --namespace=gitops-systems
tk install --version=latest --namespace=gitops-systems
# Dry-run install for a specific version and a series of components
install --dry-run --version=0.0.1 --components="source-controller,kustomize-controller"
tk install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
# Dry-run install with manifests preview
install --dry-run --verbose
tk install --dry-run --verbose
# Write install manifests to file
tk install --export > gitops-system.yaml
`,
RunE: installCmdRun,
}
var (
installDryRun bool
installManifestsPath string
installVersion string
installExport bool
installDryRun bool
installManifestsPath string
installVersion string
installComponents []string
installRegistry string
installImagePullSecret string
)
func init() {
installCmd.Flags().BoolVar(&installExport, "export", false,
"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", "master",
"toolkit tag or branch")
installCmd.Flags().StringVarP(&installManifestsPath, "manifests", "", "",
installCmd.Flags().StringVarP(&installVersion, "version", "v", defaultVersion,
"toolkit version")
installCmd.Flags().StringSliceVar(&installComponents, "components", defaultComponents,
"list of components, accepts comma-separated values")
installCmd.Flags().StringVar(&installManifestsPath, "manifests", "",
"path to the manifest directory, dev only")
installCmd.Flags().StringVar(&installRegistry, "registry", "docker.io/fluxcd",
"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")
rootCmd.AddCommand(installCmd)
}
@@ -81,9 +99,11 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
}
defer os.RemoveAll(tmpDir)
logger.Generatef("generating manifests")
if !installExport {
logger.Generatef("generating manifests")
}
if kustomizePath == "" {
err = genInstallManifests(installVersion, namespace, components, tmpDir)
err = genInstallManifests(installVersion, namespace, installComponents, installRegistry, installImagePullSecret, tmpDir)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}
@@ -101,6 +121,13 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
} else {
if verbose {
fmt.Print(yaml)
} else if installExport {
fmt.Println("---")
fmt.Println("# GitOps Toolkit revision", installVersion, time.Now().Format(time.RFC3339))
fmt.Println("# Components:", strings.Join(installComponents, ","))
fmt.Print(yaml)
fmt.Println("---")
return nil
}
}
logger.Successf("manifests build completed")
@@ -128,7 +155,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
}
logger.Waitingf("verifying installation")
for _, deployment := range components {
for _, deployment := range installComponents {
command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
namespace, deployment, timeout.String())
if _, err := utils.execCommand(ctx, applyOutput, command); err != nil {
@@ -163,18 +190,49 @@ fieldSpecs:
`
var kustomizationTmpl = `---
{{- $version := .Version }}
{{- $eventsAddr := .EventsAddr }}
{{- $registry := .Registry }}
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: {{.Namespace}}
transformers:
- labels.yaml
resources:
- namespace.yaml
- policies.yaml
- roles
- github.com/fluxcd/toolkit/manifests/policies?ref={{$version}}
{{- range .Components }}
- github.com/fluxcd/toolkit/manifests/bases/{{.}}?ref={{$version}}
- {{.}}.yaml
{{- end }}
patches:
- path: node-selector.yaml
target:
kind: Deployment
patchesJson6902:
{{- range $i, $component := .Components }}
{{- if ne $component "notification-controller" }}
- target:
group: apps
version: v1
kind: Deployment
name: {{$component}}
patch: |-
- op: replace
path: /spec/template/spec/containers/0/args/0
value: --events-addr={{$eventsAddr}}
{{- end }}
{{- end }}
{{- if $registry }}
images:
{{- range $i, $component := .Components }}
- name: fluxcd/{{$component}}
newName: {{$registry}}/{{$component}}
{{- end }}
{{- end }}
`
@@ -182,19 +240,85 @@ var kustomizationRolesTmpl = `---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- github.com/fluxcd/toolkit/manifests/rbac?ref={{.Version}}
- rbac.yaml
nameSuffix: -{{.Namespace}}
`
func genInstallManifests(version string, namespace string, components []string, tmpDir string) error {
var nodeSelectorTmpl = `---
apiVersion: apps/v1
kind: Deployment
metadata:
name: all
spec:
template:
spec:
nodeSelector:
kubernetes.io/arch: amd64
kubernetes.io/os: linux
{{- if .ImagePullSecret }}
imagePullSecrets:
- name: {{.ImagePullSecret}}
{{- end }}
`
func downloadManifests(version string, tmpDir string) error {
ghURL := "https://github.com/fluxcd/toolkit/releases/latest/download/manifests.tar.gz"
if strings.HasPrefix(version, "v") {
ghURL = fmt.Sprintf("https://github.com/fluxcd/toolkit/releases/download/%s/manifests.tar.gz", version)
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequest("GET", ghURL, nil)
if err != nil {
return fmt.Errorf("failed to create HTTP request for %s, error: %w", ghURL, err)
}
// download
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
if err != nil {
return fmt.Errorf("failed to download artifact from %s, error: %w", ghURL, err)
}
defer resp.Body.Close()
// check response
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("faild to download artifact from %s, status: %s", ghURL, resp.Status)
}
// extract
if _, err = untar.Untar(resp.Body, tmpDir); err != nil {
return fmt.Errorf("faild to untar manifests from %s, error: %w", ghURL, err)
}
return nil
}
func genInstallManifests(version string, namespace string, components []string, registry, imagePullSecret, tmpDir string) error {
eventsAddr := ""
if utils.containsItemString(components, defaultNotification) {
eventsAddr = fmt.Sprintf("http://%s/", defaultNotification)
}
model := struct {
Version string
Namespace string
Components []string
Version string
Namespace string
Components []string
EventsAddr string
Registry string
ImagePullSecret string
}{
Version: version,
Namespace: namespace,
Components: components,
Version: version,
Namespace: namespace,
Components: components,
EventsAddr: eventsAddr,
Registry: registry,
ImagePullSecret: imagePullSecret,
}
if err := downloadManifests(version, tmpDir); err != nil {
return err
}
if err := utils.execTemplate(model, namespaceTmpl, path.Join(tmpDir, "namespace.yaml")); err != nil {
@@ -205,6 +329,10 @@ func genInstallManifests(version string, namespace string, components []string,
return fmt.Errorf("generate labels failed: %w", err)
}
if err := utils.execTemplate(model, nodeSelectorTmpl, path.Join(tmpDir, "node-selector.yaml")); err != nil {
return fmt.Errorf("generate node selector failed: %w", err)
}
if err := utils.execTemplate(model, kustomizationTmpl, path.Join(tmpDir, "kustomization.yaml")); err != nil {
return fmt.Errorf("generate kustomization failed: %w", err)
}
@@ -217,6 +345,10 @@ func genInstallManifests(version string, namespace string, components []string,
return fmt.Errorf("generate roles failed: %w", err)
}
if err := utils.copyFile(filepath.Join(tmpDir, "rbac.yaml"), filepath.Join(tmpDir, "roles/rbac.yaml")); err != nil {
return fmt.Errorf("generate rbac failed: %w", err)
}
return nil
}

View File

@@ -65,13 +65,13 @@ var rootCmd = &cobra.Command{
--path="./deploy/webapp/" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--health-check="Deployment/backend.webapp" \
--health-check="Deployment/frontend.webapp" \
--health-check-timeout=2m
# Trigger a git sync of the Kustomization's source and apply changes
tk sync kustomization webapp-dev --with-source
tk reconcile kustomization webapp-dev --with-source
# Suspend a Kustomization reconciliation
tk suspend kustomization webapp-dev
@@ -98,22 +98,25 @@ var (
namespace string
timeout time.Duration
verbose bool
components []string
utils Utils
pollInterval = 2 * time.Second
logger tklog.Logger = printLogger{}
)
var (
defaultComponents = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
defaultVersion = "latest"
defaultNamespace = "gitops-system"
defaultNotification = "notification-controller"
)
func init() {
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "", "gitops-system",
rootCmd.PersistentFlags().StringVar(&namespace, "namespace", defaultNamespace,
"the namespace scope for this operation")
rootCmd.PersistentFlags().DurationVarP(&timeout, "timeout", "", 5*time.Minute,
"timeout for this operation")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false,
"print generated objects")
rootCmd.PersistentFlags().StringSliceVar(&components, "components",
[]string{"source-controller", "kustomize-controller", "notification-controller"},
"list of components, accepts comma-separated values")
}
func main() {

View File

@@ -20,12 +20,12 @@ import (
"github.com/spf13/cobra"
)
var syncCmd = &cobra.Command{
Use: "sync",
Short: "Synchronize sources and resources",
Long: "The sync sub-commands trigger a reconciliation of sources and resources.",
var reconcileCmd = &cobra.Command{
Use: "reconcile",
Short: "Reconcile sources and resources",
Long: "The reconcile sub-commands trigger a reconciliation of sources and resources.",
}
func init() {
rootCmd.AddCommand(syncCmd)
rootCmd.AddCommand(reconcileCmd)
}

View File

@@ -0,0 +1,148 @@
/*
Copyright 2020 The Flux CD contributors.
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"
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/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/v2alpha1"
)
var reconcileHrCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Reconcile a HelmRelease resource",
Long: `
The reconcile kustomization command triggers a reconciliation of a HelmRelease resource and waits for it to finish.`,
Example: ` # Trigger a HelmRelease apply outside of the reconciliation interval
tk reconcile hr podinfo
# Trigger a reconciliation of the HelmRelease's source and apply changes
tk reconcile hr podinfo --with-source
`,
RunE: reconcileHrCmdRun,
}
var (
syncHrWithSource bool
)
func init() {
reconcileHrCmd.Flags().BoolVar(&syncHrWithSource, "with-source", false, "reconcile HelmRelease source")
reconcileCmd.AddCommand(reconcileHrCmd)
}
func reconcileHrCmdRun(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)
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 syncHrWithSource {
err := syncSourceHelmCmdRun(nil, []string{helmRelease.Spec.Chart.SourceRef.Name})
if err != nil {
return err
}
} else {
logger.Actionf("annotating HelmRelease %s in %s namespace", name, namespace)
if helmRelease.Annotations == nil {
helmRelease.Annotations = map[string]string{
helmv2.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
helmRelease.Annotations[helmv2.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
return err
}
logger.Successf("HelmRelease annotated")
}
logger.Waitingf("waiting for HelmRelease reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isHelmReleaseReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("HelmRelease reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if helmRelease.Status.LastAppliedRevision != "" {
logger.Successf("reconciled revision %s", helmRelease.Status.LastAppliedRevision)
} else {
return fmt.Errorf("HelmRelease reconciliation failed")
}
return nil
}
func isHelmReleaseReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
return func() (bool, error) {
var helmRelease helmv2.HelmRelease
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return false, err
}
for _, condition := range helmRelease.Status.Conditions {
if condition.Type == helmv2.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
return false, fmt.Errorf(condition.Message)
}
}
}
return false, nil
}
}

View File

@@ -27,19 +27,19 @@ import (
"k8s.io/apimachinery/pkg/util/wait"
)
var syncKsCmd = &cobra.Command{
var reconcileKsCmd = &cobra.Command{
Use: "kustomization [name]",
Aliases: []string{"ks"},
Short: "Synchronize a Kustomization resource",
Short: "Reconcile a Kustomization resource",
Long: `
The sync kustomization command triggers a reconciliation of a Kustomization resource and waits for it to finish.`,
The reconcile kustomization command triggers a reconciliation of a Kustomization resource and waits for it to finish.`,
Example: ` # Trigger a Kustomization apply outside of the reconciliation interval
sync kustomization podinfo
tk reconcile kustomization podinfo
# Trigger a sync of the Kustomization's source and apply changes
sync kustomization podinfo --with-source
tk reconcile kustomization podinfo --with-source
`,
RunE: syncKsCmdRun,
RunE: reconcileKsCmdRun,
}
var (
@@ -47,12 +47,12 @@ var (
)
func init() {
syncKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "synchronize kustomization source")
reconcileKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "reconcile kustomization source")
syncCmd.AddCommand(syncKsCmd)
reconcileCmd.AddCommand(reconcileKsCmd)
}
func syncKsCmdRun(cmd *cobra.Command, args []string) error {
func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("kustomization name is required")
}
@@ -86,10 +86,10 @@ func syncKsCmdRun(cmd *cobra.Command, args []string) error {
logger.Actionf("annotating kustomization %s in %s namespace", name, namespace)
if kustomization.Annotations == nil {
kustomization.Annotations = map[string]string{
kustomizev1.SyncAtAnnotation: time.Now().String(),
kustomizev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
kustomization.Annotations[kustomizev1.SyncAtAnnotation] = time.Now().String()
kustomization.Annotations[kustomizev1.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err
@@ -97,13 +97,13 @@ func syncKsCmdRun(cmd *cobra.Command, args []string) error {
logger.Successf("kustomization annotated")
}
logger.Waitingf("waiting for kustomization sync")
logger.Waitingf("waiting for kustomization reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("kustomization sync completed")
logger.Successf("kustomization reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil {
@@ -111,7 +111,7 @@ func syncKsCmdRun(cmd *cobra.Command, args []string) error {
}
if kustomization.Status.LastAppliedRevision != "" {
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
logger.Successf("reconciled revision %s", kustomization.Status.LastAppliedRevision)
} else {
return fmt.Errorf("kustomization sync failed")
}

View File

@@ -20,12 +20,12 @@ import (
"github.com/spf13/cobra"
)
var syncSourceCmd = &cobra.Command{
var reconcileSourceCmd = &cobra.Command{
Use: "source",
Short: "Synchronize sources",
Long: "The sync source sub-commands trigger a reconciliation of sources.",
Short: "Reconcile sources",
Long: "The reconcile source sub-commands trigger a reconciliation of sources.",
}
func init() {
syncCmd.AddCommand(syncSourceCmd)
reconcileCmd.AddCommand(reconcileSourceCmd)
}

View File

@@ -26,18 +26,18 @@ import (
"time"
)
var syncSourceGitCmd = &cobra.Command{
var reconcileSourceGitCmd = &cobra.Command{
Use: "git [name]",
Short: "Synchronize a GitRepository source",
Long: `The sync source command triggers a reconciliation of a GitRepository resource and waits for it to finish.`,
Short: "Reconcile a GitRepository source",
Long: `The reconcile source command triggers a reconciliation of a GitRepository resource and waits for it to finish.`,
Example: ` # Trigger a git pull for an existing source
sync source git podinfo
tk reconcile source git podinfo
`,
RunE: syncSourceGitCmdRun,
}
func init() {
syncSourceCmd.AddCommand(syncSourceGitCmd)
reconcileSourceCmd.AddCommand(reconcileSourceGitCmd)
}
func syncSourceGitCmdRun(cmd *cobra.Command, args []string) error {
@@ -68,23 +68,23 @@ func syncSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if gitRepository.Annotations == nil {
gitRepository.Annotations = map[string]string{
sourcev1.SyncAtAnnotation: time.Now().String(),
sourcev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
gitRepository.Annotations[sourcev1.SyncAtAnnotation] = time.Now().String()
gitRepository.Annotations[sourcev1.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &gitRepository); err != nil {
return err
}
logger.Successf("source annotated")
logger.Waitingf("waiting for git sync")
logger.Waitingf("waiting for reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("git sync completed")
logger.Successf("git reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
if err != nil {
@@ -94,7 +94,7 @@ func syncSourceGitCmdRun(cmd *cobra.Command, args []string) error {
if gitRepository.Status.Artifact != nil {
logger.Successf("fetched revision %s", gitRepository.Status.Artifact.Revision)
} else {
return fmt.Errorf("git sync failed, artifact not found")
return fmt.Errorf("git reconciliation failed, artifact not found")
}
return nil
}

View File

@@ -0,0 +1,130 @@
/*
Copyright 2020 The Flux CD contributors.
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"
"time"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/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/v1alpha1"
)
var reconcileSourceHelmCmd = &cobra.Command{
Use: "helm [name]",
Short: "Reconcile a HelmRepository source",
Long: `The reconcile source command triggers a reconciliation of a HelmRepository resource and waits for it to finish.`,
Example: ` # Trigger a reconciliation for an existing source
tk reconcile source helm podinfo
`,
RunE: syncSourceHelmCmdRun,
}
func init() {
reconcileSourceCmd.AddCommand(reconcileSourceHelmCmd)
}
func syncSourceHelmCmdRun(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)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
logger.Actionf("annotating source %s in %s namespace", name, namespace)
var helmRepository sourcev1.HelmRepository
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
if err != nil {
return err
}
if helmRepository.Annotations == nil {
helmRepository.Annotations = map[string]string{
sourcev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
}
} else {
helmRepository.Annotations[sourcev1.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
}
if err := kubeClient.Update(ctx, &helmRepository); err != nil {
return err
}
logger.Successf("source annotated")
logger.Waitingf("waiting for reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isHelmRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
return err
}
logger.Successf("helm reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
if err != nil {
return err
}
if helmRepository.Status.Artifact != nil {
logger.Successf("fetched revision %s", helmRepository.Status.Artifact.Revision)
} else {
return fmt.Errorf("helm reconciliation failed, artifact not found")
}
return nil
}
func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
return func() (bool, error) {
var helmRepository sourcev1.HelmRepository
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &helmRepository)
if err != nil {
return false, err
}
for _, condition := range helmRepository.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
return false, fmt.Errorf(condition.Message)
}
}
}
return false, nil
}
}

View File

@@ -0,0 +1,129 @@
/*
Copyright 2020 The Flux CD contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/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/v2alpha1"
)
var resumeHrCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Resume a suspended HelmRelease",
Long: `The resume command marks a previously suspended HelmRelease resource for reconciliation and waits for it to
finish the apply.`,
Example: ` # Resume reconciliation for an existing Helm release
tk resume hr podinfo
`,
RunE: resumeHrCmdRun,
}
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)
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, name, namespace)); err != nil {
return err
}
logger.Successf("HelmRelease reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return err
}
if helmRelease.Status.LastAppliedRevision != "" {
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
} else {
return fmt.Errorf("HelmRelease reconciliation failed")
}
return nil
}
func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
return func() (bool, error) {
var helmRelease helmv2.HelmRelease
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err := kubeClient.Get(ctx, namespacedName, &helmRelease)
if err != nil {
return false, err
}
for _, condition := range helmRelease.Status.Conditions {
if condition.Type == helmv2.ReadyCondition {
if condition.Status == corev1.ConditionTrue {
return true, nil
} else if condition.Status == corev1.ConditionFalse {
if condition.Reason == helmv2.SuspendedReason {
return false, nil
}
return false, fmt.Errorf(condition.Message)
}
}
}
return false, nil
}
}

View File

@@ -35,6 +35,9 @@ var resumeKsCmd = &cobra.Command{
Short: "Resume a suspended Kustomization",
Long: `The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to
finish the apply.`,
Example: ` # Resume reconciliation for an existing Kustomization
tk resume ks podinfo
`,
RunE: resumeKsCmdRun,
}

View File

@@ -0,0 +1,76 @@
/*
Copyright 2020 The Flux CD contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
)
var suspendHrCmd = &cobra.Command{
Use: "helmrelease [name]",
Aliases: []string{"hr"},
Short: "Suspend reconciliation of HelmRelease",
Long: "The suspend command disables the reconciliation of a HelmRelease resource.",
Example: ` # Suspend reconciliation for an existing Helm release
tk suspend hr podinfo
`,
RunE: suspendHrCmdRun,
}
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)
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
}

View File

@@ -29,7 +29,10 @@ var suspendKsCmd = &cobra.Command{
Aliases: []string{"ks"},
Short: "Suspend reconciliation of Kustomization",
Long: "The suspend command disables the reconciliation of a Kustomization resource.",
RunE: suspendKsCmdRun,
Example: ` # Suspend reconciliation for an existing Kustomization
tk suspend ks podinfo
`,
RunE: suspendKsCmdRun,
}
func init() {

View File

@@ -19,10 +19,12 @@ package main
import (
"context"
"fmt"
"time"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
)
var uninstallCmd = &cobra.Command{
@@ -30,27 +32,27 @@ var uninstallCmd = &cobra.Command{
Short: "Uninstall the toolkit components",
Long: "The uninstall command removes the namespace, cluster roles, cluster role bindings and CRDs from the cluster.",
Example: ` # Dry-run uninstall of all components
uninstall --dry-run --namespace=gitops-system
tk uninstall --dry-run --namespace=gitops-system
# Uninstall all components and delete custom resource definitions
uninstall --crds --namespace=gitops-system
tk uninstall --resources --crds --namespace=gitops-system
`,
RunE: uninstallCmdRun,
}
var (
uninstallCRDs bool
uninstallKustomizations bool
uninstallDryRun bool
uninstallSilent bool
uninstallCRDs bool
uninstallResources bool
uninstallDryRun bool
uninstallSilent bool
)
func init() {
uninstallCmd.Flags().BoolVarP(&uninstallKustomizations, "kustomizations", "", false,
"removes all Kustomizations previously installed")
uninstallCmd.Flags().BoolVarP(&uninstallCRDs, "crds", "", false,
uninstallCmd.Flags().BoolVar(&uninstallResources, "resources", false,
"removes custom resources such as Kustomizations, GitRepositories and HelmRepositories")
uninstallCmd.Flags().BoolVar(&uninstallCRDs, "crds", false,
"removes all CRDs previously installed")
uninstallCmd.Flags().BoolVarP(&uninstallDryRun, "dry-run", "", false,
uninstallCmd.Flags().BoolVar(&uninstallDryRun, "dry-run", false,
"only print the object that would be deleted")
uninstallCmd.Flags().BoolVarP(&uninstallSilent, "silent", "s", false,
"delete components without asking for confirmation")
@@ -75,18 +77,19 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
}
}
if uninstallKustomizations {
logger.Actionf("uninstalling kustomizations")
command := fmt.Sprintf("kubectl -n %s delete kustomizations --all --timeout=%s %s",
namespace, timeout.String(), dryRun)
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
return fmt.Errorf("uninstall failed")
if uninstallResources {
logger.Actionf("uninstalling custom resources")
for _, kind := range []string{
kustomizev1.KustomizationKind,
sourcev1.GitRepositoryKind,
sourcev1.HelmRepositoryKind,
} {
command := fmt.Sprintf("kubectl -n %s delete %s --all --timeout=%s %s",
namespace, kind, timeout.String(), dryRun)
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
return fmt.Errorf("uninstall failed")
}
}
// TODO: use the kustomizations snapshots to create a list of objects
// that are subject to deletion and wait for all of them to be terminated
logger.Waitingf("waiting on GC")
time.Sleep(30 * time.Second)
}
kinds := "namespace,clusterroles,clusterrolebindings"

View File

@@ -26,12 +26,14 @@ import (
"os/exec"
"text/template"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
)
type Utils struct {
@@ -118,6 +120,7 @@ func (*Utils) kubeClient(config string) (client.Client, error) {
_ = corev1.AddToScheme(scheme)
_ = sourcev1.AddToScheme(scheme)
_ = kustomizev1.AddToScheme(scheme)
_ = helmv2.AddToScheme(scheme)
kubeClient, err := client.New(cfg, client.Options{
Scheme: scheme,
@@ -143,3 +146,32 @@ func (*Utils) writeFile(content, filename string) error {
return file.Sync()
}
func (*Utils) copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}
func (*Utils) containsItemString(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -36,13 +36,13 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
--path="./deploy/webapp/" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--health-check="Deployment/backend.webapp" \
--health-check="Deployment/frontend.webapp" \
--health-check-timeout=2m
# Trigger a git sync of the Kustomization's source and apply changes
tk sync kustomization webapp-dev --with-source
tk reconcile kustomization webapp-dev --with-source
# Suspend a Kustomization reconciliation
tk suspend kustomization webapp-dev
@@ -67,12 +67,11 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
### Options
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
-h, --help help for tk
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
-h, --help help for tk
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
@@ -85,8 +84,8 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
* [tk export](tk_export.md) - Export resources in YAML format
* [tk get](tk_get.md) - Get sources and resources
* [tk install](tk_install.md) - Install the toolkit components
* [tk reconcile](tk_reconcile.md) - Reconcile sources and resources
* [tk resume](tk_resume.md) - Resume suspended resources
* [tk suspend](tk_suspend.md) - Suspend resources
* [tk sync](tk_sync.md) - Synchronize sources and resources
* [tk uninstall](tk_uninstall.md) - Uninstall the toolkit components

View File

@@ -9,18 +9,20 @@ The bootstrap sub-commands bootstrap the toolkit components on the targeted Git
### Options
```
-h, --help help for bootstrap
--version string toolkit tag or branch (default "master")
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
-h, --help help for bootstrap
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
--registry string container registry where the toolkit images are published (default "docker.io/fluxcd")
-v, --version string toolkit version (default "latest")
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -21,19 +21,19 @@ tk bootstrap github [flags]
export GITHUB_TOKEN=<my-token>
# Run bootstrap for a private repo owned by a GitHub organization
bootstrap github --owner=<organization> --repository=<repo name>
tk bootstrap github --owner=<organization> --repository=<repo name>
# Run bootstrap for a private repo and assign organization teams to it
bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
tk bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
# Run bootstrap for a repository path
bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
tk bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
tk bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
# Run bootstrap for a private repo hosted on GitHub Enterprise
bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
tk bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
```
@@ -54,12 +54,14 @@ tk bootstrap github [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--version string toolkit tag or branch (default "master")
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--registry string container registry where the toolkit images are published (default "docker.io/fluxcd")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
-v, --version string toolkit version (default "latest")
```
### SEE ALSO

View File

@@ -21,16 +21,16 @@ tk bootstrap gitlab [flags]
export GITLAB_TOKEN=<my-token>
# Run bootstrap for a private repo owned by a GitLab group
bootstrap gitlab --owner=<group> --repository=<repo name>
tk bootstrap gitlab --owner=<group> --repository=<repo name>
# Run bootstrap for a repository path
bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
tk bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
# Run bootstrap for a public repository on a personal account
bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
tk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
# Run bootstrap for a private repo hosted on a GitLab server
bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
tk bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
```
@@ -50,12 +50,14 @@ tk bootstrap gitlab [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--version string toolkit tag or branch (default "master")
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--registry string container registry where the toolkit images are published (default "docker.io/fluxcd")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
-v, --version string toolkit version (default "latest")
```
### SEE ALSO

View File

@@ -15,28 +15,28 @@ tk check [flags]
```
# Run pre-installation checks
check --pre
tk check --pre
# Run installation checks
check
tk check
```
### Options
```
-h, --help help for check
--pre only run pre-installation checks
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
-h, --help help for check
--pre only run pre-installation checks
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -33,11 +33,10 @@ To configure your bash shell to load completions for each session add to your ba
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -17,16 +17,16 @@ The create sub-commands generate sources and resources.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk create helmrelease](tk_create_helmrelease.md) - Create or update a HelmRelease resource
* [tk create kustomization](tk_create_kustomization.md) - Create or update a Kustomization resource
* [tk create source](tk_create_source.md) - Create or update sources

View File

@@ -0,0 +1,71 @@
## tk create helmrelease
Create or update a HelmRelease resource
### Synopsis
The helmrelease create command generates a HelmRelease resource for a given HelmRepository source.
```
tk create helmrelease [name] [flags]
```
### Examples
```
# Create a HelmRelease from a source
tk create hr podinfo \
--interval=10m \
--release-name=podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=">4.0.0"
# Create a HelmRelease with values for a local YAML file
tk create hr podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=4.0.5 \
--values=./my-values.yaml
# Create a HelmRelease definition on disk without applying it on the cluster
tk create hr podinfo \
--target-namespace=default \
--source=podinfo \
--chart-name=podinfo \
--chart-version=4.0.5 \
--values=./values.yaml \
--export > podinfo-release.yaml
```
### Options
```
--chart-name string Helm chart name
--chart-version string Helm chart version, accepts semver range
--depends-on stringArray HelmReleases that must be ready before this release can be installed
-h, --help help for helmrelease
--release-name string name used for the Helm release, defaults to a composition of '<target-namespace>-<hr-name>'
--source string HelmRepository name
--target-namespace string namespace to install this release, defaults to the HelmRelease namespace
--values string local path to the values.yaml file
```
### Options inherited from parent commands
```
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk create](tk_create.md) - Create or update sources and resources

View File

@@ -14,32 +14,32 @@ tk create kustomization [name] [flags]
```
# Create a Kustomization resource from a source at a given path
create kustomization contour \
tk create kustomization contour \
--source=contour \
--path="./examples/contour/" \
--prune=true \
--interval=10m \
--validate=client \
--validation=client \
--health-check="Deployment/contour.projectcontour" \
--health-check="DaemonSet/envoy.projectcontour" \
--health-check-timeout=3m
# Create a Kustomization resource that depends on the previous one
create kustomization webapp \
tk create kustomization webapp \
--depends-on=contour \
--source=webapp \
--path="./deploy/overlays/dev" \
--prune=true \
--interval=5m \
--validate=client
--validation=client
# Create a Kustomization resource that runs under a service account
create kustomization webapp \
tk create kustomization webapp \
--source=webapp \
--path="./deploy/overlays/staging" \
--prune=true \
--interval=5m \
--validate=client \
--validation=client \
--sa-name=reconclier \
--sa-namespace=staging
@@ -57,19 +57,18 @@ tk create kustomization [name] [flags]
--sa-name string service account name
--sa-namespace string service account namespace
--source string GitRepository name
--validate string validate the manifests before applying them on the cluster, can be 'client' or 'server'
--validation string validate the manifests before applying them on the cluster, can be 'client' or 'server'
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -15,17 +15,17 @@ The create source sub-commands generate sources.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk create](tk_create.md) - Create or update sources and resources
* [tk create source git](tk_create_source_git.md) - Create or update a GitRepository source
* [tk create source helm](tk_create_source_helm.md) - Create or update a HelmRepository source

View File

@@ -17,35 +17,35 @@ tk create source git [name] [flags]
```
# Create a source from a public Git repository master branch
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--branch=master
# Create a source from a Git repository pinned to specific git tag
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--tag="3.2.3"
# Create a source from a public Git repository tag that matches a semver range
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--tag-semver=">=3.2.0 <3.3.0"
# Create a source from a Git repository using SSH authentication
create source git podinfo \
tk create source git podinfo \
--url=ssh://git@github.com/stefanprodan/podinfo \
--branch=master
# Create a source from a Git repository using SSH authentication and an
# ECDSA P-521 curve public key
create source git podinfo \
tk create source git podinfo \
--url=ssh://git@github.com/stefanprodan/podinfo \
--branch=master \
--ssh-key-algorithm=ecdsa \
--ssh-ecdsa-curve=p521
# Create a source from a Git repository using basic authentication
create source git podinfo \
tk create source git podinfo \
--url=https://github.com/stefanprodan/podinfo \
--username=username \
--password=password
@@ -70,13 +70,12 @@ tk create source git [name] [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -0,0 +1,54 @@
## tk create source helm
Create or update a HelmRepository source
### Synopsis
The create source helm command generates a HelmRepository resource and waits for it to fetch the index.
For private Helm repositories, the basic authentication credentials are stored in a Kubernetes secret.
```
tk create source helm [name] [flags]
```
### Examples
```
# Create a source from a public Helm repository
tk create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--interval=10m
# Create a source from a Helm repository using basic authentication
tk create source helm podinfo \
--url=https://stefanprodan.github.io/podinfo \
--username=username \
--password=password
```
### Options
```
-h, --help help for helm
-p, --password string basic authentication password
--url string Helm repository address
-u, --username string basic authentication username
```
### Options inherited from parent commands
```
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk create source](tk_create_source.md) - Create or update sources

View File

@@ -16,16 +16,16 @@ The delete sub-commands delete sources and resources.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk delete helmrelease](tk_delete_helmrelease.md) - Delete a HelmRelease resource
* [tk delete kustomization](tk_delete_kustomization.md) - Delete a Kustomization resource
* [tk delete source](tk_delete_source.md) - Delete sources

View File

@@ -0,0 +1,40 @@
## tk delete helmrelease
Delete a HelmRelease resource
### Synopsis
The delete helmrelease command removes the given HelmRelease from the cluster.
```
tk delete helmrelease [name] [flags]
```
### Examples
```
# Delete a Helm release and the Kubernetes resources created by it
tk delete hr podinfo
```
### Options
```
-h, --help help for helmrelease
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk delete](tk_delete.md) - Delete sources and resources

View File

@@ -10,6 +10,14 @@ The delete kustomization command deletes the given Kustomization from the cluste
tk delete kustomization [name] [flags]
```
### Examples
```
# Delete a kustomization and the Kubernetes resources created by it
tk delete kustomization podinfo
```
### Options
```
@@ -19,12 +27,11 @@ tk delete kustomization [name] [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -15,16 +15,16 @@ The delete source sub-commands delete sources.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk delete](tk_delete.md) - Delete sources and resources
* [tk delete source git](tk_delete_source_git.md) - Delete a GitRepository source
* [tk delete source helm](tk_delete_source_helm.md) - Delete a HelmRepository source

View File

@@ -10,6 +10,14 @@ The delete source git command deletes the given GitRepository from the cluster.
tk delete source git [name] [flags]
```
### Examples
```
# Delete a Git repository
tk delete source git podinfo
```
### Options
```
@@ -19,12 +27,11 @@ tk delete source git [name] [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -0,0 +1,40 @@
## tk delete source helm
Delete a HelmRepository source
### Synopsis
The delete source helm command deletes the given HelmRepository from the cluster.
```
tk delete source helm [name] [flags]
```
### Examples
```
# Delete a Helm repository
tk delete source helm podinfo
```
### Options
```
-h, --help help for helm
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
-s, --silent delete resource without asking for confirmation
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk delete source](tk_delete_source.md) - Delete sources

View File

@@ -16,16 +16,16 @@ The export sub-commands export resources in YAML format.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk export helmrelease](tk_export_helmrelease.md) - Export HelmRelease resources in YAML format
* [tk export kustomization](tk_export_kustomization.md) - Export Kustomization resources in YAML format
* [tk export source](tk_export_source.md) - Export sources

View File

@@ -0,0 +1,43 @@
## tk export helmrelease
Export HelmRelease resources in YAML format
### Synopsis
The export helmrelease command exports one or all HelmRelease resources in YAML format.
```
tk export helmrelease [name] [flags]
```
### Examples
```
# Export all HelmRelease resources
tk export helmrelease --all > kustomizations.yaml
# Export a HelmRelease
tk export hr my-app > app-release.yaml
```
### Options
```
-h, --help help for helmrelease
```
### Options inherited from parent commands
```
--all select all resources
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk export](tk_export.md) - Export resources in YAML format

View File

@@ -14,10 +14,10 @@ tk export kustomization [name] [flags]
```
# Export all Kustomization resources
export kustomization --all > kustomizations.yaml
tk export kustomization --all > kustomizations.yaml
# Export a Kustomization
export kustomization my-app > kustomization.yaml
tk export kustomization my-app > kustomization.yaml
```
@@ -30,12 +30,11 @@ tk export kustomization [name] [flags]
### Options inherited from parent commands
```
--all select all resources
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--all select all resources
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -16,16 +16,16 @@ The export source sub-commands export sources in YAML format.
### Options inherited from parent commands
```
--all select all resources
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--all select all resources
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk export](tk_export.md) - Export resources in YAML format
* [tk export source git](tk_export_source_git.md) - Export GitRepository sources in YAML format
* [tk export source helm](tk_export_source_helm.md) - Export HelmRepository sources in YAML format

View File

@@ -14,10 +14,10 @@ tk export source git [name] [flags]
```
# Export all GitRepository sources
export source git --all > sources.yaml
tk export source git --all > sources.yaml
# Export a GitRepository source including the SSH key pair or basic auth credentials
export source git my-private-repo --with-credentials > source.yaml
tk export source git my-private-repo --with-credentials > source.yaml
```
@@ -30,13 +30,12 @@ tk export source git [name] [flags]
### Options inherited from parent commands
```
--all select all resources
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--with-credentials include credential secrets
--all select all resources
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--with-credentials include credential secrets
```
### SEE ALSO

View File

@@ -0,0 +1,44 @@
## tk export source helm
Export HelmRepository sources in YAML format
### Synopsis
The export source git command exports on or all HelmRepository sources in YAML format.
```
tk export source helm [name] [flags]
```
### Examples
```
# Export all HelmRepository sources
tk export source helm --all > sources.yaml
# Export a HelmRepository source including the basic auth credentials
tk export source helm my-private-repo --with-credentials > source.yaml
```
### Options
```
-h, --help help for helm
```
### Options inherited from parent commands
```
--all select all resources
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--with-credentials include credential secrets
```
### SEE ALSO
* [tk export source](tk_export_source.md) - Export sources

View File

@@ -15,16 +15,16 @@ The get sub-commands print the statuses of sources and resources.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk get kustomizations](tk_get_kustomizations.md) - Get Kustomization source statuses
* [tk get helmreleases](tk_get_helmreleases.md) - Get HelmRelease statuses
* [tk get kustomizations](tk_get_kustomizations.md) - Get Kustomization statuses
* [tk get sources](tk_get_sources.md) - Get source statuses

View File

@@ -0,0 +1,39 @@
## tk get helmreleases
Get HelmRelease statuses
### Synopsis
The get helmreleases command prints the statuses of the resources.
```
tk get helmreleases [flags]
```
### Examples
```
# List all Helm releases and their status
tk get helmreleases
```
### Options
```
-h, --help help for helmreleases
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk get](tk_get.md) - Get sources and resources

View File

@@ -1,6 +1,6 @@
## tk get kustomizations
Get Kustomization source statuses
Get Kustomization statuses
### Synopsis
@@ -10,6 +10,14 @@ The get kustomizations command prints the statuses of the resources.
tk get kustomizations [flags]
```
### Examples
```
# List all kustomizations and their status
tk get kustomizations
```
### Options
```
@@ -19,11 +27,10 @@ tk get kustomizations [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -15,15 +15,15 @@ The get source sub-commands print the statuses of the sources.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk get](tk_get.md) - Get sources and resources
* [tk get sources git](tk_get_sources_git.md) - Get GitRepository source statuses
* [tk get sources helm](tk_get_sources_helm.md) - Get HelmRepository source statuses

View File

@@ -10,6 +10,14 @@ The get sources git command prints the status of the GitRepository sources.
tk get sources git [flags]
```
### Examples
```
# List all Git repositories and their status
tk get sources git
```
### Options
```
@@ -19,11 +27,10 @@ tk get sources git [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -0,0 +1,39 @@
## tk get sources helm
Get HelmRepository source statuses
### Synopsis
The get sources helm command prints the status of the HelmRepository sources.
```
tk get sources helm [flags]
```
### Examples
```
# List all Helm repositories and their status
tk get sources helm
```
### Options
```
-h, --help help for helm
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk get sources](tk_get_sources.md) - Get source statuses

View File

@@ -15,33 +15,39 @@ tk install [flags]
```
# Install the latest version in the gitops-systems namespace
install --version=master --namespace=gitops-systems
tk install --version=latest --namespace=gitops-systems
# Dry-run install for a specific version and a series of components
install --dry-run --version=0.0.1 --components="source-controller,kustomize-controller"
tk install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
# Dry-run install with manifests preview
install --dry-run --verbose
tk install --dry-run --verbose
# Write install manifests to file
tk install --export > gitops-system.yaml
```
### Options
```
--dry-run only print the object that would be applied
-h, --help help for install
--manifests string path to the manifest directory, dev only
-v, --version string toolkit tag or branch (default "master")
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--dry-run only print the object that would be applied
--export write the install manifests to stdout and exit
-h, --help help for install
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
--manifests string path to the manifest directory, dev only
--registry string container registry where the toolkit images are published (default "docker.io/fluxcd")
-v, --version string toolkit version (default "latest")
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

30
docs/cmd/tk_reconcile.md Normal file
View File

@@ -0,0 +1,30 @@
## tk reconcile
Reconcile sources and resources
### Synopsis
The reconcile sub-commands trigger a reconciliation of sources and resources.
### Options
```
-h, --help help for reconcile
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk reconcile helmrelease](tk_reconcile_helmrelease.md) - Reconcile a HelmRelease resource
* [tk reconcile kustomization](tk_reconcile_kustomization.md) - Reconcile a Kustomization resource
* [tk reconcile source](tk_reconcile_source.md) - Reconcile sources

View File

@@ -0,0 +1,44 @@
## tk reconcile helmrelease
Reconcile a HelmRelease resource
### Synopsis
The reconcile kustomization command triggers a reconciliation of a HelmRelease resource and waits for it to finish.
```
tk reconcile helmrelease [name] [flags]
```
### Examples
```
# Trigger a HelmRelease apply outside of the reconciliation interval
tk reconcile hr podinfo
# Trigger a reconciliation of the HelmRelease's source and apply changes
tk reconcile hr podinfo --with-source
```
### Options
```
-h, --help help for helmrelease
--with-source reconcile HelmRelease source
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk reconcile](tk_reconcile.md) - Reconcile sources and resources

View File

@@ -0,0 +1,44 @@
## tk reconcile kustomization
Reconcile a Kustomization resource
### Synopsis
The reconcile kustomization command triggers a reconciliation of a Kustomization resource and waits for it to finish.
```
tk reconcile kustomization [name] [flags]
```
### Examples
```
# Trigger a Kustomization apply outside of the reconciliation interval
tk reconcile kustomization podinfo
# Trigger a sync of the Kustomization's source and apply changes
tk reconcile kustomization podinfo --with-source
```
### Options
```
-h, --help help for kustomization
--with-source reconcile kustomization source
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk reconcile](tk_reconcile.md) - Reconcile sources and resources

View File

@@ -0,0 +1,29 @@
## tk reconcile source
Reconcile sources
### Synopsis
The reconcile source sub-commands trigger a reconciliation of sources.
### Options
```
-h, --help help for source
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk reconcile](tk_reconcile.md) - Reconcile sources and resources
* [tk reconcile source git](tk_reconcile_source_git.md) - Reconcile a GitRepository source
* [tk reconcile source helm](tk_reconcile_source_helm.md) - Reconcile a HelmRepository source

View File

@@ -0,0 +1,39 @@
## tk reconcile source git
Reconcile a GitRepository source
### Synopsis
The reconcile source command triggers a reconciliation of a GitRepository resource and waits for it to finish.
```
tk reconcile source git [name] [flags]
```
### Examples
```
# Trigger a git pull for an existing source
tk reconcile source git podinfo
```
### Options
```
-h, --help help for git
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk reconcile source](tk_reconcile_source.md) - Reconcile sources

View File

@@ -0,0 +1,39 @@
## tk reconcile source helm
Reconcile a HelmRepository source
### Synopsis
The reconcile source command triggers a reconciliation of a HelmRepository resource and waits for it to finish.
```
tk reconcile source helm [name] [flags]
```
### Examples
```
# Trigger a reconciliation for an existing source
tk reconcile source helm podinfo
```
### Options
```
-h, --help help for helm
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk reconcile source](tk_reconcile_source.md) - Reconcile sources

View File

@@ -15,15 +15,15 @@ The resume sub-commands resume a suspended resource.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk resume helmrelease](tk_resume_helmrelease.md) - Resume a suspended HelmRelease
* [tk resume kustomization](tk_resume_kustomization.md) - Resume a suspended Kustomization

View File

@@ -0,0 +1,40 @@
## tk resume helmrelease
Resume a suspended HelmRelease
### Synopsis
The resume command marks a previously suspended HelmRelease resource for reconciliation and waits for it to
finish the apply.
```
tk resume helmrelease [name] [flags]
```
### Examples
```
# Resume reconciliation for an existing Helm release
tk resume hr podinfo
```
### Options
```
-h, --help help for helmrelease
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk resume](tk_resume.md) - Resume suspended resources

View File

@@ -11,6 +11,14 @@ finish the apply.
tk resume kustomization [name] [flags]
```
### Examples
```
# Resume reconciliation for an existing Kustomization
tk resume ks podinfo
```
### Options
```
@@ -20,11 +28,10 @@ tk resume kustomization [name] [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -15,15 +15,15 @@ The suspend sub-commands suspend the reconciliation of a resource.
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk suspend helmrelease](tk_suspend_helmrelease.md) - Suspend reconciliation of HelmRelease
* [tk suspend kustomization](tk_suspend_kustomization.md) - Suspend reconciliation of Kustomization

View File

@@ -0,0 +1,39 @@
## tk suspend helmrelease
Suspend reconciliation of HelmRelease
### Synopsis
The suspend command disables the reconciliation of a HelmRelease resource.
```
tk suspend helmrelease [name] [flags]
```
### Examples
```
# Suspend reconciliation for an existing Helm release
tk suspend hr podinfo
```
### Options
```
-h, --help help for helmrelease
```
### Options inherited from parent commands
```
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk suspend](tk_suspend.md) - Suspend resources

View File

@@ -10,6 +10,14 @@ The suspend command disables the reconciliation of a Kustomization resource.
tk suspend kustomization [name] [flags]
```
### Examples
```
# Suspend reconciliation for an existing Kustomization
tk suspend ks podinfo
```
### Options
```
@@ -19,11 +27,10 @@ tk suspend kustomization [name] [flags]
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -1,30 +0,0 @@
## tk sync
Synchronize sources and resources
### Synopsis
The sync sub-commands trigger a reconciliation of sources and resources.
### Options
```
-h, --help help for sync
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk sync kustomization](tk_sync_kustomization.md) - Synchronize a Kustomization resource
* [tk sync source](tk_sync_source.md) - Synchronize sources

View File

@@ -1,45 +0,0 @@
## tk sync kustomization
Synchronize a Kustomization resource
### Synopsis
The sync kustomization command triggers a reconciliation of a Kustomization resource and waits for it to finish.
```
tk sync kustomization [name] [flags]
```
### Examples
```
# Trigger a Kustomization apply outside of the reconciliation interval
sync kustomization podinfo
# Trigger a sync of the Kustomization's source and apply changes
sync kustomization podinfo --with-source
```
### Options
```
-h, --help help for kustomization
--with-source synchronize kustomization source
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk sync](tk_sync.md) - Synchronize sources and resources

View File

@@ -1,29 +0,0 @@
## tk sync source
Synchronize sources
### Synopsis
The sync source sub-commands trigger a reconciliation of sources.
### Options
```
-h, --help help for source
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk sync](tk_sync.md) - Synchronize sources and resources
* [tk sync source git](tk_sync_source_git.md) - Synchronize a GitRepository source

View File

@@ -1,40 +0,0 @@
## tk sync source git
Synchronize a GitRepository source
### Synopsis
The sync source command triggers a reconciliation of a GitRepository resource and waits for it to finish.
```
tk sync source git [name] [flags]
```
### Examples
```
# Trigger a git pull for an existing source
sync source git podinfo
```
### Options
```
-h, --help help for git
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [tk sync source](tk_sync_source.md) - Synchronize sources

View File

@@ -14,31 +14,30 @@ tk uninstall [flags]
```
# Dry-run uninstall of all components
uninstall --dry-run --namespace=gitops-system
tk uninstall --dry-run --namespace=gitops-system
# Uninstall all components and delete custom resource definitions
uninstall --crds --namespace=gitops-system
tk uninstall --resources --crds --namespace=gitops-system
```
### Options
```
--crds removes all CRDs previously installed
--dry-run only print the object that would be deleted
-h, --help help for uninstall
--kustomizations removes all Kustomizations previously installed
-s, --silent delete components without asking for confirmation
--crds removes all CRDs previously installed
--dry-run only print the object that would be deleted
-h, --help help for uninstall
--resources removes custom resources such as Kustomizations, GitRepositories and HelmRepositories
-s, --silent delete components without asking for confirmation
```
### Options inherited from parent commands
```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO

View File

@@ -0,0 +1,25 @@
# Helm Controller
The Helm Controller is a Kubernetes operator, allowing one to declaratively manage Helm chart
releases with Kubernetes manifests.
![](../../_files/helm-controller.png)
The desired state of a Helm release is described through a Kubernetes Custom Resource named `HelmRelease`.
Based on the creation, mutation or removal of a HelmRelease resource in the cluster,
Helm actions are performed by the controller.
Features:
- Watches for `HelmRelease` objects and generates `HelmChart` objects
- Fetches artifacts produced by [source-controller](../source/controller.md) from `HelmChart` objects
- Watches `HelmChart` objects for revision changes (semver ranges)
- Performs Helm v3 actions including Helm tests as configured in the `HelmRelease` objects
- Runs Helm install/upgrade in a specific order, taking into account the depends-on relationship
- Prunes Helm releases removed from cluster (garbage collection)
- Reports Helm releases status (alerting provided by [notification-controller](../notification/controller.md))
Links:
- Source code [fluxcd/helm-controller](https://github.com/fluxcd/helm-controller)
- Specification [docs](https://github.com/fluxcd/helm-controller/tree/master/docs/spec)

View File

@@ -1,14 +1,15 @@
# Notification Controller
The Notification Controller is a Kubernetes operator,
specialized in dispatching events to external systems such as
Slack, Microsoft Teams, Discord and Rocket chat.
The Notification Controller is a Kubernetes operator, specialized in handling inbound and outbound events.
The controller receives events via HTTP and dispatch them to external
webhooks based on event severity and involved objects.
![](../../_files/notification-controller.png)
The controller can be configured with Kubernetes custom resources that
define how events are processed and where to dispatch them.
The controller handles events coming from external systems (GitHub, GitLab, Bitbucket, Harbour, Jenkins, etc)
and notifies the GitOps toolkit controllers about source changes.
The controller handles events emitted by the GitOps toolkit controllers (source, kustomize, helm)
and dispatches them to external systems (Slack, Microsoft Teams, Discord, Rocker)
based on event severity and involved objects.
Links:

1
docs/contributing/index.md Symbolic link
View File

@@ -0,0 +1 @@
../../CONTRIBUTING.md

View File

@@ -0,0 +1,233 @@
# Watching for source changes
In this guide you'll be developing a Kubernetes controller with
[Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder)
that subscribes to [GitRepository](../components/source/gitrepositories.md)
events and reacts to revision changes by downloading the artifact produced by
[source-controller](../components/source/controller.md).
## Prerequisites
On your dev machine install the following tools:
* go >= 1.13
* kubebuilder >= 2.3
* kind >= 0.8
* kubectl >= 1.18
* kustomize >= 3.5
* docker >= 19.03
## Install the GitOps Toolkit
Create a cluster for testing:
```sh
kind create cluster --name dev
```
Install the toolkit CLI:
```sh
curl -s https://toolkit.fluxcd.io/install.sh | sudo bash
```
Verify that your dev machine satisfies the prerequisites with:
```sh
tk check --pre
```
Install the toolkit controllers on the dev cluster:
```sh
tk install
```
## Clone the sample controller
You'll be using [stefanprodan/source-watcher](https://github.com/stefanprodan/source-watcher) as
a template for developing your own controller. The source-watcher was scaffolded with `kubebuilder init`.
Clone the source-watcher repo:
```sh
git clone https://github.com/stefanprodan/source-watcher
cd source-watcher
```
Build the controller:
```sh
make
```
## Run the controller
Port forward to source-controller artifacts server:
```sh
kubectl -n gitops-system port-forward svc/source-controller 8181:80
```
Export the local address as `SOURCE_HOST`:
```sh
export SOURCE_HOST=localhost:8181
```
Run source-watcher locally:
```sh
make run
```
Create a Git source:
```sh
tk create source git test \
--url=https://github.com/stefanprodan/podinfo \
--tag=4.0.0
```
The source-watcher should log the revision:
```console
New revision detected {"gitrepository": "gitops-system/test", "revision": "4.0.0/ab953493ee14c3c9800bda0251e0c507f9741408"}
Extracted tarball into /var/folders/77/3y6x_p2j2g9fspdkzjbm5_s40000gn/T/test292235827: 123 files, 29 dirs (32.603415ms)
Processing files...
```
Change the Git tag:
```sh
tk create source git test \
--url=https://github.com/stefanprodan/podinfo \
--tag=4.0.1
```
The source-watcher should log the new revision:
```console
New revision detected {"gitrepository": "gitops-system/test", "revision": "4.0.1/113360052b3153e439a0cf8de76b8e3d2a7bdf27"}
```
The source-controller reports the revision under `GitRepository.Status.Artifact.Revision` in the format: `<branch|tag>/<commit>`.
## How it works
The [GitRepositoryWatcher](https://github.com/stefanprodan/source-watcher/blob/master/controllers/gitrepository_watcher.go)
controller does the following:
* subscribes to `GitRepository` events
* detects when the Git revision changes
* downloads and extracts the source artifact
* write to stdout the extracted file names
```go
// GitRepositoryWatcher watches GitRepository objects for revision changes
type GitRepositoryWatcher struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
}
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=gitrepositories,verbs=get;list;watch
// +kubebuilder:rbac:groups=source.fluxcd.io,resources=gitrepositories/status,verbs=get
func (r *GitRepositoryWatcher) Reconcile(req ctrl.Request) (ctrl.Result, error) {
// set timeout for the reconciliation
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// get source object
var repository sourcev1.GitRepository
if err := r.Get(ctx, req.NamespacedName, &repository); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
log := r.Log.WithValues(strings.ToLower(repository.Kind), req.NamespacedName)
log.Info("New revision detected", "revision", repository.Status.Artifact.Revision)
// create tmp dir
tmpDir, err := ioutil.TempDir("", repository.Name)
if err != nil {
return ctrl.Result{}, fmt.Errorf("unable to create temp dir, error: %w", err)
}
defer os.RemoveAll(tmpDir)
// download and extract artifact
summary, err := r.fetchArtifact(ctx, repository, tmpDir)
if err != nil {
return ctrl.Result{}, fmt.Errorf("unable to fetch artifact, error: %w", err)
}
log.Info(summary)
// list artifact content
files, err := ioutil.ReadDir(tmpDir)
if err != nil {
return ctrl.Result{}, fmt.Errorf("unable to list files, error: %w", err)
}
// do something with the artifact content
for _, f := range files {
log.Info("Processing " + f.Name())
}
return ctrl.Result{}, nil
}
func (r *GitRepositoryWatcher) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&sourcev1.GitRepository{}).
WithEventFilter(GitRepositoryRevisionChangePredicate{}).
Complete(r)
}
```
To add the watcher to an existing project, copy the controller and the revision change predicate to your `controllers` dir:
* [gitrepository_watcher.go](https://github.com/stefanprodan/source-watcher/blob/master/controllers/gitrepository_watcher.go)
* [gitrepository_predicate.go](https://github.com/stefanprodan/source-watcher/blob/master/controllers/gitrepository_predicate.go)
In your `main.go` init function, register the Source API schema:
```go
import sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = sourcev1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}
```
Start the controller in the main function:
```go
func main() {
if err = (&controllers.GitRepositoryWatcher{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("GitRepositoryWatcher"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitRepositoryWatcher")
os.Exit(1)
}
}
```
Note that the watcher controller depends on Kubernetes client-go >= 1.18.
Your `go.mod` should require controller-runtime v0.6 or newer:
```go
require (
k8s.io/apimachinery v0.18.4
k8s.io/client-go v0.18.4
sigs.k8s.io/controller-runtime v0.6.0
)
```
That's it! Happy hacking!

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -2,7 +2,7 @@
## Prerequisites
You will need two Kubernetes clusters version 1.14 or newer and kubectl version 1.18.
You will need two Kubernetes clusters version 1.16 or newer and kubectl version 1.18.
For a quick local test, you can use [Kubernetes kind](https://kind.sigs.k8s.io/docs/user/quick-start/).
Any other Kubernetes setup will work as well though.
@@ -63,7 +63,7 @@ $ tk check --pre
► checking prerequisites
✔ kubectl 1.18.3 >=1.18.0
✔ kubernetes 1.18.2 >=1.14.0
✔ kubernetes 1.18.2 >=1.16.0
✔ prerequisites checks passed
```
@@ -152,7 +152,7 @@ tk create kustomization webapp-common \
--source=webapp \
--path="./deploy/webapp/common" \
--prune=true \
--validate=client \
--validation=client \
--interval=1h \
--export > ./staging-cluster/webapp-common.yaml
```
@@ -165,7 +165,7 @@ tk create kustomization webapp-backend \
--source=webapp \
--path="./deploy/webapp/backend" \
--prune=true \
--validate=client \
--validation=client \
--interval=10m \
--health-check="Deployment/backend.webapp" \
--health-check-timeout=2m \
@@ -180,7 +180,7 @@ tk create kustomization webapp-frontend \
--source=webapp \
--path="./deploy/webapp/frontend" \
--prune=true \
--validate=client \
--validation=client \
--interval=10m \
--health-check="Deployment/frontend.webapp" \
--health-check-timeout=2m \
@@ -227,7 +227,7 @@ If you delete a kustomization from the `fleet-infra` repo, the reconciler will r
were previously applied from that kustomization.
If you alter the webapp deployment using `kubectl edit`, the changes will be reverted to match
the state described in git. When dealing with an incident, you can pause the recitation of a
the state described in git. When dealing with an incident, you can pause the reconciliation of a
kustomization with `tk suspend kustomization <name>`. Once the debugging session
is over, you can re-enable the reconciliation with `tk resume kustomization <name>`.
@@ -278,7 +278,7 @@ tk create kustomization webapp \
--source=webapp \
--path="./deploy/overlays/production" \
--prune=true \
--validate=client \
--validation=client \
--interval=10m \
--health-check="Deployment/frontend.production" \
--health-check="Deployment/backend.production" \
@@ -329,19 +329,19 @@ git add -A && git commit -m "update prod webapp" && git push
Trigger a git sync:
```console
$ tk sync ks gitops-system --with-source
$ tk reconcile ks gitops-system --with-source
► annotating source gitops-system
✔ source annotated
◎ waiting for git sync
✔ git sync completed
◎ waiting for reconcilitation
✔ git reconciliation completed
✔ fetched revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9
◎ waiting for kustomization sync
✔ kustomization sync completed
◎ waiting for kustomization reconcilitation
✔ kustomization reconcilitation completed
✔ applied revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9
```
The kubectl equivalent is `kubectl -n gitops-system annotate gitrepository/gitops-system source.fluxcd.io/syncAt="$(date +%s)"`.
The kubectl equivalent is `kubectl -n gitops-system annotate gitrepository/gitops-system fluxcd.io/reconcileAt="$(date +%s)"`.
Wait for the webapp to be upgraded:

192
docs/guides/helmreleases.md Normal file
View File

@@ -0,0 +1,192 @@
# Manage Helm Releases
The [helm-controller](../components/helm/controller.md) allows you to
declaratively manage Helm chart releases with Kubernetes manifests.
It makes use of the artifacts produced by the
[source-controller](../components/source/controller.md) from
`HelmRepository` and `HelmChart` resources.
The helm-controller is part of the default toolkit installation.
## Prerequisites
To follow this guide you'll need a Kubernetes cluster with the GitOps
toolkit controllers installed on it.
Please see the [get started guide](../get-started/index.md)
or the [install command docs](../cmd/tk_install.md).
## Define a Helm repository
To be able to deploy a Helm chart, the Helm chart repository has to be
known first to the source-controller, so that the `HelmRelease` can
reference to it.
A cluster administrator should register trusted sources by creating
`HelmRepository` resources in the `gitops-system` namespace.
By default, the source-controller watches for sources only in the
`gitops-system` namespace, this way cluster admins can prevent
untrusted sources from being registered by users.
```yaml
apiVersion: source.fluxcd.io/v1alpha1
kind: HelmRepository
metadata:
name: podinfo
namespace: gitops-system
spec:
interval: 1m
url: https://stefanprodan.github.io/podinfo
```
The `interval` defines at which interval the Helm repository index
is fetched, and should be at least `1m`. Setting this to a higher
value means newer chart versions will be detected at a slower pace,
a push-based fetch can be introduced using [webhook receivers](webhook-receivers.md)
The `url` can be any HTTP/S Helm repository URL.
!!! hint "Authentication"
HTTP/S basic and TLS authentication can be configured for private
Helm repositories. See the [`HelmRepository` CRD docs](../components/source/helmrepositories.md)
for more details.
## Define a Helm release
With the `HelmRepository` created, define a new `HelmRelease` to deploy
the Helm chart from the repository:
```yaml
apiVersion: helm.fluxcd.io/v2alpha1
kind: HelmRelease
metadata:
name: podinfo
namespace: default
spec:
interval: 5m
chart:
name: podinfo
version: '^4.0.0'
sourceRef:
kind: HelmRepository
name: podinfo
namespace: gitops-system
interval: 1m
values:
replicaCount: 2
```
The `chart.name` is the name of the chart as made available by the Helm
repository, and may not include any aliases.
The `chart.version` can be a fixed semver, or any semver range (i.e.
`>=4.0.0 <4.0.2`).
The `chart` values are used by the helm-controller as a template to
create a new `HelmChart` resource in the same namespace as the
`sourceRef`. The source-controller will then lookup the chart in the
artifact of the referenced `HelmRepository`, fetch the chart, and make
it available as a `HelmChart` artifact to be used by the
helm-controller.
!!! Note
The `HelmRelease` offers an extensive set of configurable flags
for finer grain control over how Helm actions are performed.
See the [`HelmRelease` CRD docs](../components/helm/helmreleases.md)
for more details.
## Configure notifications
The default toolkit installation configures the helm-controller to
broadcast events to the [notification-controller](../components/notification/controller.md).
To receive the events as notifications, a `Provider` needs to be setup
first as described in the [notifications guide](notifications.md#define-a-provider).
Once you have set up the `Provider`, create a new `Alert` resource in
the `gitops-system` to start receiving notifications about the Helm
release:
```yaml
apiVersion: notification.fluxcd.io/v1alpha1
kind: Alert
metadata:
generation: 2
name: helm-podinfo
namespace: gitops-system
spec:
providerRef:
name: slack
eventSeverity: info
eventSources:
- kind: HelmRepository
name: podinfo
- kind: HelmChart
name: default-podinfo
- kind: HelmRelease
name: podinfo
namespace: default
```
![helm-controller alerts](../diagrams/helm-controller-alerts.png)
## Configure webhook receivers
When using semver ranges for Helm releases, you may want to trigger an update
as soon as a new chart version is published to your Helm repository.
In order to notify source-controller about a chart update,
you can [setup webhook receivers](webhook-receivers.md).
First generate a random string and create a secret with a `token` field:
```sh
TOKEN=$(head -c 12 /dev/urandom | shasum | cut -d ' ' -f1)
echo $TOKEN
kubectl -n gitops-system create secret generic webhook-token \
--from-literal=token=$TOKEN
```
When using [Harbor](https://goharbor.io/) as your Helm repository, you can define a receiver with:
```yaml
apiVersion: notification.fluxcd.io/v1alpha1
kind: Receiver
metadata:
name: helm-podinfo
namespace: gitops-system
spec:
type: harbor
secretRef:
name: webhook-token
resources:
- kind: HelmRepository
name: podinfo
```
The notification-controller generates a unique URL using the provided token and the receiver name/namespace.
Find the URL with:
```console
$ kubectl -n gitops-system get receiver/helm-podinfo
NAME READY STATUS
helm-podinfo True Receiver initialised with URL: /hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b
```
Log in to the Harbor interface, go to Projects, select a project, and select Webhooks.
Fill the form with:
* Endpoint URL: compose the address using the receiver LB and the generated URL `http://<LoadBalancerAddress>/<ReceiverURL>`
* Auth Header: use the `token` string
With the above settings, when you upload a chart, the following happens:
* Harbor sends the chart push event to the receiver address
* Notification controller validates the authenticity of the payload using the auth header
* Source controller is notified about the changes
* Source controller pulls the changes into the cluster and updates the `HelmChart` version
* Helm controller is notified about the version change and upgrades the release
!!! hint "Note"
Besides Harbor, you can define receivers for **GitHub**, **GitLab**, **Bitbucket**
and any other system that supports webhooks e.g. Jenkins, CircleCI, etc.
See the [Receiver CRD docs](../components/notification/receiver.md) for more details.

View File

@@ -42,16 +42,16 @@ spec:
name: slack-url
```
The provider type can be `slack`, `msteams`, `discord`, `rocket` or `webhook`.
The provider type can be `slack`, `msteams`, `discord`, `rocket` or `generic`.
When type `webhook` is specified, the notification controller will post the incoming
When type `generic` is specified, the notification controller will post the incoming
[event](../components/notification/event.md) in JSON format to the webhook address.
This way you can create custom handlers that can store the events in
Elasticsearch, CloudWatch, Stackdriver, etc.
## Define an alert
Create an alert definition for the webapp kustomizations:
Create an alert definition for all repositories and kustomizations:
```yaml
apiVersion: notification.fluxcd.io/v1alpha1
@@ -64,10 +64,10 @@ spec:
name: slack
eventSeverity: info
eventSources:
- kind: GitRepository
name: '*'
- kind: Kustomization
name: webapp-backend
- kind: Kustomization
name: webapp-frontend
name: '*'
```
Apply the above files or commit them to the `fleet-infra` repository.

View File

@@ -0,0 +1,173 @@
# Sealed Secrets
In order to store secrets safely in a public or private Git repository, you can use
Bitnami's [sealed-secrets controller](https://github.com/bitnami-labs/sealed-secrets)
and encrypt your Kubernetes Secrets into SealedSecrets.
The sealed secrets can be decrypted only by the controller running in your cluster and
nobody else can obtain the original secret, even if they have access to the Git repository.
## Prerequisites
To follow this guide you'll need a Kubernetes cluster with the GitOps
toolkit controllers installed on it.
Please see the [get started guide](../get-started/index.md)
or the [install command docs](../cmd/tk_install.md).
The sealed-secrets controller comes with a companion CLI tool called kubeseal.
With kubeseal you can create SealedSecret custom resources in YAML format
and store those in your Git repository.
Install the kubeseal CLI:
```sh
brew install kubeseal
```
For Linux or Windows you can download the kubeseal binary from
[GitHub](https://github.com/bitnami-labs/sealed-secrets/releases).
## Deploy sealed-secrets with a HelmRelease
You'll be using [helm-controller](../components/helm/controller.md) APIs to install
the sealed-secrets controller from its [Helm chart](https://hub.kubeapps.com/charts/stable/sealed-secrets).
First you have to register the Helm repository where the sealed-secrets chart is published:
```sh
tk create source helm stable \
--interval=1h \
--url=https://kubernetes-charts.storage.googleapis.com
```
With `interval` we configure [source-controller](../components/source/controller.md) to download
the Helm repository index every hour. If a newer version of sealed-secrets is published,
source-controller will signal helm-controller that a new chart is available.
Create a Helm release that installs the latest version of sealed-secrets controller:
```sh
tk create helmrelease sealed-secrets \
--interval=1h \
--release-name=sealed-secrets \
--target-namespace=gitops-system \
--source=stable \
--chart-name=sealed-secrets \
--chart-version="^1.10.0"
```
With chart version `^1.10.0` we configure helm-controller to automatically upgrade the release
when a new chart version is fetch by source-controller.
At startup, the sealed-secrets controller generates a 4096-bit RSA key pair and
persists the private and public keys as Kubernetes secrets in the `gitops-system` namespace.
You can retrieve the public key with:
```sh
kubeseal --fetch-cert \
--controller-name=sealed-secrets \
--controller-namespace=gitops-system \
> pub-sealed-secrets.pem
```
The public key can be safely stored in Git, and can be used to encrypt secrets
without direct access to the Kubernetes cluster.
## Encrypt secrets
Generate a Kubernetes secret manifest with kubectl:
```sh
kubectl -n default create secret generic basic-auth \
--from-literal=user=admin \
--from-literal=password=change-me \
--dry-run \
-o yaml > basic-auth.yaml
```
Encrypt the secret with kubeseal:
```sh
kubeseal --format=yaml --cert=pub-sealed-secrets.pem \
< basic-auth.yaml > basic-auth-sealed.yaml
```
Delete the plain secret and apply the sealed one:
```sh
rm basic-auth.yaml
kubectl apply -f basic-auth-sealed.yaml
```
Verify that the sealed-secrets controller has created the `basic-auth` Kubernetes Secret:
```console
$ kubectl -n default get secrets basic-auth
NAME TYPE DATA AGE
basic-auth Opaque 2 1m43s
```
## GitOps workflow
A cluster admin should add the stable `HelmRepository` manifest and the sealed-secrets `HelmRelease`
to the fleet repository.
Helm repository manifest:
```yaml
apiVersion: source.fluxcd.io/v1alpha1
kind: HelmRepository
metadata:
name: stable
namespace: gitops-system
spec:
interval: 1h0m0s
url: https://kubernetes-charts.storage.googleapis.com
```
Helm release manifest:
```yaml
apiVersion: helm.fluxcd.io/v2alpha1
kind: HelmRelease
metadata:
name: sealed-secrets
namespace: gitops-system
spec:
chart:
name: sealed-secrets
sourceRef:
kind: HelmRepository
name: stable
version: "^1.10.0"
interval: 1h0m0s
releaseName: sealed-secrets
targetNamespace: gitops-system
```
!!! hint
You can generate the above manifests using `tk create <kind> --export > manifest.yaml`.
Once the sealed-secrets controller is installed, the admin fetches the
public key and shares it with the teams that operate on the fleet clusters via Git.
When a team member wants to create a Kubernetes Secret on a cluster,
they uses kubeseal and the public key corresponding to that cluster to generate a SealedSecret.
Assuming a team member wants to deploy an application that needs to connect
to a database using a username and password, they'll be doing the following:
* create a Kubernetes Secret manifest locally with the db credentials e.g. `db-auth.yaml`
* encrypt the secret with kubeseal as `db-auth-sealed.yaml`
* delete the original secret file `db-auth.yaml`
* create a Kubernetes Deployment manifest for the app e.g. `app-deployment.yaml`
* add the Secret to the Deployment manifest as a [volume mount or env var](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets) using the original name `db-auth`
* commit the manifests `db-auth-sealed.yaml` and `app-deployment.yaml` to a Git repository that's being synced by the GitOps toolkit controllers
Once the manifests have been pushed to the Git repository, the following happens:
* source-controller pulls the changes from Git
* kustomize-controller applies the SealedSecret and the Deployment manifests
* sealed-secrets controller decrypts the SealedSecret and creates a Kubernetes Secret
* kubelet creates the pods and mounts the secret as a volume or env variable inside the app container

View File

@@ -0,0 +1,138 @@
# Setup Webhook Receivers
The GitOps toolkit controllers are by design **pull-based**.
In order to notify the controllers about changes in Git or Helm repositories,
you can setup webhooks and trigger a cluster reconciliation
every time a source changes. Using webhook receivers, you can build **push-based**
GitOps pipelines that react to external events.
## Prerequisites
To follow this guide you'll need a Kubernetes cluster with the GitOps
toolkit controllers installed on it.
Please see the [get started guide](../get-started/index.md)
or the [install command docs](../cmd/tk_install.md).
The [notification controller](../components/notification/controller.md)
can handle events coming from external systems
(GitHub, GitLab, Bitbucket, Harbour, Jenkins, etc)
and notify the GitOps toolkit controllers about source changes.
The notification controller is part of the default toolkit installation.
## Expose the webhook receiver
In order to receive Git push or Helm chart upload events, you'll have to
expose the webhook receiver endpoint outside of your Kubernetes cluster on
a public address.
The notification controller handles webhook requests on port `9292`.
This port can be used to create a Kubernetes LoadBalancer Service or Ingress.
Create a `LoadBalancer` service:
```yaml
apiVersion: v1
kind: Service
metadata:
name: receiver
namespace: gitops-system
spec:
type: LoadBalancer
selector:
app: notification-controller
ports:
- name: http
port: 80
protocol: TCP
targetPort: 9292
```
Wait for Kubernetes to assign a public address with:
```sh
watch kubectl -n gitops-system get svc/receiver
```
## Define a Git repository
Create a Git source pointing to a GitHub repository that you have control over:
```yaml
apiVersion: source.fluxcd.io/v1alpha1
kind: GitRepository
metadata:
name: webapp
namespace: gitops-system
spec:
interval: 60m
url: https://github.com/<GH-ORG>/<GH-REPO>
ref:
branch: master
```
!!! hint "Authentication"
SSH or token based authentication can be configured for private repositories.
See the [GitRepository CRD docs](../components/source/gitrepositories.md) for more details.
## Define a Git repository receiver
First generate a random string and create a secret with a `token` field:
```sh
TOKEN=$(head -c 12 /dev/urandom | shasum | cut -d ' ' -f1)
echo $TOKEN
kubectl -n gitops-system create secret generic webhook-token \
--from-literal=token=$TOKEN
```
Create a receiver for GitHub and specify the `GitRepository` object:
```yaml
apiVersion: notification.fluxcd.io/v1alpha1
kind: Receiver
metadata:
name: webapp
namespace: gitops-system
spec:
type: github
events:
- "ping"
- "push"
secretRef:
name: webhook-token
resources:
- kind: GitRepository
name: webapp
```
!!! hint "Note"
Besides GitHub, you can define receivers for **GitLab**, **Bitbucket**, **Harbour**
and any other system that supports webhooks e.g. Jenkins, CircleCI, etc.
See the [Receiver CRD docs](../components/notification/receiver.md) for more details.
The notification controller generates a unique URL using the provided token and the receiver name/namespace.
Find the URL with:
```console
$ kubectl -n gitops-system get receiver/webapp
NAME READY STATUS
webapp True Receiver initialised with URL: /hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b
```
On GitHub, navigate to your repository and click on the "Add webhook" button under "Settings/Webhooks".
Fill the form with:
* **Payload URL**: compose the address using the receiver LB and the generated URL `http://<LoadBalancerAddress>/<ReceiverURL>`
* **Secret**: use the `token` string
With the above settings, when you push a commit to the repository, the following happens:
* GitHub sends the Git push event to the receiver address
* Notification controller validates the authenticity of the payload using HMAC
* Source controller is notified about the changes
* Source controller pulls the changes into the cluster and updates the `GitRepository` revision
* Kustomize controller is notified about the revision change
* Kustomize controller reconciles all the `Kustomizations` that reference the `GitRepository` object

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