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

Compare commits

..

68 Commits

Author SHA1 Message Date
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
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
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
Stefan Prodan
b7727e2659 Merge pull request #74 from fluxcd/docs-notifications
Add notifications guide
2020-07-02 15:13:03 +03:00
stefanprodan
229d1d8c6e Add notifications guide 2020-07-02 14:51:28 +03:00
Stefan Prodan
c0b18f85aa Merge pull request #73 from fluxcd/notification-controller
Add notification component
2020-07-02 13:43:15 +03:00
stefanprodan
b11b9588f8 Update tk docs 2020-07-02 13:35:30 +03:00
stefanprodan
633d028841 Update kustomize controller and enable events 2020-07-02 13:14:56 +03:00
stefanprodan
a744b304a0 Add notification controller to docs 2020-07-02 12:58:01 +03:00
stefanprodan
e594350307 Add notification controller to tk components 2020-07-02 12:52:55 +03:00
Stefan Prodan
ecf7a1eac1 Merge pull request #70 from fluxcd/fluxcd-pkg
Migrate to fluxcd/pkg
2020-06-30 17:32:38 +03:00
stefanprodan
4621afcb31 Migrate to fluxcd/pkg 2020-06-30 17:11:04 +03:00
Stefan Prodan
006c949941 Merge pull request #69 from fluxcd/docs-meta
Add metadata to docs website
2020-06-26 16:53:09 +03:00
stefanprodan
72e06ab337 Add metadata to docs website 2020-06-26 16:41:04 +03:00
Hidde Beydals
f4b2a32a23 Merge pull request #67 from fluxcd/log-interface
Create logger interface
2020-06-25 18:20:17 +02:00
Hidde Beydals
329e21fd78 Create logger interface 2020-06-25 18:05:15 +02:00
Hidde Beydals
5499d15402 Merge pull request #68 from fluxcd/sort-ecdsa-curves
Sort supported ECDSA curves names
2020-06-25 18:03:29 +02:00
Hidde Beydals
d7f8a05612 Sort supported ECDSA curves names
To ensure options are always printed in the same order.
2020-06-25 17:53:41 +02:00
Hidde Beydals
1f99a75049 Merge pull request #66 from fluxcd/docs/cli-examples
Improve CLI command descriptions
2020-06-25 15:58:33 +02:00
Hidde Beydals
21fd436621 Add descriptions to all CLI commands 2020-06-25 15:49:31 +02:00
123 changed files with 2460 additions and 2358 deletions

View File

@@ -14,12 +14,29 @@ jobs:
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: Copy assets - name: Copy assets
run: | 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/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/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/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/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 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 - name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@master uses: mhausenblas/mkdocs-deploy-gh-pages@master
env: env:

View File

@@ -30,7 +30,7 @@ jobs:
- name: Check if working tree is dirty - name: Check if working tree is dirty
run: | run: |
if [[ $(git diff --stat) != '' ]]; then if [[ $(git diff --stat) != '' ]]; then
git diff --stat git diff
echo 'run make test and commit changes' echo 'run make test and commit changes'
exit 1 exit 1
fi fi
@@ -41,7 +41,7 @@ jobs:
./bin/tk check --pre ./bin/tk check --pre
- name: tk install --version - name: tk install --version
run: | run: |
./bin/tk install --version=master --namespace=test --verbose ./bin/tk install --version=master --namespace=test --verbose --components="source-controller,kustomize-controller"
- name: tk uninstall - name: tk uninstall
run: | run: |
./bin/tk uninstall --namespace=test --crds --silent ./bin/tk uninstall --namespace=test --crds --silent
@@ -69,7 +69,7 @@ jobs:
--health-check-timeout=3m --health-check-timeout=3m
- name: tk sync kustomization --with-source - name: tk sync kustomization --with-source
run: | run: |
./bin/tk sync kustomization podinfo --with-source ./bin/tk reconcile kustomization podinfo --with-source
- name: tk get kustomizations - name: tk get kustomizations
run: | run: |
./bin/tk get kustomizations ./bin/tk get kustomizations

View File

@@ -14,7 +14,7 @@ jobs:
- name: Unshallow - name: Unshallow
run: git fetch --prune --unshallow run: git fetch --prune --unshallow
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2-beta uses: actions/setup-go@v2
with: with:
go-version: 1.14.x go-version: 1.14.x
- name: Download release notes utility - name: Download release notes utility
@@ -25,10 +25,60 @@ jobs:
run: | run: |
echo 'CHANGELOG' > /tmp/release.txt echo 'CHANGELOG' > /tmp/release.txt
github-release-notes -org fluxcd -repo toolkit -since-latest-release >> /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 - name: Run GoReleaser
uses: goreleaser/goreleaser-action@v1 uses: goreleaser/goreleaser-action@v1
with: with:
version: latest version: latest
args: release --release-notes=/tmp/release.txt args: release --release-notes=/tmp/release.txt --skip-validate
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore vendored
View File

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

View File

@@ -1,8 +1,8 @@
# Contributing # Contributing
FluxCD toolkit is [Apache 2.0 licensed](LICENSE) and accepts contributions The GitOps Toolkit is [Apache 2.0 licensed](https://github.com/fluxcd/toolkit/blob/master/LICENSE)
via GitHub pull requests. This document outlines some of the conventions on and accepts contributions via GitHub pull requests. This document outlines
to make it easier to get your contribution accepted. 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 We gratefully welcome improvements to issues and documentation as well as to
code. 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 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 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 [DCO](DCO) file for details before you start contributing code to FluxCD
toolkit. organization.
## Communications ## Communications
The project uses Slack: To join the conversation, simply join the The project uses Slack: To join the conversation, simply join the
[CNCF](https://slack.cncf.io/) Slack workspace and use 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. 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) 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 ### 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 - Limit the subject to 50 characters and write as the continuation
of the sentence "If applied, this commit will ..." 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) The [following article](https://chris.beams.io/posts/git-commit/#seven-rules)
has some more helpful advice on documenting your work. 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) [![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) [![report](https://goreportcard.com/badge/github.com/fluxcd/toolkit)](https://goreportcard.com/report/github.com/fluxcd/toolkit)

View File

@@ -40,11 +40,13 @@ import (
var bootstrapCmd = &cobra.Command{ var bootstrapCmd = &cobra.Command{
Use: "bootstrap", Use: "bootstrap",
Short: "Bootstrap commands", Short: "Bootstrap toolkit components",
Long: "The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.",
} }
var ( var (
bootstrapVersion string bootstrapVersion string
bootstrapComponents []string
) )
const ( const (
@@ -55,7 +57,10 @@ const (
) )
func init() { 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")
rootCmd.AddCommand(bootstrapCmd) rootCmd.AddCommand(bootstrapCmd)
} }
@@ -68,7 +73,7 @@ func generateInstallManifests(targetPath, namespace, tmpDir string) (string, err
return "", fmt.Errorf("generating manifests failed: %w", err) return "", fmt.Errorf("generating manifests failed: %w", err)
} }
if err := genInstallManifests(bootstrapVersion, namespace, components, tkDir); err != nil { if err := genInstallManifests(bootstrapVersion, namespace, bootstrapComponents, tkDir); err != nil {
return "", fmt.Errorf("generating manifests failed: %w", err) return "", fmt.Errorf("generating manifests failed: %w", err)
} }
@@ -136,7 +141,6 @@ func generateSyncManifests(url, name, namespace, targetPath, tmpDir string, inte
} }
gvk = kustomizev1.GroupVersion.WithKind("Kustomization") gvk = kustomizev1.GroupVersion.WithKind("Kustomization")
emptyAPIGroup := ""
kustomization := kustomizev1.Kustomization{ kustomization := kustomizev1.Kustomization{
TypeMeta: metav1.TypeMeta{ TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind, Kind: gvk.Kind,
@@ -152,10 +156,9 @@ func generateSyncManifests(url, name, namespace, targetPath, tmpDir string, inte
}, },
Path: fmt.Sprintf("./%s", strings.TrimPrefix(targetPath, "./")), Path: fmt.Sprintf("./%s", strings.TrimPrefix(targetPath, "./")),
Prune: true, Prune: true,
SourceRef: corev1.TypedLocalObjectReference{ SourceRef: kustomizev1.CrossNamespaceObjectReference{
APIGroup: &emptyAPIGroup, Kind: sourcev1.GitRepositoryKind,
Kind: "GitRepository", Name: name,
Name: name,
}, },
}, },
} }
@@ -178,7 +181,7 @@ func applySyncManifests(ctx context.Context, kubeClient client.Client, name, nam
return err return err
} }
logWaiting("waiting for cluster sync") logger.Waitingf("waiting for cluster sync")
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(pollInterval, timeout,
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil { isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {

View File

@@ -27,16 +27,15 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fluxcd/toolkit/pkg/git" "github.com/fluxcd/pkg/git"
) )
var bootstrapGitHubCmd = &cobra.Command{ var bootstrapGitHubCmd = &cobra.Command{
Use: "github", Use: "github",
Short: "Bootstrap GitHub repository", Short: "Bootstrap toolkit components in a GitHub repository",
Long: ` Long: `The bootstrap github command creates the GitHub repository if it doesn't exists and
The bootstrap command creates the GitHub repository if it doesn't exists and
commits the toolkit components manifests to the master branch. commits the toolkit components manifests to the master branch.
Then it configure the target cluster to synchronize with the repository. Then it configures the target cluster to synchronize with the repository.
If the toolkit components are present on the cluster, If the toolkit components are present on the cluster,
the bootstrap command will perform an upgrade if needed.`, the bootstrap command will perform an upgrade if needed.`,
Example: ` # Create a GitHub personal access token and export it as an env var Example: ` # Create a GitHub personal access token and export it as an env var
@@ -119,13 +118,13 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
defer cancel() defer cancel()
// create GitHub repository if doesn't exists // create GitHub repository if doesn't exists
logAction("connecting to %s", ghHostname) logger.Actionf("connecting to %s", ghHostname)
changed, err := provider.CreateRepository(ctx, repository) changed, err := provider.CreateRepository(ctx, repository)
if err != nil { if err != nil {
return err return err
} }
if changed { if changed {
logSuccess("repository created") logger.Successf("repository created")
} }
withErrors := false withErrors := false
@@ -133,10 +132,10 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if !ghPersonal { if !ghPersonal {
for _, team := range ghTeams { for _, team := range ghTeams {
if changed, err := provider.AddTeam(ctx, repository, team, ghDefaultPermission); err != nil { if changed, err := provider.AddTeam(ctx, repository, team, ghDefaultPermission); err != nil {
logFailure(err.Error()) logger.Failuref(err.Error())
withErrors = true withErrors = true
} else if changed { } else if changed {
logSuccess("%s team access granted", team) logger.Successf("%s team access granted", team)
} }
} }
} }
@@ -145,10 +144,10 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil { if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
return err return err
} }
logSuccess("repository cloned") logger.Successf("repository cloned")
// generate install manifests // generate install manifests
logGenerate("generating manifests") logger.Generatef("generating manifests")
manifest, err := generateInstallManifests(ghPath, namespace, tmpDir) manifest, err := generateInstallManifests(ghPath, namespace, tmpDir)
if err != nil { if err != nil {
return err return err
@@ -165,9 +164,9 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if err := repository.Push(ctx); err != nil { if err := repository.Push(ctx); err != nil {
return err return err
} }
logSuccess("components manifests pushed") logger.Successf("components manifests pushed")
} else { } else {
logSuccess("components are up to date") logger.Successf("components are up to date")
} }
// determine if repo synchronization is working // determine if repo synchronization is working
@@ -175,16 +174,16 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if isInstall { if isInstall {
// apply install manifests // apply install manifests
logAction("installing components in %s namespace", namespace) 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 return err
} }
logSuccess("install completed") logger.Successf("install completed")
} }
// setup SSH deploy key // setup SSH deploy key
if shouldCreateDeployKey(ctx, kubeClient, namespace) { if shouldCreateDeployKey(ctx, kubeClient, namespace) {
logAction("configuring deploy key") logger.Actionf("configuring deploy key")
u, err := url.Parse(repository.GetSSH()) u, err := url.Parse(repository.GetSSH())
if err != nil { if err != nil {
return fmt.Errorf("git URL parse failed: %w", err) return fmt.Errorf("git URL parse failed: %w", err)
@@ -203,14 +202,14 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil { if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
return err return err
} else if changed { } else if changed {
logSuccess("deploy key configured") logger.Successf("deploy key configured")
} }
} }
// configure repo synchronization // configure repo synchronization
if isInstall { if isInstall {
// generate source and kustomization manifests // generate source and kustomization manifests
logAction("generating sync manifests") logger.Actionf("generating sync manifests")
if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, ghPath, tmpDir, ghInterval); err != nil { if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
return err return err
} }
@@ -222,11 +221,11 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if err := repository.Push(ctx); err != nil { if err := repository.Push(ctx); err != nil {
return err return err
} }
logSuccess("sync manifests pushed") logger.Successf("sync manifests pushed")
} }
// apply manifests and waiting for sync // apply manifests and waiting for sync
logAction("applying sync manifests") logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil { if err := applySyncManifests(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil {
return err return err
} }
@@ -236,6 +235,6 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("bootstrap completed with errors") return fmt.Errorf("bootstrap completed with errors")
} }
logSuccess("bootstrap finished") logger.Successf("bootstrap finished")
return nil return nil
} }

View File

@@ -27,16 +27,15 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fluxcd/toolkit/pkg/git" "github.com/fluxcd/pkg/git"
) )
var bootstrapGitLabCmd = &cobra.Command{ var bootstrapGitLabCmd = &cobra.Command{
Use: "gitlab", Use: "gitlab",
Short: "Bootstrap GitLab repository", Short: "Bootstrap toolkit components in a GitLab repository",
Long: ` Long: `The bootstrap gitlab command creates the GitLab repository if it doesn't exists and
The bootstrap command creates the GitLab repository if it doesn't exists and
commits the toolkit components manifests to the master branch. commits the toolkit components manifests to the master branch.
Then it configure the target cluster to synchronize with the repository. Then it configures the target cluster to synchronize with the repository.
If the toolkit components are present on the cluster, If the toolkit components are present on the cluster,
the bootstrap command will perform an upgrade if needed.`, the bootstrap command will perform an upgrade if needed.`,
Example: ` # Create a GitLab API token and export it as an env var Example: ` # Create a GitLab API token and export it as an env var
@@ -110,23 +109,23 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
defer cancel() defer cancel()
// create GitLab project if doesn't exists // create GitLab project if doesn't exists
logAction("connecting to %s", glHostname) logger.Actionf("connecting to %s", glHostname)
changed, err := provider.CreateRepository(ctx, repository) changed, err := provider.CreateRepository(ctx, repository)
if err != nil { if err != nil {
return err return err
} }
if changed { if changed {
logSuccess("repository created") logger.Successf("repository created")
} }
// clone repository and checkout the master branch // clone repository and checkout the master branch
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil { if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
return err return err
} }
logSuccess("repository cloned") logger.Successf("repository cloned")
// generate install manifests // generate install manifests
logGenerate("generating manifests") logger.Generatef("generating manifests")
manifest, err := generateInstallManifests(glPath, namespace, tmpDir) manifest, err := generateInstallManifests(glPath, namespace, tmpDir)
if err != nil { if err != nil {
return err return err
@@ -143,9 +142,9 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
if err := repository.Push(ctx); err != nil { if err := repository.Push(ctx); err != nil {
return err return err
} }
logSuccess("components manifests pushed") logger.Successf("components manifests pushed")
} else { } else {
logSuccess("components are up to date") logger.Successf("components are up to date")
} }
// determine if repo synchronization is working // determine if repo synchronization is working
@@ -153,16 +152,16 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
if isInstall { if isInstall {
// apply install manifests // apply install manifests
logAction("installing components in %s namespace", namespace) 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 return err
} }
logSuccess("install completed") logger.Successf("install completed")
} }
// setup SSH deploy key // setup SSH deploy key
if shouldCreateDeployKey(ctx, kubeClient, namespace) { if shouldCreateDeployKey(ctx, kubeClient, namespace) {
logAction("configuring deploy key") logger.Actionf("configuring deploy key")
u, err := url.Parse(repository.GetSSH()) u, err := url.Parse(repository.GetSSH())
if err != nil { if err != nil {
return fmt.Errorf("git URL parse failed: %w", err) return fmt.Errorf("git URL parse failed: %w", err)
@@ -181,14 +180,14 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil { if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
return err return err
} else if changed { } else if changed {
logSuccess("deploy key configured") logger.Successf("deploy key configured")
} }
} }
// configure repo synchronization // configure repo synchronization
if isInstall { if isInstall {
// generate source and kustomization manifests // generate source and kustomization manifests
logAction("generating sync manifests") logger.Actionf("generating sync manifests")
if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, glPath, tmpDir, glInterval); err != nil { if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, glPath, tmpDir, glInterval); err != nil {
return err return err
} }
@@ -200,16 +199,16 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
if err := repository.Push(ctx); err != nil { if err := repository.Push(ctx); err != nil {
return err return err
} }
logSuccess("sync manifests pushed") logger.Successf("sync manifests pushed")
} }
// apply manifests and waiting for sync // apply manifests and waiting for sync
logAction("applying sync manifests") logger.Actionf("applying sync manifests")
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, glPath, tmpDir); err != nil { if err := applySyncManifests(ctx, kubeClient, namespace, namespace, glPath, tmpDir); err != nil {
return err return err
} }
} }
logSuccess("bootstrap finished") logger.Successf("bootstrap finished")
return nil return nil
} }

View File

@@ -32,26 +32,27 @@ import (
var checkCmd = &cobra.Command{ var checkCmd = &cobra.Command{
Use: "check", Use: "check",
Short: "Check requirements and installation", Short: "Check requirements and installation",
Long: ` Long: `The check command will perform a series of checks to validate that
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.`, the local environment is configured correctly and if the installed components are healthy.`,
Example: ` # Run pre-installation checks Example: ` # Run pre-installation checks
check --pre tk check --pre
# Run installation checks # Run installation checks
check tk check
`, `,
RunE: runCheckCmd, RunE: runCheckCmd,
} }
var ( var (
checkPre bool checkPre bool
checkComponents []string
) )
func init() { func init() {
checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false, checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false,
"only run pre-installation checks") "only run pre-installation checks")
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaultComponents,
"list of components, accepts comma-separated values")
rootCmd.AddCommand(checkCmd) rootCmd.AddCommand(checkCmd)
} }
@@ -59,7 +60,7 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel() defer cancel()
logAction("checking prerequisites") logger.Actionf("checking prerequisites")
checkFailed := false checkFailed := false
if !kubectlCheck(ctx, ">=1.18.0") { if !kubectlCheck(ctx, ">=1.18.0") {
@@ -74,83 +75,83 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
if checkFailed { if checkFailed {
os.Exit(1) os.Exit(1)
} }
logSuccess("prerequisites checks passed") logger.Successf("prerequisites checks passed")
return nil return nil
} }
logAction("checking controllers") logger.Actionf("checking controllers")
if !componentsCheck() { if !componentsCheck() {
checkFailed = true checkFailed = true
} }
if checkFailed { if checkFailed {
os.Exit(1) os.Exit(1)
} }
logSuccess("all checks passed") logger.Successf("all checks passed")
return nil return nil
} }
func kubectlCheck(ctx context.Context, version string) bool { func kubectlCheck(ctx context.Context, version string) bool {
_, err := exec.LookPath("kubectl") _, err := exec.LookPath("kubectl")
if err != nil { if err != nil {
logFailure("kubectl not found") logger.Failuref("kubectl not found")
return false return false
} }
command := "kubectl version --client --short | awk '{ print $3 }'" command := "kubectl version --client --short | awk '{ print $3 }'"
output, err := utils.execCommand(ctx, ModeCapture, command) output, err := utils.execCommand(ctx, ModeCapture, command)
if err != nil { if err != nil {
logFailure("kubectl version can't be determined") logger.Failuref("kubectl version can't be determined")
return false return false
} }
v, err := semver.ParseTolerant(output) v, err := semver.ParseTolerant(output)
if err != nil { if err != nil {
logFailure("kubectl version can't be parsed") logger.Failuref("kubectl version can't be parsed")
return false return false
} }
rng, _ := semver.ParseRange(version) rng, _ := semver.ParseRange(version)
if !rng(v) { if !rng(v) {
logFailure("kubectl version must be %s", version) logger.Failuref("kubectl version must be %s", version)
return false return false
} }
logSuccess("kubectl %s %s", v.String(), version) logger.Successf("kubectl %s %s", v.String(), version)
return true return true
} }
func kubernetesCheck(version string) bool { func kubernetesCheck(version string) bool {
cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil { if err != nil {
logFailure("Kubernetes client initialization failed: %s", err.Error()) logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false return false
} }
client, err := kubernetes.NewForConfig(cfg) client, err := kubernetes.NewForConfig(cfg)
if err != nil { if err != nil {
logFailure("Kubernetes client initialization failed: %s", err.Error()) logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
return false return false
} }
ver, err := client.Discovery().ServerVersion() ver, err := client.Discovery().ServerVersion()
if err != nil { if err != nil {
logFailure("Kubernetes API call failed: %s", err.Error()) logger.Failuref("Kubernetes API call failed: %s", err.Error())
return false return false
} }
v, err := semver.ParseTolerant(ver.String()) v, err := semver.ParseTolerant(ver.String())
if err != nil { if err != nil {
logFailure("Kubernetes version can't be determined") logger.Failuref("Kubernetes version can't be determined")
return false return false
} }
rng, _ := semver.ParseRange(version) rng, _ := semver.ParseRange(version)
if !rng(v) { if !rng(v) {
logFailure("Kubernetes version must be %s", version) logger.Failuref("Kubernetes version must be %s", version)
return false return false
} }
logSuccess("Kubernetes %s %s", v.String(), version) logger.Successf("Kubernetes %s %s", v.String(), version)
return true return true
} }
@@ -159,14 +160,14 @@ func componentsCheck() bool {
defer cancel() defer cancel()
ok := true ok := true
for _, deployment := range components { for _, deployment := range checkComponents {
command := fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s", command := fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
namespace, deployment, timeout.String()) namespace, deployment, timeout.String())
if output, err := utils.execCommand(ctx, ModeCapture, command); err != nil { if output, err := utils.execCommand(ctx, ModeCapture, command); err != nil {
logFailure("%s: %s", deployment, strings.TrimSuffix(output, "\n")) logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
ok = false ok = false
} else { } else {
logSuccess("%s is healthy", deployment) logger.Successf("%s is healthy", deployment)
} }
} }
return ok return ok

View File

@@ -24,7 +24,8 @@ import (
var createCmd = &cobra.Command{ var createCmd = &cobra.Command{
Use: "create", Use: "create",
Short: "Create commands", Short: "Create or update sources and resources",
Long: "The create sub-commands generate sources and resources.",
} }
var ( var (
@@ -34,6 +35,6 @@ var (
func init() { func init() {
createCmd.PersistentFlags().DurationVarP(&interval, "interval", "", time.Minute, "source sync interval") createCmd.PersistentFlags().DurationVarP(&interval, "interval", "", time.Minute, "source sync interval")
createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in yaml format to stdout") createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in YAML format to stdout")
rootCmd.AddCommand(createCmd) rootCmd.AddCommand(createCmd)
} }

View File

@@ -37,11 +37,9 @@ import (
var createKsCmd = &cobra.Command{ var createKsCmd = &cobra.Command{
Use: "kustomization [name]", Use: "kustomization [name]",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Create or update a kustomization resource", Short: "Create or update a Kustomization resource",
Long: ` Long: "The kustomization source create command generates a Kustomize resource for a given GitRepository source.",
The kustomization source command generates a kustomization.kustomize.fluxcd.io resource for a given GitRepository source. Example: ` # Create a Kustomization resource from a source at a given path
API spec: https://github.com/fluxcd/kustomize-controller/tree/master/docs/spec/v1alpha1`,
Example: ` # Create a kustomization from a source at a given path
create kustomization contour \ create kustomization contour \
--source=contour \ --source=contour \
--path="./examples/contour/" \ --path="./examples/contour/" \
@@ -52,7 +50,7 @@ API spec: https://github.com/fluxcd/kustomize-controller/tree/master/docs/spec/v
--health-check="DaemonSet/envoy.projectcontour" \ --health-check="DaemonSet/envoy.projectcontour" \
--health-check-timeout=3m --health-check-timeout=3m
# Create a kustomization that depends on the previous one # Create a Kustomization resource that depends on the previous one
create kustomization webapp \ create kustomization webapp \
--depends-on=contour \ --depends-on=contour \
--source=webapp \ --source=webapp \
@@ -61,7 +59,7 @@ API spec: https://github.com/fluxcd/kustomize-controller/tree/master/docs/spec/v
--interval=5m \ --interval=5m \
--validate=client --validate=client
# Create a kustomization that runs under a service account # Create a Kustomization resource that runs under a service account
create kustomization webapp \ create kustomization webapp \
--source=webapp \ --source=webapp \
--path="./deploy/overlays/staging" \ --path="./deploy/overlays/staging" \
@@ -88,12 +86,12 @@ var (
func init() { func init() {
createKsCmd.Flags().StringVar(&ksSource, "source", "", "GitRepository name") createKsCmd.Flags().StringVar(&ksSource, "source", "", "GitRepository name")
createKsCmd.Flags().StringVar(&ksPath, "path", "./", "path to the directory containing the kustomization file") createKsCmd.Flags().StringVar(&ksPath, "path", "./", "path to the directory containing the Kustomization file")
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection") 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().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().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(&ksValidate, "validate", "", "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().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(&ksSAName, "sa-name", "", "service account name")
createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace") createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace")
createCmd.AddCommand(createKsCmd) createCmd.AddCommand(createKsCmd)
@@ -124,10 +122,9 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
} }
if !export { if !export {
logGenerate("generating kustomization") logger.Generatef("generating kustomization")
} }
emptyAPIGroup := ""
kustomization := kustomizev1.Kustomization{ kustomization := kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
@@ -140,10 +137,9 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
}, },
Path: ksPath, Path: ksPath,
Prune: ksPrune, Prune: ksPrune,
SourceRef: corev1.TypedLocalObjectReference{ SourceRef: kustomizev1.CrossNamespaceObjectReference{
APIGroup: &emptyAPIGroup, Kind: sourcev1.GitRepositoryKind,
Kind: "GitRepository", Name: ksSource,
Name: ksSource,
}, },
Suspend: false, Suspend: false,
Validation: ksValidate, Validation: ksValidate,
@@ -194,18 +190,18 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
return exportKs(kustomization) return exportKs(kustomization)
} }
logAction("applying kustomization") logger.Actionf("applying kustomization")
if err := upsertKustomization(ctx, kubeClient, kustomization); err != nil { if err := upsertKustomization(ctx, kubeClient, kustomization); err != nil {
return err return err
} }
logWaiting("waiting for kustomization sync") logger.Waitingf("waiting for kustomization sync")
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(pollInterval, timeout,
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil { isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
return err return err
} }
logSuccess("kustomization %s is ready", name) logger.Successf("kustomization %s is ready", name)
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: namespace, Namespace: namespace,
@@ -217,7 +213,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
} }
if kustomization.Status.LastAppliedRevision != "" { if kustomization.Status.LastAppliedRevision != "" {
logSuccess("applied revision %s", kustomization.Status.LastAppliedRevision) logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
} else { } else {
return fmt.Errorf("kustomization sync failed") return fmt.Errorf("kustomization sync failed")
} }
@@ -238,7 +234,7 @@ func upsertKustomization(ctx context.Context, kubeClient client.Client, kustomiz
if err := kubeClient.Create(ctx, &kustomization); err != nil { if err := kubeClient.Create(ctx, &kustomization); err != nil {
return err return err
} else { } else {
logSuccess("kustomization created") logger.Successf("kustomization created")
return nil return nil
} }
} }
@@ -250,7 +246,7 @@ func upsertKustomization(ctx context.Context, kubeClient client.Client, kustomiz
return err return err
} }
logSuccess("kustomization updated") logger.Successf("kustomization updated")
return nil return nil
} }

View File

@@ -22,7 +22,8 @@ import (
var createSourceCmd = &cobra.Command{ var createSourceCmd = &cobra.Command{
Use: "source", Use: "source",
Short: "Create source commands", Short: "Create or update sources",
Long: "The create source sub-commands generate sources.",
} }
func init() { func init() {

View File

@@ -35,14 +35,14 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/toolkit/pkg/ssh" "github.com/fluxcd/pkg/ssh"
) )
var createSourceGitCmd = &cobra.Command{ var createSourceGitCmd = &cobra.Command{
Use: "git [name]", Use: "git [name]",
Short: "Create or update a git source", Short: "Create or update a GitRepository source",
Long: ` Long: `
The create source command generates a GitRepository resource and waits for it to sync. The create source git command generates a GitRepository resource and waits for it to sync.
For Git over SSH, host and SSH keys are automatically generated and stored in a Kubernetes secret. 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.`, 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 Example: ` # Create a source from a public Git repository master branch
@@ -166,7 +166,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
withAuth := false withAuth := false
// TODO(hidde): move all auth prep to separate func? // TODO(hidde): move all auth prep to separate func?
if u.Scheme == "ssh" { if u.Scheme == "ssh" {
logAction("generating deploy key pair") logger.Actionf("generating deploy key pair")
pair, err := generateKeyPair(ctx) pair, err := generateKeyPair(ctx)
if err != nil { if err != nil {
return err return err
@@ -181,15 +181,15 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("aborting") return fmt.Errorf("aborting")
} }
logAction("collecting preferred public key from SSH server") logger.Actionf("collecting preferred public key from SSH server")
hostKey, err := scanHostKey(ctx, u) hostKey, err := scanHostKey(ctx, u)
if err != nil { if err != nil {
return err return err
} }
logSuccess("collected public key from SSH server:") logger.Successf("collected public key from SSH server:")
fmt.Printf("%s", hostKey) fmt.Printf("%s", hostKey)
logAction("applying secret with keys") logger.Actionf("applying secret with keys")
secret := corev1.Secret{ secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
@@ -206,7 +206,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
withAuth = true withAuth = true
} else if sourceGitUsername != "" && sourceGitPassword != "" { } else if sourceGitUsername != "" && sourceGitPassword != "" {
logAction("applying secret with basic auth credentials") logger.Actionf("applying secret with basic auth credentials")
secret := corev1.Secret{ secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
@@ -224,10 +224,10 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
if withAuth { if withAuth {
logSuccess("authentication configured") logger.Successf("authentication configured")
} }
logGenerate("generating source") logger.Generatef("generating source")
if withAuth { if withAuth {
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{ gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
@@ -235,18 +235,18 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
logAction("applying source") logger.Actionf("applying source")
if err := upsertGitRepository(ctx, kubeClient, gitRepository); err != nil { if err := upsertGitRepository(ctx, kubeClient, gitRepository); err != nil {
return err return err
} }
logWaiting("waiting for git sync") logger.Waitingf("waiting for git sync")
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(pollInterval, timeout,
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil { isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
return err return err
} }
logSuccess("git sync completed") logger.Successf("git sync completed")
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: namespace, Namespace: namespace,
@@ -258,7 +258,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
if gitRepository.Status.Artifact != nil { if gitRepository.Status.Artifact != nil {
logSuccess("fetched revision: %s", gitRepository.Status.Artifact.Revision) logger.Successf("fetched revision: %s", gitRepository.Status.Artifact.Revision)
} else { } else {
return fmt.Errorf("git sync failed, artifact not found") return fmt.Errorf("git sync failed, artifact not found")
} }
@@ -336,7 +336,7 @@ func upsertGitRepository(ctx context.Context, kubeClient client.Client, gitRepos
if err := kubeClient.Create(ctx, &gitRepository); err != nil { if err := kubeClient.Create(ctx, &gitRepository); err != nil {
return err return err
} else { } else {
logSuccess("source created") logger.Successf("source created")
return nil return nil
} }
} }
@@ -348,7 +348,7 @@ func upsertGitRepository(ctx context.Context, kubeClient client.Client, gitRepos
return err return err
} }
logSuccess("source updated") logger.Successf("source updated")
return nil return nil
} }

View File

@@ -22,7 +22,8 @@ import (
var deleteCmd = &cobra.Command{ var deleteCmd = &cobra.Command{
Use: "delete", Use: "delete",
Short: "Delete commands", Short: "Delete sources and resources",
Long: "The delete sub-commands delete sources and resources.",
} }
var ( var (

View File

@@ -29,7 +29,8 @@ import (
var deleteKsCmd = &cobra.Command{ var deleteKsCmd = &cobra.Command{
Use: "kustomization [name]", Use: "kustomization [name]",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Delete kustomization", Short: "Delete a Kustomization resource",
Long: "The delete kustomization command deletes the given Kustomization from the cluster.",
RunE: deleteKsCmdRun, RunE: deleteKsCmdRun,
} }
@@ -64,7 +65,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
if !deleteSilent { if !deleteSilent {
if !kustomization.Spec.Suspend { if !kustomization.Spec.Suspend {
logWaiting("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name) logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s kustomization!", name)
} }
prompt := promptui.Prompt{ prompt := promptui.Prompt{
Label: "Are you sure you want to delete this kustomization", Label: "Are you sure you want to delete this kustomization",
@@ -75,12 +76,12 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
logAction("deleting kustomization %s in %s namespace", name, namespace) logger.Actionf("deleting kustomization %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &kustomization) err = kubeClient.Delete(ctx, &kustomization)
if err != nil { if err != nil {
return err return err
} }
logSuccess("kustomization deleted") logger.Successf("kustomization deleted")
return nil return nil
} }

View File

@@ -22,7 +22,8 @@ import (
var deleteSourceCmd = &cobra.Command{ var deleteSourceCmd = &cobra.Command{
Use: "source", Use: "source",
Short: "Delete sources commands", Short: "Delete sources",
Long: "The delete source sub-commands delete sources.",
} }
func init() { func init() {

View File

@@ -28,7 +28,8 @@ import (
var deleteSourceGitCmd = &cobra.Command{ var deleteSourceGitCmd = &cobra.Command{
Use: "git [name]", Use: "git [name]",
Short: "Delete git source", Short: "Delete a GitRepository source",
Long: "The delete source git command deletes the given GitRepository from the cluster.",
RunE: deleteSourceGitCmdRun, RunE: deleteSourceGitCmdRun,
} }
@@ -71,12 +72,12 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
} }
logAction("deleting source %s in %s namespace", name, namespace) logger.Actionf("deleting source %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &git) err = kubeClient.Delete(ctx, &git)
if err != nil { if err != nil {
return err return err
} }
logSuccess("source deleted") logger.Successf("source deleted")
return nil return nil
} }

View File

@@ -22,7 +22,8 @@ import (
var exportCmd = &cobra.Command{ var exportCmd = &cobra.Command{
Use: "export", Use: "export",
Short: "Export commands", Short: "Export resources in YAML format",
Long: "The export sub-commands export resources in YAML format.",
} }
var ( var (

View File

@@ -31,11 +31,12 @@ import (
var exportKsCmd = &cobra.Command{ var exportKsCmd = &cobra.Command{
Use: "kustomization [name]", Use: "kustomization [name]",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Export kustomization in YAML format", Short: "Export Kustomization resources in YAML format",
Example: ` # Export all kustomizations Long: "The export kustomization command exports one or all Kustomization resources in YAML format.",
Example: ` # Export all Kustomization resources
export kustomization --all > kustomizations.yaml export kustomization --all > kustomizations.yaml
# Export a kustomization # Export a Kustomization
export kustomization my-app > kustomization.yaml export kustomization my-app > kustomization.yaml
`, `,
RunE: exportKsCmdRun, RunE: exportKsCmdRun,
@@ -66,7 +67,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
logFailure("no kustomizations found in %s namespace", namespace) logger.Failuref("no kustomizations found in %s namespace", namespace)
return nil return nil
} }

View File

@@ -22,7 +22,8 @@ import (
var exportSourceCmd = &cobra.Command{ var exportSourceCmd = &cobra.Command{
Use: "source", Use: "source",
Short: "Export source commands", Short: "Export sources",
Long: "The export source sub-commands export sources in YAML format.",
} }
var ( var (

View File

@@ -31,11 +31,12 @@ import (
var exportSourceGitCmd = &cobra.Command{ var exportSourceGitCmd = &cobra.Command{
Use: "git [name]", Use: "git [name]",
Short: "Export git sources in YAML format", Short: "Export GitRepository sources in YAML format",
Example: ` # Export all git sources 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 export source git --all > sources.yaml
# Export a git source including the SSH keys or basic auth credentials # Export a GitRepository source including the SSH key pair or basic auth credentials
export source git my-private-repo --with-credentials > source.yaml export source git my-private-repo --with-credentials > source.yaml
`, `,
RunE: exportSourceGitCmdRun, RunE: exportSourceGitCmdRun,
@@ -66,7 +67,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
logFailure("no source found in %s namespace", namespace) logger.Failuref("no source found in %s namespace", namespace)
return nil return nil
} }

View File

@@ -19,6 +19,7 @@ package main
import ( import (
"crypto/elliptic" "crypto/elliptic"
"fmt" "fmt"
"sort"
"strconv" "strconv"
"strings" "strings"
) )
@@ -124,5 +125,6 @@ func ecdsaCurves() []string {
for k := range supportedECDSACurves { for k := range supportedECDSACurves {
keys = append(keys, k) keys = append(keys, k)
} }
sort.Strings(keys)
return keys return keys
} }

View File

@@ -22,7 +22,8 @@ import (
var getCmd = &cobra.Command{ var getCmd = &cobra.Command{
Use: "get", Use: "get",
Short: "Get commands", Short: "Get sources and resources",
Long: "The get sub-commands print the statuses of sources and resources.",
} }
func init() { func init() {

View File

@@ -28,10 +28,9 @@ import (
var getKsCmd = &cobra.Command{ var getKsCmd = &cobra.Command{
Use: "kustomizations", Use: "kustomizations",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Get kustomizations status", Short: "Get Kustomization source statuses",
Long: ` Long: "The get kustomizations command prints the statuses of the resources.",
The get kustomizations command prints the status of the resources.`, RunE: getKsCmdRun,
RunE: getKsCmdRun,
} }
func init() { func init() {
@@ -54,13 +53,13 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
logFailure("no kustomizations found in %s namespace", namespace) logger.Failuref("no kustomizations found in %s namespace", namespace)
return nil return nil
} }
for _, kustomization := range list.Items { for _, kustomization := range list.Items {
if kustomization.Spec.Suspend { if kustomization.Spec.Suspend {
logSuccess("%s is suspended", kustomization.GetName()) logger.Successf("%s is suspended", kustomization.GetName())
continue continue
} }
isInitialized := false isInitialized := false
@@ -68,19 +67,19 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
if condition.Type == kustomizev1.ReadyCondition { if condition.Type == kustomizev1.ReadyCondition {
if condition.Status != corev1.ConditionFalse { if condition.Status != corev1.ConditionFalse {
if kustomization.Status.LastAppliedRevision != "" { if kustomization.Status.LastAppliedRevision != "" {
logSuccess("%s last applied revision %s", kustomization.GetName(), kustomization.Status.LastAppliedRevision) logger.Successf("%s last applied revision %s", kustomization.GetName(), kustomization.Status.LastAppliedRevision)
} else { } else {
logSuccess("%s reconciling", kustomization.GetName()) logger.Successf("%s reconciling", kustomization.GetName())
} }
} else { } else {
logFailure("%s %s", kustomization.GetName(), condition.Message) logger.Failuref("%s %s", kustomization.GetName(), condition.Message)
} }
isInitialized = true isInitialized = true
break break
} }
} }
if !isInitialized { if !isInitialized {
logFailure("%s is not ready", kustomization.GetName()) logger.Failuref("%s is not ready", kustomization.GetName())
} }
} }
return nil return nil

View File

@@ -22,7 +22,8 @@ import (
var getSourceCmd = &cobra.Command{ var getSourceCmd = &cobra.Command{
Use: "sources", Use: "sources",
Short: "Get sources commands", Short: "Get source statuses",
Long: "The get source sub-commands print the statuses of the sources.",
} }
func init() { func init() {

View File

@@ -27,10 +27,9 @@ import (
var getSourceGitCmd = &cobra.Command{ var getSourceGitCmd = &cobra.Command{
Use: "git", Use: "git",
Short: "Get git sources status", Short: "Get GitRepository source statuses",
Long: ` Long: "The get sources git command prints the status of the GitRepository sources.",
The get sources command prints the status of the git resources.`, RunE: getSourceGitCmdRun,
RunE: getSourceGitCmdRun,
} }
func init() { func init() {
@@ -53,7 +52,7 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
logFailure("no sources found in %s namespace", namespace) logger.Failuref("no sources found in %s namespace", namespace)
return nil return nil
} }
@@ -62,16 +61,16 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
for _, condition := range source.Status.Conditions { for _, condition := range source.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition { if condition.Type == sourcev1.ReadyCondition {
if condition.Status != corev1.ConditionFalse { if condition.Status != corev1.ConditionFalse {
logSuccess("%s last fetched revision: %s", source.GetName(), source.Status.Artifact.Revision) logger.Successf("%s last fetched revision: %s", source.GetName(), source.Status.Artifact.Revision)
} else { } else {
logFailure("%s %s", source.GetName(), condition.Message) logger.Failuref("%s %s", source.GetName(), condition.Message)
} }
isInitialized = true isInitialized = true
break break
} }
} }
if !isInitialized { if !isInitialized {
logFailure("%s is not ready", source.GetName()) logger.Failuref("%s is not ready", source.GetName())
} }
} }
return nil return nil

View File

@@ -19,11 +19,14 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/fluxcd/pkg/untar"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
@@ -33,32 +36,40 @@ import (
var installCmd = &cobra.Command{ var installCmd = &cobra.Command{
Use: "install", Use: "install",
Short: "Install the toolkit components", Short: "Install the toolkit components",
Long: ` Long: `The install command deploys the toolkit components in the specified namespace.
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.`, If a previous version is installed, then an in-place upgrade will be performed.`,
Example: ` # Install the latest version in the gitops-systems namespace 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 # 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 # 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, RunE: installCmdRun,
} }
var ( var (
installExport bool
installDryRun bool installDryRun bool
installManifestsPath string installManifestsPath string
installVersion string installVersion string
installComponents []string
) )
func init() { func init() {
installCmd.Flags().BoolVar(&installExport, "export", false,
"write the install manifests to stdout and exit")
installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false, installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false,
"only print the object that would be applied") "only print the object that would be applied")
installCmd.Flags().StringVarP(&installVersion, "version", "v", "master", installCmd.Flags().StringVarP(&installVersion, "version", "v", defaultVersion,
"toolkit tag or branch") "toolkit version")
installCmd.Flags().StringSliceVar(&installComponents, "components", defaultComponents,
"list of components, accepts comma-separated values")
installCmd.Flags().StringVarP(&installManifestsPath, "manifests", "", "", installCmd.Flags().StringVarP(&installManifestsPath, "manifests", "", "",
"path to the manifest directory, dev only") "path to the manifest directory, dev only")
rootCmd.AddCommand(installCmd) rootCmd.AddCommand(installCmd)
@@ -82,9 +93,11 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
logGenerate("generating manifests") if !installExport {
logger.Generatef("generating manifests")
}
if kustomizePath == "" { if kustomizePath == "" {
err = genInstallManifests(installVersion, namespace, components, tmpDir) err = genInstallManifests(installVersion, namespace, installComponents, tmpDir)
if err != nil { if err != nil {
return fmt.Errorf("install failed: %w", err) return fmt.Errorf("install failed: %w", err)
} }
@@ -102,11 +115,17 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
} else { } else {
if verbose { if verbose {
fmt.Print(yaml) fmt.Print(yaml)
} else if installExport {
fmt.Println("---")
fmt.Println("# GitOps Toolkit revision", installVersion, time.Now().Format(time.RFC3339))
fmt.Print(yaml)
fmt.Println("---")
return nil
} }
} }
logSuccess("manifests build completed") logger.Successf("manifests build completed")
logAction("installing components in %s namespace", namespace) logger.Actionf("installing components in %s namespace", namespace)
applyOutput := ModeStderrOS applyOutput := ModeStderrOS
if verbose { if verbose {
applyOutput = ModeOS applyOutput = ModeOS
@@ -122,24 +141,24 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
} }
if installDryRun { if installDryRun {
logSuccess("install dry-run finished") logger.Successf("install dry-run finished")
return nil return nil
} else { } else {
logSuccess("install completed") logger.Successf("install completed")
} }
logWaiting("verifying installation") logger.Waitingf("verifying installation")
for _, deployment := range components { for _, deployment := range installComponents {
command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s", command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
namespace, deployment, timeout.String()) namespace, deployment, timeout.String())
if _, err := utils.execCommand(ctx, applyOutput, command); err != nil { if _, err := utils.execCommand(ctx, applyOutput, command); err != nil {
return fmt.Errorf("install failed") return fmt.Errorf("install failed")
} else { } else {
logSuccess("%s ready", deployment) logger.Successf("%s ready", deployment)
} }
} }
logSuccess("install finished") logger.Successf("install finished")
return nil return nil
} }
@@ -172,10 +191,10 @@ transformers:
- labels.yaml - labels.yaml
resources: resources:
- namespace.yaml - namespace.yaml
- policies.yaml
- roles - roles
- github.com/fluxcd/toolkit/manifests/policies?ref={{$version}}
{{- range .Components }} {{- range .Components }}
- github.com/fluxcd/toolkit/manifests/bases/{{.}}?ref={{$version}} - {{.}}.yaml
{{- end }} {{- end }}
` `
@@ -183,10 +202,44 @@ var kustomizationRolesTmpl = `---
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
resources: resources:
- github.com/fluxcd/toolkit/manifests/rbac?ref={{.Version}} - rbac.yaml
nameSuffix: -{{.Namespace}} nameSuffix: -{{.Namespace}}
` `
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, tmpDir string) error { func genInstallManifests(version string, namespace string, components []string, tmpDir string) error {
model := struct { model := struct {
Version string Version string
@@ -198,6 +251,10 @@ func genInstallManifests(version string, namespace string, components []string,
Components: components, Components: components,
} }
if err := downloadManifests(version, tmpDir); err != nil {
return err
}
if err := utils.execTemplate(model, namespaceTmpl, path.Join(tmpDir, "namespace.yaml")); err != nil { if err := utils.execTemplate(model, namespaceTmpl, path.Join(tmpDir, "namespace.yaml")); err != nil {
return fmt.Errorf("generate namespace failed: %w", err) return fmt.Errorf("generate namespace failed: %w", err)
} }
@@ -218,6 +275,10 @@ func genInstallManifests(version string, namespace string, components []string,
return fmt.Errorf("generate roles failed: %w", err) 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 return nil
} }

View File

@@ -18,22 +18,24 @@ package main
import "fmt" import "fmt"
func logAction(format string, a ...interface{}) { type printLogger struct{}
func (l printLogger) Actionf(format string, a ...interface{}) {
fmt.Println(``, fmt.Sprintf(format, a...)) fmt.Println(``, fmt.Sprintf(format, a...))
} }
func logGenerate(format string, a ...interface{}) { func (l printLogger) Generatef(format string, a ...interface{}) {
fmt.Println(``, fmt.Sprintf(format, a...)) fmt.Println(``, fmt.Sprintf(format, a...))
} }
func logWaiting(format string, a ...interface{}) { func (l printLogger) Waitingf(format string, a ...interface{}) {
fmt.Println(``, fmt.Sprintf(format, a...)) fmt.Println(``, fmt.Sprintf(format, a...))
} }
func logSuccess(format string, a ...interface{}) { func (l printLogger) Successf(format string, a ...interface{}) {
fmt.Println(``, fmt.Sprintf(format, a...)) fmt.Println(``, fmt.Sprintf(format, a...))
} }
func logFailure(format string, a ...interface{}) { func (l printLogger) Failuref(format string, a ...interface{}) {
fmt.Println(``, fmt.Sprintf(format, a...)) fmt.Println(``, fmt.Sprintf(format, a...))
} }

View File

@@ -25,6 +25,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/cobra/doc" "github.com/spf13/cobra/doc"
_ "k8s.io/client-go/plugin/pkg/client/auth" _ "k8s.io/client-go/plugin/pkg/client/auth"
tklog "github.com/fluxcd/toolkit/pkg/log"
) )
var VERSION = "0.0.0-dev.0" var VERSION = "0.0.0-dev.0"
@@ -48,16 +50,16 @@ var rootCmd = &cobra.Command{
--branch=master \ --branch=master \
--interval=3m --interval=3m
# List git sources and their status # List GitRepository sources and their status
tk get sources git tk get sources git
# Trigger a git sync # Trigger a GitRepository source sync
tk sync source git webapp-latest tk sync source git webapp-latest
# Export git sources in YAML format # Export GitRepository sources in YAML format
tk export source git --all > sources.yaml tk export source git --all > sources.yaml
# Create a kustomization for deploying a series of microservices # Create a Kustomization for deploying a series of microservices
tk create kustomization webapp-dev \ tk create kustomization webapp-dev \
--source=webapp-latest \ --source=webapp-latest \
--path="./deploy/webapp/" \ --path="./deploy/webapp/" \
@@ -68,22 +70,22 @@ var rootCmd = &cobra.Command{
--health-check="Deployment/frontend.webapp" \ --health-check="Deployment/frontend.webapp" \
--health-check-timeout=2m --health-check-timeout=2m
# Trigger a git sync and apply changes if any # 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 # Suspend a Kustomization reconciliation
tk suspend kustomization webapp-dev tk suspend kustomization webapp-dev
# Export kustomizations in YAML format # Export Kustomizations in YAML format
tk export kustomization --all > kustomizations.yaml tk export kustomization --all > kustomizations.yaml
# Resume a kustomization reconciliation # Resume a Kustomization reconciliation
tk resume kustomization webapp-dev tk resume kustomization webapp-dev
# Delete a kustomization # Delete a Kustomization
tk delete kustomization webapp-dev tk delete kustomization webapp-dev
# Delete a git source # Delete a GitRepository source
tk delete source git webapp-latest tk delete source git webapp-latest
# Uninstall the toolkit and delete CRDs # Uninstall the toolkit and delete CRDs
@@ -96,21 +98,24 @@ var (
namespace string namespace string
timeout time.Duration timeout time.Duration
verbose bool verbose bool
components []string
utils Utils utils Utils
pollInterval = 2 * time.Second pollInterval = 2 * time.Second
logger tklog.Logger = printLogger{}
)
var (
defaultComponents = []string{"source-controller", "kustomize-controller", "helm-controller", "notification-controller"}
defaultVersion = "latest"
defaultNamespace = "gitops-system"
) )
func init() { func init() {
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "", "gitops-system", rootCmd.PersistentFlags().StringVar(&namespace, "namespace", defaultNamespace,
"the namespace scope for this operation") "the namespace scope for this operation")
rootCmd.PersistentFlags().DurationVarP(&timeout, "timeout", "", 5*time.Minute, rootCmd.PersistentFlags().DurationVarP(&timeout, "timeout", "", 5*time.Minute,
"timeout for this operation") "timeout for this operation")
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false, rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false,
"print generated objects") "print generated objects")
rootCmd.PersistentFlags().StringSliceVar(&components, "components",
[]string{"source-controller", "kustomize-controller"},
"list of components, accepts comma-separated values")
} }
func main() { func main() {
@@ -118,7 +123,7 @@ func main() {
generateDocs() generateDocs()
kubeconfigFlag() kubeconfigFlag()
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
logFailure("%v", err) logger.Failuref("%v", err)
os.Exit(1) os.Exit(1)
} }
} }

View File

@@ -20,11 +20,12 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var syncCmd = &cobra.Command{ var reconcileCmd = &cobra.Command{
Use: "sync", Use: "reconcile",
Short: "Synchronize commands", Short: "Reconcile sources and resources",
Long: "The reconcile sub-commands trigger a reconciliation of sources and resources.",
} }
func init() { 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" "k8s.io/apimachinery/pkg/util/wait"
) )
var syncKsCmd = &cobra.Command{ var reconcileKsCmd = &cobra.Command{
Use: "kustomization [name]", Use: "kustomization [name]",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Synchronize kustomization", Short: "Reconcile a Kustomization resource",
Long: ` 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 Example: ` # Trigger a Kustomization apply outside of the reconciliation interval
sync kustomization podinfo tk reconcile kustomization podinfo
# Trigger a git sync of the kustomization source and apply changes # 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 ( var (
@@ -47,12 +47,12 @@ var (
) )
func init() { 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 { if len(args) < 1 {
return fmt.Errorf("kustomization name is required") return fmt.Errorf("kustomization name is required")
} }
@@ -83,27 +83,27 @@ func syncKsCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
} else { } else {
logAction("annotating kustomization %s in %s namespace", name, namespace) logger.Actionf("annotating kustomization %s in %s namespace", name, namespace)
if kustomization.Annotations == nil { if kustomization.Annotations == nil {
kustomization.Annotations = map[string]string{ kustomization.Annotations = map[string]string{
kustomizev1.SyncAtAnnotation: time.Now().String(), kustomizev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
} }
} else { } 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 { if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err return err
} }
logSuccess("kustomization annotated") logger.Successf("kustomization annotated")
} }
logWaiting("waiting for kustomization sync") logger.Waitingf("waiting for kustomization reconciliation")
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(pollInterval, timeout,
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil { isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
return err return err
} }
logSuccess("kustomization sync completed") logger.Successf("kustomization reconciliation completed")
err = kubeClient.Get(ctx, namespacedName, &kustomization) err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil { if err != nil {
@@ -111,7 +111,7 @@ func syncKsCmdRun(cmd *cobra.Command, args []string) error {
} }
if kustomization.Status.LastAppliedRevision != "" { if kustomization.Status.LastAppliedRevision != "" {
logSuccess("applied revision %s", kustomization.Status.LastAppliedRevision) logger.Successf("reconciled revision %s", kustomization.Status.LastAppliedRevision)
} else { } else {
return fmt.Errorf("kustomization sync failed") return fmt.Errorf("kustomization sync failed")
} }

View File

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

View File

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

@@ -22,7 +22,8 @@ import (
var resumeCmd = &cobra.Command{ var resumeCmd = &cobra.Command{
Use: "resume", Use: "resume",
Short: "Resume commands", Short: "Resume suspended resources",
Long: "The resume sub-commands resume a suspended resource.",
} }
func init() { func init() {

View File

@@ -0,0 +1,126 @@
/*
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.`,
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

@@ -32,9 +32,10 @@ import (
var resumeKsCmd = &cobra.Command{ var resumeKsCmd = &cobra.Command{
Use: "kustomization [name]", Use: "kustomization [name]",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Resume kustomization", 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.", Long: `The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to
RunE: resumeKsCmdRun, finish the apply.`,
RunE: resumeKsCmdRun,
} }
func init() { func init() {
@@ -65,20 +66,20 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
logAction("resuming kustomization %s in %s namespace", name, namespace) logger.Actionf("resuming kustomization %s in %s namespace", name, namespace)
kustomization.Spec.Suspend = false kustomization.Spec.Suspend = false
if err := kubeClient.Update(ctx, &kustomization); err != nil { if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err return err
} }
logSuccess("kustomization resumed") logger.Successf("kustomization resumed")
logWaiting("waiting for kustomization sync") logger.Waitingf("waiting for kustomization sync")
if err := wait.PollImmediate(pollInterval, timeout, if err := wait.PollImmediate(pollInterval, timeout,
isKustomizationResumed(ctx, kubeClient, name, namespace)); err != nil { isKustomizationResumed(ctx, kubeClient, name, namespace)); err != nil {
return err return err
} }
logSuccess("kustomization sync completed") logger.Successf("kustomization sync completed")
err = kubeClient.Get(ctx, namespacedName, &kustomization) err = kubeClient.Get(ctx, namespacedName, &kustomization)
if err != nil { if err != nil {
@@ -86,7 +87,7 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
} }
if kustomization.Status.LastAppliedRevision != "" { if kustomization.Status.LastAppliedRevision != "" {
logSuccess("applied revision %s", kustomization.Status.LastAppliedRevision) logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
} else { } else {
return fmt.Errorf("kustomization sync failed") return fmt.Errorf("kustomization sync failed")
} }

View File

@@ -22,7 +22,8 @@ import (
var suspendCmd = &cobra.Command{ var suspendCmd = &cobra.Command{
Use: "suspend", Use: "suspend",
Short: "Suspend commands", Short: "Suspend resources",
Long: "The suspend sub-commands suspend the reconciliation of a resource.",
} }
func init() { func init() {

View File

@@ -0,0 +1,73 @@
/*
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.",
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

@@ -27,7 +27,7 @@ import (
var suspendKsCmd = &cobra.Command{ var suspendKsCmd = &cobra.Command{
Use: "kustomization [name]", Use: "kustomization [name]",
Aliases: []string{"ks"}, Aliases: []string{"ks"},
Short: "Suspend kustomization", Short: "Suspend reconciliation of Kustomization",
Long: "The suspend command disables the reconciliation of a Kustomization resource.", Long: "The suspend command disables the reconciliation of a Kustomization resource.",
RunE: suspendKsCmdRun, RunE: suspendKsCmdRun,
} }
@@ -60,12 +60,12 @@ func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
return err return err
} }
logAction("suspending kustomization %s in %s namespace", name, namespace) logger.Actionf("suspending kustomization %s in %s namespace", name, namespace)
kustomization.Spec.Suspend = true kustomization.Spec.Suspend = true
if err := kubeClient.Update(ctx, &kustomization); err != nil { if err := kubeClient.Update(ctx, &kustomization); err != nil {
return err return err
} }
logSuccess("kustomization suspended") logger.Successf("kustomization suspended")
return nil return nil
} }

View File

@@ -28,9 +28,7 @@ import (
var uninstallCmd = &cobra.Command{ var uninstallCmd = &cobra.Command{
Use: "uninstall", Use: "uninstall",
Short: "Uninstall the toolkit components", Short: "Uninstall the toolkit components",
Long: ` Long: "The uninstall command removes the namespace, cluster roles, cluster role bindings and CRDs from the cluster.",
The uninstall command removes the namespace, cluster roles,
cluster role bindings and CRDs.`,
Example: ` # Dry-run uninstall of all components Example: ` # Dry-run uninstall of all components
uninstall --dry-run --namespace=gitops-system uninstall --dry-run --namespace=gitops-system
@@ -49,7 +47,7 @@ var (
func init() { func init() {
uninstallCmd.Flags().BoolVarP(&uninstallKustomizations, "kustomizations", "", false, uninstallCmd.Flags().BoolVarP(&uninstallKustomizations, "kustomizations", "", false,
"removes all kustomizations previously installed") "removes all Kustomizations previously installed")
uninstallCmd.Flags().BoolVarP(&uninstallCRDs, "crds", "", false, uninstallCmd.Flags().BoolVarP(&uninstallCRDs, "crds", "", false,
"removes all CRDs previously installed") "removes all CRDs previously installed")
uninstallCmd.Flags().BoolVarP(&uninstallDryRun, "dry-run", "", false, uninstallCmd.Flags().BoolVarP(&uninstallDryRun, "dry-run", "", false,
@@ -78,7 +76,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
} }
if uninstallKustomizations { if uninstallKustomizations {
logAction("uninstalling kustomizations") logger.Actionf("uninstalling kustomizations")
command := fmt.Sprintf("kubectl -n %s delete kustomizations --all --timeout=%s %s", command := fmt.Sprintf("kubectl -n %s delete kustomizations --all --timeout=%s %s",
namespace, timeout.String(), dryRun) namespace, timeout.String(), dryRun)
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil { if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
@@ -87,7 +85,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
// TODO: use the kustomizations snapshots to create a list of objects // 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 // that are subject to deletion and wait for all of them to be terminated
logWaiting("waiting on GC") logger.Waitingf("waiting on GC")
time.Sleep(30 * time.Second) time.Sleep(30 * time.Second)
} }
@@ -96,13 +94,13 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
kinds += ",crds" kinds += ",crds"
} }
logAction("uninstalling components") logger.Actionf("uninstalling components")
command := fmt.Sprintf("kubectl delete %s -l app.kubernetes.io/instance=%s --timeout=%s %s", command := fmt.Sprintf("kubectl delete %s -l app.kubernetes.io/instance=%s --timeout=%s %s",
kinds, namespace, timeout.String(), dryRun) kinds, namespace, timeout.String(), dryRun)
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil { if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
return fmt.Errorf("uninstall failed") return fmt.Errorf("uninstall failed")
} }
logSuccess("uninstall finished") logger.Successf("uninstall finished")
return nil return nil
} }

View File

@@ -143,3 +143,23 @@ func (*Utils) writeFile(content, filename string) error {
return file.Sync() 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()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -21,16 +21,16 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
--branch=master \ --branch=master \
--interval=3m --interval=3m
# List git sources and their status # List GitRepository sources and their status
tk get sources git tk get sources git
# Trigger a git sync # Trigger a GitRepository source sync
tk sync source git webapp-latest tk sync source git webapp-latest
# Export git sources in YAML format # Export GitRepository sources in YAML format
tk export source git --all > sources.yaml tk export source git --all > sources.yaml
# Create a kustomization for deploying a series of microservices # Create a Kustomization for deploying a series of microservices
tk create kustomization webapp-dev \ tk create kustomization webapp-dev \
--source=webapp-latest \ --source=webapp-latest \
--path="./deploy/webapp/" \ --path="./deploy/webapp/" \
@@ -41,22 +41,22 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
--health-check="Deployment/frontend.webapp" \ --health-check="Deployment/frontend.webapp" \
--health-check-timeout=2m --health-check-timeout=2m
# Trigger a git sync and apply changes if any # 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 # Suspend a Kustomization reconciliation
tk suspend kustomization webapp-dev tk suspend kustomization webapp-dev
# Export kustomizations in YAML format # Export Kustomizations in YAML format
tk export kustomization --all > kustomizations.yaml tk export kustomization --all > kustomizations.yaml
# Resume a kustomization reconciliation # Resume a Kustomization reconciliation
tk resume kustomization webapp-dev tk resume kustomization webapp-dev
# Delete a kustomization # Delete a Kustomization
tk delete kustomization webapp-dev tk delete kustomization webapp-dev
# Delete a git source # Delete a GitRepository source
tk delete source git webapp-latest tk delete source git webapp-latest
# Uninstall the toolkit and delete CRDs # Uninstall the toolkit and delete CRDs
@@ -67,26 +67,25 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
### Options ### Options
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) -h, --help help for tk
-h, --help help for tk --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk bootstrap](tk_bootstrap.md) - Bootstrap commands * [tk bootstrap](tk_bootstrap.md) - Bootstrap toolkit components
* [tk check](tk_check.md) - Check requirements and installation * [tk check](tk_check.md) - Check requirements and installation
* [tk completion](tk_completion.md) - Generates bash completion scripts * [tk completion](tk_completion.md) - Generates bash completion scripts
* [tk create](tk_create.md) - Create commands * [tk create](tk_create.md) - Create or update sources and resources
* [tk delete](tk_delete.md) - Delete commands * [tk delete](tk_delete.md) - Delete sources and resources
* [tk export](tk_export.md) - Export commands * [tk export](tk_export.md) - Export resources in YAML format
* [tk get](tk_get.md) - Get commands * [tk get](tk_get.md) - Get sources and resources
* [tk install](tk_install.md) - Install the toolkit components * [tk install](tk_install.md) - Install the toolkit components
* [tk resume](tk_resume.md) - Resume commands * [tk reconcile](tk_reconcile.md) - Reconcile sources and resources
* [tk suspend](tk_suspend.md) - Suspend commands * [tk resume](tk_resume.md) - Resume suspended resources
* [tk sync](tk_sync.md) - Synchronize commands * [tk suspend](tk_suspend.md) - Suspend resources
* [tk uninstall](tk_uninstall.md) - Uninstall the toolkit components * [tk uninstall](tk_uninstall.md) - Uninstall the toolkit components

View File

@@ -1,31 +1,31 @@
## tk bootstrap ## tk bootstrap
Bootstrap commands Bootstrap toolkit components
### Synopsis ### Synopsis
Bootstrap commands The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.
### Options ### Options
``` ```
-h, --help help for bootstrap --components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--version string toolkit tag or branch (default "master") -h, --help help for bootstrap
-v, --version string toolkit version (default "latest")
``` ```
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines * [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
* [tk bootstrap github](tk_bootstrap_github.md) - Bootstrap GitHub repository * [tk bootstrap github](tk_bootstrap_github.md) - Bootstrap toolkit components in a GitHub repository
* [tk bootstrap gitlab](tk_bootstrap_gitlab.md) - Bootstrap GitLab repository * [tk bootstrap gitlab](tk_bootstrap_gitlab.md) - Bootstrap toolkit components in a GitLab repository

View File

@@ -1,13 +1,12 @@
## tk bootstrap github ## tk bootstrap github
Bootstrap GitHub repository Bootstrap toolkit components in a GitHub repository
### Synopsis ### Synopsis
The bootstrap github command creates the GitHub repository if it doesn't exists and
The bootstrap command creates the GitHub repository if it doesn't exists and
commits the toolkit components manifests to the master branch. commits the toolkit components manifests to the master branch.
Then it configure the target cluster to synchronize with the repository. Then it configures the target cluster to synchronize with the repository.
If the toolkit components are present on the cluster, If the toolkit components are present on the cluster,
the bootstrap command will perform an upgrade if needed. the bootstrap command will perform an upgrade if needed.
@@ -55,15 +54,15 @@ tk bootstrap github [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system") --namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s) --timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects --verbose print generated objects
--version string toolkit tag or branch (default "master") -v, --version string toolkit version (default "latest")
``` ```
### SEE ALSO ### SEE ALSO
* [tk bootstrap](tk_bootstrap.md) - Bootstrap commands * [tk bootstrap](tk_bootstrap.md) - Bootstrap toolkit components

View File

@@ -1,13 +1,12 @@
## tk bootstrap gitlab ## tk bootstrap gitlab
Bootstrap GitLab repository Bootstrap toolkit components in a GitLab repository
### Synopsis ### Synopsis
The bootstrap gitlab command creates the GitLab repository if it doesn't exists and
The bootstrap command creates the GitLab repository if it doesn't exists and
commits the toolkit components manifests to the master branch. commits the toolkit components manifests to the master branch.
Then it configure the target cluster to synchronize with the repository. Then it configures the target cluster to synchronize with the repository.
If the toolkit components are present on the cluster, If the toolkit components are present on the cluster,
the bootstrap command will perform an upgrade if needed. the bootstrap command will perform an upgrade if needed.
@@ -51,15 +50,15 @@ tk bootstrap gitlab [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--namespace string the namespace scope for this operation (default "gitops-system") --namespace string the namespace scope for this operation (default "gitops-system")
--timeout duration timeout for this operation (default 5m0s) --timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects --verbose print generated objects
--version string toolkit tag or branch (default "master") -v, --version string toolkit version (default "latest")
``` ```
### SEE ALSO ### SEE ALSO
* [tk bootstrap](tk_bootstrap.md) - Bootstrap commands * [tk bootstrap](tk_bootstrap.md) - Bootstrap toolkit components

View File

@@ -4,7 +4,6 @@ Check requirements and installation
### Synopsis ### Synopsis
The check command will perform a series of checks to validate that 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. the local environment is configured correctly and if the installed components are healthy.
@@ -16,28 +15,28 @@ tk check [flags]
``` ```
# Run pre-installation checks # Run pre-installation checks
check --pre tk check --pre
# Run installation checks # Run installation checks
check tk check
``` ```
### Options ### Options
``` ```
-h, --help help for check --components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
--pre only run pre-installation checks -h, --help help for check
--pre only run pre-installation checks
``` ```
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### 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 ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO

View File

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

View File

@@ -1,12 +1,10 @@
## tk create kustomization ## tk create kustomization
Create or update a kustomization resource Create or update a Kustomization resource
### Synopsis ### Synopsis
The kustomization source create command generates a Kustomize resource for a given GitRepository source.
The kustomization source command generates a kustomization.kustomize.fluxcd.io resource for a given GitRepository source.
API spec: https://github.com/fluxcd/kustomize-controller/tree/master/docs/spec/v1alpha1
``` ```
tk create kustomization [name] [flags] tk create kustomization [name] [flags]
@@ -15,7 +13,7 @@ tk create kustomization [name] [flags]
### Examples ### Examples
``` ```
# Create a kustomization from a source at a given path # Create a Kustomization resource from a source at a given path
create kustomization contour \ create kustomization contour \
--source=contour \ --source=contour \
--path="./examples/contour/" \ --path="./examples/contour/" \
@@ -26,7 +24,7 @@ tk create kustomization [name] [flags]
--health-check="DaemonSet/envoy.projectcontour" \ --health-check="DaemonSet/envoy.projectcontour" \
--health-check-timeout=3m --health-check-timeout=3m
# Create a kustomization that depends on the previous one # Create a Kustomization resource that depends on the previous one
create kustomization webapp \ create kustomization webapp \
--depends-on=contour \ --depends-on=contour \
--source=webapp \ --source=webapp \
@@ -35,7 +33,7 @@ tk create kustomization [name] [flags]
--interval=5m \ --interval=5m \
--validate=client --validate=client
# Create a kustomization that runs under a service account # Create a Kustomization resource that runs under a service account
create kustomization webapp \ create kustomization webapp \
--source=webapp \ --source=webapp \
--path="./deploy/overlays/staging" \ --path="./deploy/overlays/staging" \
@@ -50,11 +48,11 @@ tk create kustomization [name] [flags]
### Options ### Options
``` ```
--depends-on stringArray kustomization that must be ready before this kustomization can be applied --depends-on stringArray Kustomization that must be ready before this Kustomization can be applied
--health-check stringArray workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>' --health-check stringArray workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'
--health-check-timeout duration timeout of health checking operations (default 2m0s) --health-check-timeout duration timeout of health checking operations (default 2m0s)
-h, --help help for kustomization -h, --help help for kustomization
--path string path to the directory containing the kustomization file (default "./") --path string path to the directory containing the Kustomization file (default "./")
--prune enable garbage collection --prune enable garbage collection
--sa-name string service account name --sa-name string service account name
--sa-namespace string service account namespace --sa-namespace string service account namespace
@@ -65,16 +63,15 @@ tk create kustomization [name] [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --export export in YAML format to stdout
--export export in yaml format to stdout --interval duration source sync interval (default 1m0s)
--interval duration source sync interval (default 1m0s) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk create](tk_create.md) - Create commands * [tk create](tk_create.md) - Create or update sources and resources

View File

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

View File

@@ -1,11 +1,11 @@
## tk create source git ## tk create source git
Create or update a git source Create or update a GitRepository source
### Synopsis ### Synopsis
The create source command generates a GitRepository resource and waits for it to sync. The create source git command generates a GitRepository resource and waits for it to sync.
For Git over SSH, host and SSH keys are automatically generated and stored in a Kubernetes secret. 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. For private Git repositories, the basic authentication credentials are stored in a Kubernetes secret.
@@ -70,16 +70,15 @@ tk create source git [name] [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --export export in YAML format to stdout
--export export in yaml format to stdout --interval duration source sync interval (default 1m0s)
--interval duration source sync interval (default 1m0s) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk create source](tk_create_source.md) - Create source commands * [tk create source](tk_create_source.md) - Create or update sources

View File

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

View File

@@ -1,10 +1,10 @@
## tk delete kustomization ## tk delete kustomization
Delete kustomization Delete a Kustomization resource
### Synopsis ### Synopsis
Delete kustomization The delete kustomization command deletes the given Kustomization from the cluster.
``` ```
tk delete kustomization [name] [flags] tk delete kustomization [name] [flags]
@@ -19,15 +19,14 @@ tk delete kustomization [name] [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") -s, --silent delete resource without asking for confirmation
-s, --silent delete resource without asking for confirmation --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk delete](tk_delete.md) - Delete commands * [tk delete](tk_delete.md) - Delete sources and resources

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,10 @@
## tk export kustomization ## tk export kustomization
Export kustomization in YAML format Export Kustomization resources in YAML format
### Synopsis ### Synopsis
Export kustomization in YAML format The export kustomization command exports one or all Kustomization resources in YAML format.
``` ```
tk export kustomization [name] [flags] tk export kustomization [name] [flags]
@@ -13,10 +13,10 @@ tk export kustomization [name] [flags]
### Examples ### Examples
``` ```
# Export all kustomizations # Export all Kustomization resources
export kustomization --all > kustomizations.yaml export kustomization --all > kustomizations.yaml
# Export a kustomization # Export a Kustomization
export kustomization my-app > kustomization.yaml export kustomization my-app > kustomization.yaml
``` ```
@@ -30,15 +30,14 @@ tk export kustomization [name] [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--all select all resources --all select all resources
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk export](tk_export.md) - Export commands * [tk export](tk_export.md) - Export resources in YAML format

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,6 @@ Install the toolkit components
### Synopsis ### Synopsis
The install command deploys the toolkit components in the specified namespace. 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. If a previous version is installed, then an in-place upgrade will be performed.
@@ -16,33 +15,37 @@ tk install [flags]
``` ```
# Install the latest version in the gitops-systems namespace # 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 # 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 # 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 ### Options
``` ```
--dry-run only print the object that would be applied --components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
-h, --help help for install --dry-run only print the object that would be applied
--manifests string path to the manifest directory, dev only --export write the install manifests to stdout and exit
-v, --version string toolkit tag or branch (default "master") -h, --help help for install
--manifests string path to the manifest directory, dev only
-v, --version string toolkit version (default "latest")
``` ```
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### 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 helm repo update 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

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

@@ -1,10 +1,11 @@
## tk resume kustomization ## tk resume kustomization
Resume kustomization Resume a suspended Kustomization
### Synopsis ### Synopsis
The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to finish the apply. The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to
finish the apply.
``` ```
tk resume kustomization [name] [flags] tk resume kustomization [name] [flags]
@@ -19,14 +20,13 @@ tk resume kustomization [name] [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk resume](tk_resume.md) - Resume commands * [tk resume](tk_resume.md) - Resume suspended resources

View File

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

@@ -1,6 +1,6 @@
## tk suspend kustomization ## tk suspend kustomization
Suspend kustomization Suspend reconciliation of Kustomization
### Synopsis ### Synopsis
@@ -19,14 +19,13 @@ tk suspend kustomization [name] [flags]
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### SEE ALSO
* [tk suspend](tk_suspend.md) - Suspend commands * [tk suspend](tk_suspend.md) - Suspend resources

View File

@@ -1,30 +0,0 @@
## tk sync
Synchronize commands
### Synopsis
Synchronize commands
### 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])
--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 kustomization
* [tk sync source](tk_sync_source.md) - Synchronize source commands

View File

@@ -1,45 +0,0 @@
## tk sync kustomization
Synchronize kustomization
### 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 git sync of the kustomization 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])
--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 commands

View File

@@ -1,29 +0,0 @@
## tk sync source
Synchronize source commands
### Synopsis
Synchronize source commands
### 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])
--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 commands
* [tk sync source git](tk_sync_source_git.md) - Synchronize git source

View File

@@ -1,41 +0,0 @@
## tk sync source git
Synchronize git 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])
--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 source commands

View File

@@ -4,9 +4,7 @@ Uninstall the toolkit components
### Synopsis ### Synopsis
The uninstall command removes the namespace, cluster roles, cluster role bindings and CRDs from the cluster.
The uninstall command removes the namespace, cluster roles,
cluster role bindings and CRDs.
``` ```
tk uninstall [flags] tk uninstall [flags]
@@ -29,18 +27,17 @@ tk uninstall [flags]
--crds removes all CRDs previously installed --crds removes all CRDs previously installed
--dry-run only print the object that would be deleted --dry-run only print the object that would be deleted
-h, --help help for uninstall -h, --help help for uninstall
--kustomizations removes all kustomizations previously installed --kustomizations removes all Kustomizations previously installed
-s, --silent delete components without asking for confirmation -s, --silent delete components without asking for confirmation
``` ```
### Options inherited from parent commands ### Options inherited from parent commands
``` ```
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller]) --kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--kubeconfig string path to the kubeconfig file (default "~/.kube/config") --namespace string the namespace scope for this operation (default "gitops-system")
--namespace string the namespace scope for this operation (default "gitops-system") --timeout duration timeout for this operation (default 5m0s)
--timeout duration timeout for this operation (default 5m0s) --verbose print generated objects
--verbose print generated objects
``` ```
### SEE ALSO ### 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

@@ -15,7 +15,7 @@ Features:
- Health assessment of the deployed workloads - Health assessment of the deployed workloads
- Runs pipelines in a specific order (depends-on relationship) - Runs pipelines in a specific order (depends-on relationship)
- Prunes objects removed from source (garbage collection) - Prunes objects removed from source (garbage collection)
- Reports cluster state changes (Slack/Discord) - Reports cluster state changes (alerting provided by notification-controller)
Links: Links:

View File

@@ -0,0 +1,17 @@
# Notification Controller
The Notification Controller is a Kubernetes operator, specialized in handling inbound and outbound events.
![](../../_files/notification-controller.png)
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:
- Source code [fluxcd/notification-controller](https://github.com/fluxcd/notification-controller)
- Specification [docs](https://github.com/fluxcd/notification-controller/tree/master/docs/spec)

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -21,7 +21,7 @@ export GITHUB_USER=<your-username>
To install the latest `tk` release run: To install the latest `tk` release run:
```bash ```sh
curl -s https://toolkit.fluxcd.io/install.sh | sudo bash curl -s https://toolkit.fluxcd.io/install.sh | sudo bash
``` ```
@@ -58,7 +58,7 @@ kubectl cluster-info --context kind-staging
Verify that your staging cluster satisfies the prerequisites with: Verify that your staging cluster satisfies the prerequisites with:
```text ```console
$ tk check --pre $ tk check --pre
► checking prerequisites ► checking prerequisites
@@ -104,22 +104,9 @@ $ tk bootstrap github --owner=gitopsrun --repository=fleet-infra --path=staging-
✚ generating manifests ✚ generating manifests
✔ components manifests pushed ✔ components manifests pushed
► installing components in gitops-system namespace ► installing components in gitops-system namespace
namespace/gitops-system created
customresourcedefinition.apiextensions.k8s.io/gitrepositories.source.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/helmcharts.source.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/helmrepositories.source.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/kustomizations.kustomize.fluxcd.io created
customresourcedefinition.apiextensions.k8s.io/profiles.kustomize.fluxcd.io created
role.rbac.authorization.k8s.io/crd-controller-gitops-system created
rolebinding.rbac.authorization.k8s.io/crd-controller-gitops-system created
clusterrolebinding.rbac.authorization.k8s.io/cluster-reconciler-gitops-system created
service/source-controller created
deployment.apps/kustomize-controller created
deployment.apps/source-controller created
networkpolicy.networking.k8s.io/deny-ingress created
Waiting for deployment "source-controller" rollout to finish: 0 of 1 updated replicas are available...
deployment "source-controller" successfully rolled out deployment "source-controller" successfully rolled out
deployment "kustomize-controller" successfully rolled out deployment "kustomize-controller" successfully rolled out
deployment "notification-controller" successfully rolled out
✔ install completed ✔ install completed
► configuring deploy key ► configuring deploy key
✔ deploy key configured ✔ deploy key configured
@@ -208,7 +195,7 @@ git add -A && git commit -m "add staging webapp" && git push
In about 30s the synchronization should start: In about 30s the synchronization should start:
```text ```console
$ watch tk get kustomizations $ watch tk get kustomizations
✔ gitops-system last applied revision master/35d5765a1acb9e9ce66cad7274c6fe03eee1e8eb ✔ gitops-system last applied revision master/35d5765a1acb9e9ce66cad7274c6fe03eee1e8eb
@@ -219,7 +206,7 @@ $ watch tk get kustomizations
When the synchronization finishes you can check that the webapp services are running: When the synchronization finishes you can check that the webapp services are running:
```text ```console
$ kubectl -n webapp get deployments,services $ kubectl -n webapp get deployments,services
NAME READY UP-TO-DATE AVAILABLE AGE NAME READY UP-TO-DATE AVAILABLE AGE
@@ -307,7 +294,7 @@ git add -A && git commit -m "add prod webapp" && git push
List git sources: List git sources:
```text ```console
$ tk get sources git $ tk get sources git
✔ gitops-system last fetched revision master/99072ee132abdead8b7799d7891eae2f524eb73d ✔ gitops-system last fetched revision master/99072ee132abdead8b7799d7891eae2f524eb73d
@@ -318,7 +305,7 @@ The kubectl equivalent is `kubectl -n gitops-system get gitrepositories`.
List kustomization: List kustomization:
```text ```console
$ tk get kustomizations $ tk get kustomizations
✔ gitops-system last applied revision master/99072ee132abdead8b7799d7891eae2f524eb73d ✔ gitops-system last applied revision master/99072ee132abdead8b7799d7891eae2f524eb73d
@@ -341,24 +328,24 @@ git add -A && git commit -m "update prod webapp" && git push
Trigger a git sync: Trigger a git sync:
```text ```console
$ tk sync ks gitops-system --with-source $ tk reconcile ks gitops-system --with-source
► annotating source gitops-system ► annotating source gitops-system
✔ source annotated ✔ source annotated
◎ waiting for git sync ◎ waiting for reconcilitation
✔ git sync completed ✔ git reconciliation completed
✔ fetched revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9 ✔ fetched revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9
◎ waiting for kustomization sync ◎ waiting for kustomization reconcilitation
✔ kustomization sync completed ✔ kustomization reconcilitation completed
✔ applied revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9 ✔ 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: Wait for the webapp to be upgraded:
```text ```console
$ watch tk get kustomizations $ watch tk get kustomizations
✔ gitops-system last applied revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9 ✔ gitops-system last applied revision master/d751ea264d48bf0db8b588d1d08184834ac8fec9

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

@@ -0,0 +1,101 @@
# Setup Notifications
When operating a cluster, different teams may wish to receive notifications about
the status of their GitOps pipelines.
For example, the on-call team would receive alerts about reconciliation
failures in the cluster, while the dev team may wish to be alerted when a new version
of an app was deployed and if the deployment is healthy.
## Prerequisites
* [Get started guide](../get-started/index.md)
The GitOps toolkit controllers emit Kubernetes events whenever a resource status changes.
You can use the [notification-controller](../components/notification/controller.md)
to forward these events to Slack, Microsoft Teams, Discord or Rocket chart.
The notification controller is part of the default toolkit installation.
## Define a provider
First create a secret with your Slack incoming webhook:
```sh
kubectl -n gitops-system create secret generic slack-url \
--from-literal=address=https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
```
Note that the secret must contain an `address` field,
it can be a Slack, Microsoft Teams, Discord or Rocket webhook URL.
Create a notification provider for Slack by referencing the above secret:
```yaml
apiVersion: notification.fluxcd.io/v1alpha1
kind: Provider
metadata:
name: slack
namespace: gitops-system
spec:
type: slack
channel: general
secretRef:
name: slack-url
```
The provider type can be `slack`, `msteams`, `discord`, `rocket` or `generic`.
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 all repositories and kustomizations:
```yaml
apiVersion: notification.fluxcd.io/v1alpha1
kind: Alert
metadata:
name: on-call-webapp
namespace: gitops-system
spec:
providerRef:
name: slack
eventSeverity: info
eventSources:
- kind: GitRepository
name: '*'
- kind: Kustomization
name: '*'
```
Apply the above files or commit them to the `fleet-infra` repository.
To verify that the alert has been acknowledge by the notification controller do:
```console
$ kubectl -n gitops-system get alerts
NAME READY STATUS AGE
on-call-webapp True Initialized 1m
```
Multiple alerts can be used to send notifications to different channels or Slack organizations.
The event severity can be set to `info` or `error`.
When the severity is set to `error`, the kustomize controller will alert on any error
encountered during the reconciliation process.
This includes kustomize build and validation errors,
apply errors and health check failures.
![error alert](../diagrams/slack-error-alert.png)
When the verbosity is set to `info`, the controller will alert if:
* a Kubernetes object was created, updated or deleted
* heath checks are passing
* a dependency is delaying the execution
* an error occurs
![info alert](../diagrams/slack-info-alert.png)

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

View File

@@ -29,7 +29,7 @@ Target features:
- External events handling (webhook receivers) - External events handling (webhook receivers)
- Source write-back (automated patching) - Source write-back (automated patching)
- Policy driven validation (OPA, admission controllers) - Policy driven validation (OPA, admission controllers)
- Seamless integration with Git providers (GitHub, GitLab, BitBucket) - Seamless integration with Git providers (GitHub, GitLab, Bitbucket)
- Interoperability with workflow providers (GitHub Actions, Tekton, Argo) - Interoperability with workflow providers (GitHub Actions, Tekton, Argo)
- Interoperability with CAPI providers - Interoperability with CAPI providers
@@ -39,8 +39,15 @@ Components:
- [Source Controller](components/source/controller.md) - [Source Controller](components/source/controller.md)
- [GitRepository CRD](components/source/gitrepositories.md) - [GitRepository CRD](components/source/gitrepositories.md)
- [HelmRepository CRD](components/source/helmrepositories.md) - [HelmRepository CRD](components/source/helmrepositories.md)
- [HelmChart CRD](components/source/helmcharts.md)
- [Kustomize Controller](components/kustomize/controller.md) - [Kustomize Controller](components/kustomize/controller.md)
- [Kustomization CRD](components/kustomize/kustomization.md) - [Kustomization CRD](components/kustomize/kustomization.md)
- Helm Controller (TBA) - [Helm Controller](components/helm/controller.md)
- [HelmRelease CRD](components/helm/helmreleases.md)
- [Notification Controller](components/notification/controller.md)
- [Provider CRD](components/notification/provider.md)
- [Alert CRD](components/notification/alert.md)
- [Receiver CRD](components/notification/receiver.md)
To get started with the toolkit please follow this [guide](get-started/index.md). To get started with the toolkit please follow this [guide](get-started/index.md).

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