Compare commits
146 Commits
v0.0.1-bet
...
v0.0.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca5732e586 | ||
|
|
2463d72f3b | ||
|
|
d6f7474200 | ||
|
|
0b2bc7ab3f | ||
|
|
0a4fac61d4 | ||
|
|
797aec5528 | ||
|
|
5f0b95dc59 | ||
|
|
b384c5f14c | ||
|
|
5254dca9d9 | ||
|
|
8534ccbf37 | ||
|
|
9af874d810 | ||
|
|
4e3dee15ce | ||
|
|
aaad618e20 | ||
|
|
10bb50bd82 | ||
|
|
6d2ff6e019 | ||
|
|
670070a879 | ||
|
|
dcec8007d4 | ||
|
|
3abf4a49cd | ||
|
|
38825bf96a | ||
|
|
faa69da28d | ||
|
|
5cf524e2fd | ||
|
|
88802a44e7 | ||
|
|
94498d862d | ||
|
|
9418b24e8f | ||
|
|
b92cbcd7e7 | ||
|
|
9ef2ff92df | ||
|
|
422724bd2d | ||
|
|
6cb7897f25 | ||
|
|
499ba15004 | ||
|
|
b04abe989e | ||
|
|
ea576179f9 | ||
|
|
116d53a978 | ||
|
|
32adbf2ec8 | ||
|
|
c664484fda | ||
|
|
06906eba4c | ||
|
|
d387ebf32d | ||
|
|
f75556f33c | ||
|
|
2cf09e4de6 | ||
|
|
a5a3a9c586 | ||
|
|
746dfbd955 | ||
|
|
b1993d2fb7 | ||
|
|
e8096dec88 | ||
|
|
39eee51ec8 | ||
|
|
7bb3a10795 | ||
|
|
a8cbe4b05f | ||
|
|
fe86da0cde | ||
|
|
4c86a2c191 | ||
|
|
8dc5db17ac | ||
|
|
549c3a190e | ||
|
|
7a68c4ccf3 | ||
|
|
4c684df653 | ||
|
|
bf8831b833 | ||
|
|
394227571f | ||
|
|
bf67577073 | ||
|
|
e180611024 | ||
|
|
43cfc55368 | ||
|
|
c03b7ea15d | ||
|
|
ddfedfb590 | ||
|
|
24418370f1 | ||
|
|
02521b6964 | ||
|
|
16f693148b | ||
|
|
0bf46cb63f | ||
|
|
2e38855396 | ||
|
|
97592a1387 | ||
|
|
c61bf76c80 | ||
|
|
e95b137011 | ||
|
|
ad655183e0 | ||
|
|
789fd34c4a | ||
|
|
87bbbaa475 | ||
|
|
a4ca813cf5 | ||
|
|
e8eef73212 | ||
|
|
512d4a43cb | ||
|
|
b9f7b1d175 | ||
|
|
b7727e2659 | ||
|
|
229d1d8c6e | ||
|
|
c0b18f85aa | ||
|
|
b11b9588f8 | ||
|
|
633d028841 | ||
|
|
a744b304a0 | ||
|
|
e594350307 | ||
|
|
ecf7a1eac1 | ||
|
|
4621afcb31 | ||
|
|
006c949941 | ||
|
|
72e06ab337 | ||
|
|
f4b2a32a23 | ||
|
|
329e21fd78 | ||
|
|
5499d15402 | ||
|
|
d7f8a05612 | ||
|
|
1f99a75049 | ||
|
|
21fd436621 | ||
|
|
ebcbe98684 | ||
|
|
0e437c1105 | ||
|
|
4b18f56f00 | ||
|
|
fd7ab0a7fd | ||
|
|
c3c84d0ea0 | ||
|
|
43b00c5696 | ||
|
|
a9f4536de4 | ||
|
|
892230280c | ||
|
|
0969a0c42a | ||
|
|
185143ecf6 | ||
|
|
6e06f94a91 | ||
|
|
9af0bc31c3 | ||
|
|
6bcbb13bfb | ||
|
|
9a6d48d038 | ||
|
|
0e81f6c3af | ||
|
|
353a2dd92b | ||
|
|
ee749236e1 | ||
|
|
cf45401250 | ||
|
|
15429160c7 | ||
|
|
3ea7f31797 | ||
|
|
dbfa2f9944 | ||
|
|
98cf176c81 | ||
|
|
39b00797d6 | ||
|
|
1df5a36f84 | ||
|
|
1db3bb3d33 | ||
|
|
807848b6bb | ||
|
|
917598acf8 | ||
|
|
b8bddf6a39 | ||
|
|
da95b7559d | ||
|
|
041b475f49 | ||
|
|
c0a8604f90 | ||
|
|
ce80bd521a | ||
|
|
e92615b3a8 | ||
|
|
3d7349ee53 | ||
|
|
0935a637f9 | ||
|
|
c23d40ca71 | ||
|
|
9ffe908c66 | ||
|
|
45003436bf | ||
|
|
5074ff2889 | ||
|
|
c1d7582461 | ||
|
|
186c7d5786 | ||
|
|
7a87d353cb | ||
|
|
badd2a102f | ||
|
|
d0a79c2b4c | ||
|
|
bd781bbcfb | ||
|
|
f3d50e158a | ||
|
|
34ada4113f | ||
|
|
4f43b504f4 | ||
|
|
62e4b03342 | ||
|
|
dca7b0ba91 | ||
|
|
2a61befbfd | ||
|
|
287be26190 | ||
|
|
4992e11383 | ||
|
|
727734850e | ||
|
|
e042d25062 | ||
|
|
ba7a11d0e5 |
44
.github/workflows/docs.yaml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Publish docs via GitHub Pages
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- docs*
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Deploy docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout master
|
||||
uses: actions/checkout@v1
|
||||
- name: Copy assets
|
||||
run: |
|
||||
# source-controller CRDs
|
||||
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/api/source.md > docs/components/source/api.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/gitrepositories.md > docs/components/source/gitrepositories.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/helmrepositories.md > docs/components/source/helmrepositories.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/source-controller/master/docs/spec/v1alpha1/helmcharts.md > docs/components/source/helmcharts.md
|
||||
|
||||
# kustomize-controller CRDs
|
||||
curl https://raw.githubusercontent.com/fluxcd/kustomize-controller/master/docs/api/kustomize.md > docs/components/kustomize/api.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/kustomize-controller/master/docs/spec/v1alpha1/kustomization.md > docs/components/kustomize/kustomization.md
|
||||
|
||||
# helm-controller CRDs
|
||||
curl https://raw.githubusercontent.com/fluxcd/helm-controller/master/docs/api/helmrelease.md > docs/components/helm/api.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/helm-controller/master/docs/spec/v2alpha1/helmreleases.md > docs/components/helm/helmreleases.md
|
||||
|
||||
# notification-controller CRDs
|
||||
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/api/notification.md > docs/components/notification/api.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/event.md > docs/components/notification/event.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/alert.md > docs/components/notification/alert.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/provider.md > docs/components/notification/provider.md
|
||||
curl https://raw.githubusercontent.com/fluxcd/notification-controller/master/docs/spec/v1alpha1/receiver.md > docs/components/notification/receiver.md
|
||||
|
||||
# install script
|
||||
cp install/tk.sh docs/install.sh
|
||||
- name: Deploy docs
|
||||
uses: mhausenblas/mkdocs-deploy-gh-pages@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CUSTOM_DOMAIN: toolkit.fluxcd.io
|
||||
34
.github/workflows/e2e.yaml
vendored
@@ -24,12 +24,15 @@ jobs:
|
||||
with:
|
||||
go-version: 1.14.x
|
||||
- name: Setup Kubernetes
|
||||
uses: engineerd/setup-kind@v0.3.0
|
||||
uses: engineerd/setup-kind@v0.4.0
|
||||
with:
|
||||
image: kindest/node:v1.16.9
|
||||
- name: Run test
|
||||
run: make test
|
||||
- name: Check if working tree is dirty
|
||||
run: |
|
||||
if [[ $(git diff --stat) != '' ]]; then
|
||||
git diff
|
||||
echo 'run make test and commit changes'
|
||||
exit 1
|
||||
fi
|
||||
@@ -40,7 +43,7 @@ jobs:
|
||||
./bin/tk check --pre
|
||||
- name: tk install --version
|
||||
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
|
||||
run: |
|
||||
./bin/tk uninstall --namespace=test --crds --silent
|
||||
@@ -62,13 +65,13 @@ jobs:
|
||||
--path="./deploy/overlays/dev" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--health-check="Deployment/frontend.dev" \
|
||||
--health-check="Deployment/backend.dev" \
|
||||
--health-check-timeout=3m
|
||||
- name: tk sync kustomization --with-source
|
||||
run: |
|
||||
./bin/tk sync kustomization podinfo --with-source
|
||||
./bin/tk reconcile kustomization podinfo --with-source
|
||||
- name: tk get kustomizations
|
||||
run: |
|
||||
./bin/tk get kustomizations
|
||||
@@ -88,6 +91,29 @@ jobs:
|
||||
- name: tk delete source git
|
||||
run: |
|
||||
./bin/tk delete source git podinfo --silent
|
||||
- name: tk create source helm
|
||||
run: |
|
||||
./bin/tk create source helm podinfo \
|
||||
--url https://stefanprodan.github.io/podinfo
|
||||
- name: tk create helmrelease
|
||||
run: |
|
||||
./bin/tk create hr podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=">4.0.0 <5.0.0"
|
||||
- name: tk get helmreleases
|
||||
run: |
|
||||
./bin/tk get helmreleases
|
||||
- name: tk export helmrelease
|
||||
run: |
|
||||
./bin/tk export hr --all
|
||||
- name: tk delete helmrelease
|
||||
run: |
|
||||
./bin/tk delete hr podinfo --silent
|
||||
- name: tk delete source helm
|
||||
run: |
|
||||
./bin/tk delete source helm podinfo --silent
|
||||
- name: tk check
|
||||
run: |
|
||||
./bin/tk check
|
||||
|
||||
54
.github/workflows/release.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2-beta
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.14.x
|
||||
- name: Download release notes utility
|
||||
@@ -25,10 +25,60 @@ jobs:
|
||||
run: |
|
||||
echo 'CHANGELOG' > /tmp/release.txt
|
||||
github-release-notes -org fluxcd -repo toolkit -since-latest-release >> /tmp/release.txt
|
||||
- name: Setup Kustomize
|
||||
uses: ./.github/actions/kustomize
|
||||
- name: Generate manifests tarball
|
||||
run: |
|
||||
mkdir -p ./output
|
||||
files=""
|
||||
|
||||
# build controllers
|
||||
for controller in ./manifests/bases/*/; do
|
||||
output_path="./output/$(basename $controller).yaml"
|
||||
echo "building $controller to $output_path"
|
||||
|
||||
kustomize build $controller > $output_path
|
||||
files+=" $(basename $output_path)"
|
||||
done
|
||||
|
||||
# build rbac
|
||||
rbac_path="./manifests/rbac"
|
||||
rbac_output_path="./output/rbac.yaml"
|
||||
echo "building $rbac_path to $rbac_output_path"
|
||||
kustomize build $rbac_path > $rbac_output_path
|
||||
files+=" $(basename $rbac_output_path)"
|
||||
|
||||
# build policies
|
||||
policies_path="./manifests/policies"
|
||||
policies_output_path="./output/policies.yaml"
|
||||
echo "building $policies_path to $policies_output_path"
|
||||
kustomize build $policies_path > $policies_output_path
|
||||
files+=" $(basename $policies_output_path)"
|
||||
|
||||
# create tarball
|
||||
cd ./output && tar -cvzf manifests.tar.gz $files
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: actions/create-release@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
- name: Upload artifacts
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./output/manifests.tar.gz
|
||||
asset_name: manifests.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v1
|
||||
with:
|
||||
version: latest
|
||||
args: release --release-notes=/tmp/release.txt
|
||||
args: release --release-notes=/tmp/release.txt --skip-validate
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
3
.gitignore
vendored
@@ -13,4 +13,5 @@
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
bin/
|
||||
bin/
|
||||
output/
|
||||
@@ -1,8 +1,8 @@
|
||||
# Contributing
|
||||
|
||||
FluxCD toolkit is [Apache 2.0 licensed](LICENSE) and accepts contributions
|
||||
via GitHub pull requests. This document outlines some of the conventions on
|
||||
to make it easier to get your contribution accepted.
|
||||
The GitOps Toolkit is [Apache 2.0 licensed](https://github.com/fluxcd/toolkit/blob/master/LICENSE)
|
||||
and accepts contributions via GitHub pull requests. This document outlines
|
||||
some of the conventions on to make it easier to get your contribution accepted.
|
||||
|
||||
We gratefully welcome improvements to issues and documentation as well as to
|
||||
code.
|
||||
@@ -14,13 +14,13 @@ Origin (DCO). This document was created by the Linux Kernel community and is a
|
||||
simple statement that you, as a contributor, have the legal right to make the
|
||||
contribution. No action from you is required, but it's a good idea to see the
|
||||
[DCO](DCO) file for details before you start contributing code to FluxCD
|
||||
toolkit.
|
||||
organization.
|
||||
|
||||
## Communications
|
||||
|
||||
The project uses Slack: To join the conversation, simply join the
|
||||
[CNCF](https://slack.cncf.io/) Slack workspace and use the
|
||||
[#flux](https://cloud-native.slack.com/messages/flux/) channel.
|
||||
[#flux-dev](https://cloud-native.slack.com/messages/flux-dev/) channel.
|
||||
|
||||
The developers use a mailing list to discuss development as well.
|
||||
Simply subscribe to [flux-dev on cncf.io](https://lists.cncf.io/g/cncf-flux-dev)
|
||||
@@ -57,7 +57,7 @@ get asked to resubmit the PR or divide the changes into more than one PR.
|
||||
|
||||
### Format of the Commit Message
|
||||
|
||||
For Source Controller we prefer the following rules for good commit messages:
|
||||
For the GitOps Toolkit controllers we prefer the following rules for good commit messages:
|
||||
|
||||
- Limit the subject to 50 characters and write as the continuation
|
||||
of the sentence "If applied, this commit will ..."
|
||||
@@ -66,3 +66,16 @@ For Source Controller we prefer the following rules for good commit messages:
|
||||
|
||||
The [following article](https://chris.beams.io/posts/git-commit/#seven-rules)
|
||||
has some more helpful advice on documenting your work.
|
||||
|
||||
## Understanding the GitOps Toolkit
|
||||
|
||||
If you are entirely new to the GitOps Toolkit,
|
||||
you might want to take a look at the [introductory talk and demo](https://www.youtube.com/watch?v=qQBtSkgl7tI).
|
||||
|
||||
This project is composed of:
|
||||
|
||||
- [/f/toolkit](https://github.com/fluxcd/toolkit): The GitOps Toolkit CLI
|
||||
- [/f/source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources
|
||||
- [/f/kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
|
||||
- [/f/helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
|
||||
- [/f/notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events
|
||||
|
||||
2
Makefile
@@ -11,7 +11,7 @@ fmt:
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
test: tidy fmt vet
|
||||
test: tidy fmt vet docs
|
||||
go test ./... -coverprofile cover.out
|
||||
|
||||
build:
|
||||
|
||||
11
README.md
@@ -1,4 +1,4 @@
|
||||
# toolkit
|
||||
# GitOps Toolkit
|
||||
|
||||
[](https://github.com/fluxcd/toolkit/actions)
|
||||
[](https://goreportcard.com/report/github.com/fluxcd/toolkit)
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
Experimental toolkit for assembling CD pipelines the GitOps way.
|
||||
|
||||

|
||||

|
||||
|
||||
Components:
|
||||
* [Toolkit CLI](docs/cmd/tk.md)
|
||||
* [Source Controller](https://github.com/fluxcd/source-controller)
|
||||
* [Kustomize Controller](https://github.com/fluxcd/kustomize-controller)
|
||||
|
||||
To install the toolkit CLI, follow the [instructions](install/README.md).
|
||||
To get started with the toolkit please read the [docs](https://toolkit.fluxcd.io/).
|
||||
|
||||
@@ -1,20 +1,252 @@
|
||||
/*
|
||||
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"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sigs.k8s.io/yaml"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
var bootstrapCmd = &cobra.Command{
|
||||
Use: "bootstrap",
|
||||
Short: "Bootstrap commands",
|
||||
Short: "Bootstrap toolkit components",
|
||||
Long: "The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.",
|
||||
}
|
||||
|
||||
var (
|
||||
bootstrapVersion string
|
||||
bootstrapVersion string
|
||||
bootstrapComponents []string
|
||||
)
|
||||
|
||||
const (
|
||||
bootstrapBranch = "master"
|
||||
bootstrapInstallManifest = "toolkit-components.yaml"
|
||||
bootstrapSourceManifest = "toolkit-source.yaml"
|
||||
bootstrapKustomizationManifest = "toolkit-kustomization.yaml"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func generateInstallManifests(targetPath, namespace, tmpDir string) (string, error) {
|
||||
tkDir := path.Join(tmpDir, ".tk")
|
||||
defer os.RemoveAll(tkDir)
|
||||
|
||||
if err := os.MkdirAll(tkDir, os.ModePerm); err != nil {
|
||||
return "", fmt.Errorf("generating manifests failed: %w", err)
|
||||
}
|
||||
|
||||
if err := genInstallManifests(bootstrapVersion, namespace, bootstrapComponents, tkDir); err != nil {
|
||||
return "", fmt.Errorf("generating manifests failed: %w", err)
|
||||
}
|
||||
|
||||
manifestsDir := path.Join(tmpDir, targetPath, namespace)
|
||||
if err := os.MkdirAll(manifestsDir, os.ModePerm); err != nil {
|
||||
return "", fmt.Errorf("generating manifests failed: %w", err)
|
||||
}
|
||||
|
||||
manifest := path.Join(manifestsDir, bootstrapInstallManifest)
|
||||
if err := buildKustomization(tkDir, manifest); err != nil {
|
||||
return "", fmt.Errorf("build kustomization failed: %w", err)
|
||||
}
|
||||
|
||||
return manifest, nil
|
||||
}
|
||||
|
||||
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
|
||||
command := fmt.Sprintf("kubectl apply -f %s", manifestPath)
|
||||
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
}
|
||||
|
||||
for _, deployment := range components {
|
||||
command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
|
||||
namespace, deployment, timeout.String())
|
||||
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateSyncManifests(url, name, namespace, targetPath, tmpDir string, interval time.Duration) error {
|
||||
gvk := sourcev1.GroupVersion.WithKind("GitRepository")
|
||||
gitRepository := sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
URL: url,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
},
|
||||
Reference: &sourcev1.GitRepositoryRef{
|
||||
Branch: "master",
|
||||
},
|
||||
SecretRef: &corev1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitData, err := yaml.Marshal(gitRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.writeFile(string(gitData), filepath.Join(tmpDir, targetPath, namespace, bootstrapSourceManifest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gvk = kustomizev1.GroupVersion.WithKind("Kustomization")
|
||||
kustomization := kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{
|
||||
Duration: 10 * time.Minute,
|
||||
},
|
||||
Path: fmt.Sprintf("./%s", strings.TrimPrefix(targetPath, "./")),
|
||||
Prune: true,
|
||||
SourceRef: kustomizev1.CrossNamespaceObjectReference{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ksData, err := yaml.Marshal(kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.writeFile(string(ksData), filepath.Join(tmpDir, targetPath, namespace, bootstrapKustomizationManifest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, targetPath, tmpDir string) error {
|
||||
command := fmt.Sprintf("kubectl apply -f %s", filepath.Join(tmpDir, targetPath, namespace))
|
||||
if _, err := utils.execCommand(ctx, ModeStderrOS, command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for cluster sync")
|
||||
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldInstallManifests(ctx context.Context, kubeClient client.Client, namespace string) bool {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: namespace,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
if err := kubeClient.Get(ctx, namespacedName, &kustomization); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return kustomization.Status.LastAppliedRevision == ""
|
||||
}
|
||||
|
||||
func shouldCreateDeployKey(ctx context.Context, kubeClient client.Client, namespace string) bool {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: namespace,
|
||||
}
|
||||
|
||||
var existing corev1.Secret
|
||||
if err := kubeClient.Get(ctx, namespacedName, &existing); err != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func generateDeployKey(ctx context.Context, kubeClient client.Client, url *url.URL, namespace string) (string, error) {
|
||||
pair, err := generateKeyPair(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hostKey, err := scanHostKey(ctx, url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
Namespace: namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"identity": string(pair.PrivateKey),
|
||||
"identity.pub": string(pair.PublicKey),
|
||||
"known_hosts": string(hostKey),
|
||||
},
|
||||
}
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(pair.PublicKey), nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -7,47 +23,38 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sigs.k8s.io/yaml"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/object"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/fluxcd/pkg/git"
|
||||
)
|
||||
|
||||
var bootstrapGitHubCmd = &cobra.Command{
|
||||
Use: "github",
|
||||
Short: "Bootstrap GitHub repository",
|
||||
Long: `
|
||||
The bootstrap command creates the GitHub repository if it doesn't exists and
|
||||
Short: "Bootstrap toolkit components in a GitHub repository",
|
||||
Long: `The bootstrap github command creates the GitHub repository if it doesn't exists and
|
||||
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,
|
||||
the bootstrap command will perform an upgrade if needed.`,
|
||||
Example: ` # Create a GitHub personal access token and export it as an env var
|
||||
export GITHUB_TOKEN=<my-token>
|
||||
|
||||
# Run bootstrap for a private repo owned by a GitHub organization
|
||||
bootstrap github --owner=<organization> --repository=<repo name>
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name>
|
||||
|
||||
# Run bootstrap for a private repo and assign organization teams to it
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
|
||||
|
||||
# Run bootstrap for a repository path
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
|
||||
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
tk bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
|
||||
# Run bootstrap for a private repo hosted on GitHub Enterprise
|
||||
bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
|
||||
`,
|
||||
RunE: bootstrapGitHubCmdRun,
|
||||
}
|
||||
@@ -59,37 +66,41 @@ var (
|
||||
ghPersonal bool
|
||||
ghPrivate bool
|
||||
ghHostname string
|
||||
ghPath string
|
||||
ghTeams []string
|
||||
)
|
||||
|
||||
const (
|
||||
ghTokenName = "GITHUB_TOKEN"
|
||||
ghBranch = "master"
|
||||
ghInstallManifest = "toolkit.yaml"
|
||||
ghSourceManifest = "toolkit-source.yaml"
|
||||
ghKustomizationManifest = "toolkit-kustomization.yaml"
|
||||
ghDefaultHostname = "github.com"
|
||||
ghDefaultPermission = "maintain"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghOwner, "owner", "", "GitHub user or organization name")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghRepository, "repository", "", "GitHub repository name")
|
||||
bootstrapGitHubCmd.Flags().StringArrayVar(&ghTeams, "team", []string{}, "GitHub team to be given maintainer access")
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&ghPersonal, "personal", false, "is personal repository")
|
||||
bootstrapGitHubCmd.Flags().BoolVar(&ghPrivate, "private", true, "is private repository")
|
||||
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", ghDefaultHostname, "GitHub hostname")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
||||
bootstrapGitHubCmd.Flags().StringVar(&ghPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
||||
|
||||
bootstrapCmd.AddCommand(bootstrapGitHubCmd)
|
||||
}
|
||||
|
||||
func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ghToken := os.Getenv(ghTokenName)
|
||||
ghToken := os.Getenv(git.GitHubTokenName)
|
||||
if ghToken == "" {
|
||||
return fmt.Errorf("%s environment variable not found", ghTokenName)
|
||||
return fmt.Errorf("%s environment variable not found", git.GitHubTokenName)
|
||||
}
|
||||
|
||||
ghURL := fmt.Sprintf("https://%s/%s/%s", ghHostname, ghOwner, ghRepository)
|
||||
sshURL := fmt.Sprintf("ssh://git@%s/%s/%s", ghHostname, ghOwner, ghRepository)
|
||||
if ghOwner == "" || ghRepository == "" {
|
||||
return fmt.Errorf("owner and repository are required")
|
||||
repository, err := git.NewRepository(ghRepository, ghOwner, ghHostname, ghToken, "tk", ghOwner+"@users.noreply.github.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider := &git.GithubProvider{
|
||||
IsPrivate: ghPrivate,
|
||||
IsPersonal: ghPersonal,
|
||||
}
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
@@ -107,428 +118,123 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
||||
defer cancel()
|
||||
|
||||
// create GitHub repository if doesn't exists
|
||||
logAction("connecting to %s", ghHostname)
|
||||
if err := createGitHubRepository(ctx, ghHostname, ghOwner, ghRepository, ghToken, ghPrivate, ghPersonal); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// clone repository and checkout the master branch
|
||||
repo, err := checkoutGitHubRepository(ctx, ghURL, ghBranch, ghToken, tmpDir)
|
||||
logger.Actionf("connecting to %s", ghHostname)
|
||||
changed, err := provider.CreateRepository(ctx, repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("repository cloned")
|
||||
if changed {
|
||||
logger.Successf("repository created")
|
||||
}
|
||||
|
||||
withErrors := false
|
||||
// add teams to org repository
|
||||
if !ghPersonal {
|
||||
for _, team := range ghTeams {
|
||||
if changed, err := provider.AddTeam(ctx, repository, team, ghDefaultPermission); err != nil {
|
||||
logger.Failuref(err.Error())
|
||||
withErrors = true
|
||||
} else if changed {
|
||||
logger.Successf("%s team access granted", team)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clone repository and checkout the master branch
|
||||
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("repository cloned")
|
||||
|
||||
// generate install manifests
|
||||
logGenerate("generating manifests")
|
||||
manifest, err := generateGitHubInstall(namespace, tmpDir)
|
||||
logger.Generatef("generating manifests")
|
||||
manifest, err := generateInstallManifests(ghPath, namespace, tmpDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stage install manifests
|
||||
changed, err := commitGitHubManifests(repo, namespace)
|
||||
changed, err = repository.Commit(ctx, path.Join(ghPath, namespace), "Add manifests")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// push install manifests
|
||||
if changed {
|
||||
if err := pushGitHubRepository(ctx, repo, ghToken); err != nil {
|
||||
if err := repository.Push(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("components manifests pushed")
|
||||
logger.Successf("components manifests pushed")
|
||||
} else {
|
||||
logSuccess("components are up to date")
|
||||
logger.Successf("components are up to date")
|
||||
}
|
||||
|
||||
// determine if repo synchronization is working
|
||||
isInstall := shouldInstallGitHub(ctx, kubeClient, namespace)
|
||||
isInstall := shouldInstallManifests(ctx, kubeClient, namespace)
|
||||
|
||||
if isInstall {
|
||||
// apply install manifests
|
||||
logAction("installing components in %s namespace", namespace)
|
||||
command := fmt.Sprintf("kubectl apply -f %s", manifest)
|
||||
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
}
|
||||
logSuccess("install completed")
|
||||
|
||||
// check installation
|
||||
logWaiting("verifying installation")
|
||||
for _, deployment := range components {
|
||||
command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
|
||||
namespace, deployment, timeout.String())
|
||||
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
} else {
|
||||
logSuccess("%s ready", deployment)
|
||||
}
|
||||
logger.Actionf("installing components in %s namespace", namespace)
|
||||
if err := applyInstallManifests(ctx, manifest, bootstrapComponents); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("install completed")
|
||||
}
|
||||
|
||||
// setup SSH deploy key
|
||||
if shouldCreateGitHubDeployKey(ctx, kubeClient, namespace) {
|
||||
logAction("configuring deploy key")
|
||||
u, err := url.Parse(sshURL)
|
||||
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
||||
logger.Actionf("configuring deploy key")
|
||||
u, err := url.Parse(repository.GetSSH())
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
|
||||
key, err := generateGitHubDeployKey(ctx, kubeClient, u, namespace)
|
||||
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating deploy key failed: %w", err)
|
||||
}
|
||||
|
||||
if err := createGitHubDeployKey(ctx, key, ghHostname, ghOwner, ghRepository, ghToken, ghPersonal); err != nil {
|
||||
return err
|
||||
keyName := "tk"
|
||||
if ghPath != "" {
|
||||
keyName = fmt.Sprintf("tk-%s", ghPath)
|
||||
}
|
||||
|
||||
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
|
||||
return err
|
||||
} else if changed {
|
||||
logger.Successf("deploy key configured")
|
||||
}
|
||||
logSuccess("deploy key configured")
|
||||
}
|
||||
|
||||
// configure repo synchronization
|
||||
if isInstall {
|
||||
// generate source and kustomization manifests
|
||||
logAction("generating sync manifests")
|
||||
if err := generateGitHubKustomization(sshURL, namespace, namespace, tmpDir, ghInterval); err != nil {
|
||||
logger.Actionf("generating sync manifests")
|
||||
if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stage manifests
|
||||
changed, err = commitGitHubManifests(repo, namespace)
|
||||
if err != nil {
|
||||
// commit and push manifests
|
||||
if changed, err = repository.Commit(ctx, path.Join(ghPath, namespace), "Add manifests"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// push manifests
|
||||
if changed {
|
||||
if err := pushGitHubRepository(ctx, repo, ghToken); err != nil {
|
||||
} else if changed {
|
||||
if err := repository.Push(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("sync manifests pushed")
|
||||
}
|
||||
logSuccess("sync manifests pushed")
|
||||
|
||||
// apply manifests and waiting for sync
|
||||
logAction("applying sync manifests")
|
||||
if err := applyGitHubKustomization(ctx, kubeClient, namespace, namespace, tmpDir); err != nil {
|
||||
logger.Actionf("applying sync manifests")
|
||||
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logSuccess("bootstrap finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeGitHubClient(hostname, token string) (*github.Client, error) {
|
||||
auth := github.BasicAuthTransport{
|
||||
Username: "git",
|
||||
Password: token,
|
||||
}
|
||||
|
||||
gh := github.NewClient(auth.Client())
|
||||
if hostname != ghDefaultHostname {
|
||||
baseURL := fmt.Sprintf("https://%s/api/v3/", hostname)
|
||||
uploadURL := fmt.Sprintf("https://%s/api/uploads/", hostname)
|
||||
if g, err := github.NewEnterpriseClient(baseURL, uploadURL, auth.Client()); err == nil {
|
||||
gh = g
|
||||
} else {
|
||||
return nil, fmt.Errorf("github client error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return gh, nil
|
||||
}
|
||||
|
||||
func createGitHubRepository(ctx context.Context, hostname, owner, name, token string, isPrivate, isPersonal bool) error {
|
||||
gh, err := makeGitHubClient(hostname, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
org := ""
|
||||
if !isPersonal {
|
||||
org = owner
|
||||
}
|
||||
|
||||
if _, _, err := gh.Repositories.Get(ctx, org, name); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
autoInit := true
|
||||
_, _, err = gh.Repositories.Create(ctx, org, &github.Repository{
|
||||
AutoInit: &autoInit,
|
||||
Name: &name,
|
||||
Private: &isPrivate,
|
||||
})
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "name already exists on this account") {
|
||||
return fmt.Errorf("github create repository error: %w", err)
|
||||
}
|
||||
} else {
|
||||
logSuccess("repository created")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkoutGitHubRepository(ctx context.Context, url, branch, token, path string) (*git.Repository, error) {
|
||||
auth := &http.BasicAuth{
|
||||
Username: "git",
|
||||
Password: token,
|
||||
}
|
||||
repo, err := git.PlainCloneContext(ctx, path, false, &git.CloneOptions{
|
||||
URL: url,
|
||||
Auth: auth,
|
||||
RemoteName: git.DefaultRemoteName,
|
||||
ReferenceName: plumbing.NewBranchReferenceName(branch),
|
||||
SingleBranch: true,
|
||||
NoCheckout: false,
|
||||
Progress: nil,
|
||||
Tags: git.NoTags,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("git clone error: %w", err)
|
||||
}
|
||||
|
||||
_, err = repo.Head()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("git resolve HEAD error: %w", err)
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func generateGitHubInstall(namespace, tmpDir string) (string, error) {
|
||||
tkDir := path.Join(tmpDir, ".tk")
|
||||
defer os.RemoveAll(tkDir)
|
||||
|
||||
if err := os.MkdirAll(tkDir, os.ModePerm); err != nil {
|
||||
return "", fmt.Errorf("generating manifests failed: %w", err)
|
||||
}
|
||||
|
||||
if err := genInstallManifests(bootstrapVersion, namespace, components, tkDir); err != nil {
|
||||
return "", fmt.Errorf("generating manifests failed: %w", err)
|
||||
}
|
||||
|
||||
manifestsDir := path.Join(tmpDir, namespace)
|
||||
if err := os.MkdirAll(manifestsDir, os.ModePerm); err != nil {
|
||||
return "", fmt.Errorf("generating manifests failed: %w", err)
|
||||
}
|
||||
|
||||
manifest := path.Join(manifestsDir, ghInstallManifest)
|
||||
if err := buildKustomization(tkDir, manifest); err != nil {
|
||||
return "", fmt.Errorf("build kustomization failed: %w", err)
|
||||
}
|
||||
|
||||
return manifest, nil
|
||||
}
|
||||
|
||||
func commitGitHubManifests(repo *git.Repository, namespace string) (bool, error) {
|
||||
w, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
_, err = w.Add(namespace)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
status, err := w.Status()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !status.IsClean() {
|
||||
if _, err := w.Commit("Add manifests", &git.CommitOptions{
|
||||
Author: &object.Signature{
|
||||
Name: "tk",
|
||||
Email: "tk@users.noreply.github.com",
|
||||
When: time.Now(),
|
||||
},
|
||||
}); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func pushGitHubRepository(ctx context.Context, repo *git.Repository, token string) error {
|
||||
auth := &http.BasicAuth{
|
||||
Username: "git",
|
||||
Password: token,
|
||||
}
|
||||
err := repo.PushContext(ctx, &git.PushOptions{
|
||||
Auth: auth,
|
||||
Progress: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("git push error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateGitHubKustomization(url, name, namespace, tmpDir string, interval time.Duration) error {
|
||||
gvk := sourcev1.GroupVersion.WithKind("GitRepository")
|
||||
gitRepository := sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: sourcev1.GitRepositorySpec{
|
||||
URL: url,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
},
|
||||
Reference: &sourcev1.GitRepositoryRef{
|
||||
Branch: "master",
|
||||
},
|
||||
SecretRef: &corev1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gitData, err := yaml.Marshal(gitRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.writeFile(string(gitData), filepath.Join(tmpDir, namespace, ghSourceManifest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gvk = kustomizev1.GroupVersion.WithKind("Kustomization")
|
||||
emptyAPIGroup := ""
|
||||
kustomization := kustomizev1.Kustomization{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: kustomizev1.KustomizationSpec{
|
||||
Interval: metav1.Duration{
|
||||
Duration: 10 * time.Minute,
|
||||
},
|
||||
Path: "./",
|
||||
Prune: true,
|
||||
SourceRef: corev1.TypedLocalObjectReference{
|
||||
APIGroup: &emptyAPIGroup,
|
||||
Kind: "GitRepository",
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ksData, err := yaml.Marshal(kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.writeFile(string(ksData), filepath.Join(tmpDir, namespace, ghKustomizationManifest)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyGitHubKustomization(ctx context.Context, kubeClient client.Client, name, namespace, tmpDir string) error {
|
||||
command := fmt.Sprintf("kubectl apply -f %s", filepath.Join(tmpDir, namespace))
|
||||
if _, err := utils.execCommand(ctx, ModeStderrOS, command); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logWaiting("waiting for cluster sync")
|
||||
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldInstallGitHub(ctx context.Context, kubeClient client.Client, namespace string) bool {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: namespace,
|
||||
}
|
||||
var kustomization kustomizev1.Kustomization
|
||||
if err := kubeClient.Get(ctx, namespacedName, &kustomization); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return kustomization.Status.LastAppliedRevision == ""
|
||||
}
|
||||
|
||||
func shouldCreateGitHubDeployKey(ctx context.Context, kubeClient client.Client, namespace string) bool {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: namespace,
|
||||
}
|
||||
|
||||
var existing corev1.Secret
|
||||
if err := kubeClient.Get(ctx, namespacedName, &existing); err != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func generateGitHubDeployKey(ctx context.Context, kubeClient client.Client, url *url.URL, namespace string) (string, error) {
|
||||
pair, err := generateKeyPair(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
hostKey, err := scanHostKey(ctx, url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespace,
|
||||
Namespace: namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"identity": string(pair.PrivateKey),
|
||||
"identity.pub": string(pair.PublicKey),
|
||||
"known_hosts": string(hostKey),
|
||||
},
|
||||
}
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(pair.PublicKey), nil
|
||||
}
|
||||
|
||||
func createGitHubDeployKey(ctx context.Context, key, hostname, owner, name, token string, isPersonal bool) error {
|
||||
gh, err := makeGitHubClient(hostname, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyName := fmt.Sprintf("tk-%s", namespace)
|
||||
isReadOnly := true
|
||||
_, _, err = gh.Repositories.CreateKey(ctx, owner, name, &github.Key{
|
||||
Title: &keyName,
|
||||
Key: &key,
|
||||
ReadOnly: &isReadOnly,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("github create deploy key error: %w", err)
|
||||
}
|
||||
if withErrors {
|
||||
return fmt.Errorf("bootstrap completed with errors")
|
||||
}
|
||||
|
||||
logger.Successf("bootstrap finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
214
cmd/tk/bootstrap_gitlab.go
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/fluxcd/pkg/git"
|
||||
)
|
||||
|
||||
var bootstrapGitLabCmd = &cobra.Command{
|
||||
Use: "gitlab",
|
||||
Short: "Bootstrap toolkit components in a GitLab repository",
|
||||
Long: `The bootstrap gitlab command creates the GitLab repository if it doesn't exists and
|
||||
commits the toolkit components manifests to the master branch.
|
||||
Then it configures the target cluster to synchronize with the repository.
|
||||
If the toolkit components are present on the cluster,
|
||||
the bootstrap command will perform an upgrade if needed.`,
|
||||
Example: ` # Create a GitLab API token and export it as an env var
|
||||
export GITLAB_TOKEN=<my-token>
|
||||
|
||||
# Run bootstrap for a private repo owned by a GitLab group
|
||||
tk bootstrap gitlab --owner=<group> --repository=<repo name>
|
||||
|
||||
# Run bootstrap for a repository path
|
||||
tk bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
|
||||
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
tk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
|
||||
# Run bootstrap for a private repo hosted on a GitLab server
|
||||
tk bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
|
||||
`,
|
||||
RunE: bootstrapGitLabCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
glOwner string
|
||||
glRepository string
|
||||
glInterval time.Duration
|
||||
glPersonal bool
|
||||
glPrivate bool
|
||||
glHostname string
|
||||
glPath string
|
||||
)
|
||||
|
||||
func init() {
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glOwner, "owner", "", "GitLab user or group name")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glRepository, "repository", "", "GitLab repository name")
|
||||
bootstrapGitLabCmd.Flags().BoolVar(&glPersonal, "personal", false, "is personal repository")
|
||||
bootstrapGitLabCmd.Flags().BoolVar(&glPrivate, "private", true, "is private repository")
|
||||
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
||||
bootstrapGitLabCmd.Flags().StringVar(&glPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
||||
|
||||
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
|
||||
}
|
||||
|
||||
func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
||||
glToken := os.Getenv(git.GitLabTokenName)
|
||||
if glToken == "" {
|
||||
return fmt.Errorf("%s environment variable not found", git.GitLabTokenName)
|
||||
}
|
||||
|
||||
repository, err := git.NewRepository(glRepository, glOwner, glHostname, glToken, "tk", glOwner+"@users.noreply.gitlab.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider := &git.GitLabProvider{
|
||||
IsPrivate: glPrivate,
|
||||
IsPersonal: glPersonal,
|
||||
}
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
// create GitLab project if doesn't exists
|
||||
logger.Actionf("connecting to %s", glHostname)
|
||||
changed, err := provider.CreateRepository(ctx, repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if changed {
|
||||
logger.Successf("repository created")
|
||||
}
|
||||
|
||||
// clone repository and checkout the master branch
|
||||
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("repository cloned")
|
||||
|
||||
// generate install manifests
|
||||
logger.Generatef("generating manifests")
|
||||
manifest, err := generateInstallManifests(glPath, namespace, tmpDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stage install manifests
|
||||
changed, err = repository.Commit(ctx, path.Join(glPath, namespace), "Add manifests")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// push install manifests
|
||||
if changed {
|
||||
if err := repository.Push(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("components manifests pushed")
|
||||
} else {
|
||||
logger.Successf("components are up to date")
|
||||
}
|
||||
|
||||
// determine if repo synchronization is working
|
||||
isInstall := shouldInstallManifests(ctx, kubeClient, namespace)
|
||||
|
||||
if isInstall {
|
||||
// apply install manifests
|
||||
logger.Actionf("installing components in %s namespace", namespace)
|
||||
if err := applyInstallManifests(ctx, manifest, bootstrapComponents); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("install completed")
|
||||
}
|
||||
|
||||
// setup SSH deploy key
|
||||
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
||||
logger.Actionf("configuring deploy key")
|
||||
u, err := url.Parse(repository.GetSSH())
|
||||
if err != nil {
|
||||
return fmt.Errorf("git URL parse failed: %w", err)
|
||||
}
|
||||
|
||||
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating deploy key failed: %w", err)
|
||||
}
|
||||
|
||||
keyName := "tk"
|
||||
if glPath != "" {
|
||||
keyName = fmt.Sprintf("tk-%s", glPath)
|
||||
}
|
||||
|
||||
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
|
||||
return err
|
||||
} else if changed {
|
||||
logger.Successf("deploy key configured")
|
||||
}
|
||||
}
|
||||
|
||||
// configure repo synchronization
|
||||
if isInstall {
|
||||
// generate source and kustomization manifests
|
||||
logger.Actionf("generating sync manifests")
|
||||
if err := generateSyncManifests(repository.GetSSH(), namespace, namespace, glPath, tmpDir, glInterval); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// commit and push manifests
|
||||
if changed, err = repository.Commit(ctx, path.Join(glPath, namespace), "Add manifests"); err != nil {
|
||||
return err
|
||||
} else if changed {
|
||||
if err := repository.Push(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("sync manifests pushed")
|
||||
}
|
||||
|
||||
// apply manifests and waiting for sync
|
||||
logger.Actionf("applying sync manifests")
|
||||
if err := applySyncManifests(ctx, kubeClient, namespace, namespace, glPath, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Successf("bootstrap finished")
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -16,26 +32,27 @@ import (
|
||||
var checkCmd = &cobra.Command{
|
||||
Use: "check",
|
||||
Short: "Check requirements and installation",
|
||||
Long: `
|
||||
The check command will perform a series of checks to validate that
|
||||
Long: `The check command will perform a series of checks to validate that
|
||||
the local environment is configured correctly and if the installed components are healthy.`,
|
||||
Example: ` # Run pre-installation checks
|
||||
check --pre
|
||||
tk check --pre
|
||||
|
||||
# Run installation checks
|
||||
check
|
||||
tk check
|
||||
`,
|
||||
RunE: runCheckCmd,
|
||||
}
|
||||
|
||||
var (
|
||||
checkPre bool
|
||||
checkPre bool
|
||||
checkComponents []string
|
||||
)
|
||||
|
||||
func init() {
|
||||
checkCmd.Flags().BoolVarP(&checkPre, "pre", "", false,
|
||||
"only run pre-installation checks")
|
||||
|
||||
checkCmd.Flags().StringSliceVar(&checkComponents, "components", defaultComponents,
|
||||
"list of components, accepts comma-separated values")
|
||||
rootCmd.AddCommand(checkCmd)
|
||||
}
|
||||
|
||||
@@ -43,14 +60,14 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
logAction("checking prerequisites")
|
||||
logger.Actionf("checking prerequisites")
|
||||
checkFailed := false
|
||||
|
||||
if !kubectlCheck(ctx, ">=1.18.0") {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
if !kubernetesCheck(">=1.14.0") {
|
||||
if !kubernetesCheck(">=1.16.0") {
|
||||
checkFailed = true
|
||||
}
|
||||
|
||||
@@ -58,83 +75,83 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
||||
if checkFailed {
|
||||
os.Exit(1)
|
||||
}
|
||||
logSuccess("prerequisites checks passed")
|
||||
logger.Successf("prerequisites checks passed")
|
||||
return nil
|
||||
}
|
||||
|
||||
logAction("checking controllers")
|
||||
logger.Actionf("checking controllers")
|
||||
if !componentsCheck() {
|
||||
checkFailed = true
|
||||
}
|
||||
if checkFailed {
|
||||
os.Exit(1)
|
||||
}
|
||||
logSuccess("all checks passed")
|
||||
logger.Successf("all checks passed")
|
||||
return nil
|
||||
}
|
||||
|
||||
func kubectlCheck(ctx context.Context, version string) bool {
|
||||
_, err := exec.LookPath("kubectl")
|
||||
if err != nil {
|
||||
logFailure("kubectl not found")
|
||||
logger.Failuref("kubectl not found")
|
||||
return false
|
||||
}
|
||||
|
||||
command := "kubectl version --client --short | awk '{ print $3 }'"
|
||||
output, err := utils.execCommand(ctx, ModeCapture, command)
|
||||
if err != nil {
|
||||
logFailure("kubectl version can't be determined")
|
||||
logger.Failuref("kubectl version can't be determined")
|
||||
return false
|
||||
}
|
||||
|
||||
v, err := semver.ParseTolerant(output)
|
||||
if err != nil {
|
||||
logFailure("kubectl version can't be parsed")
|
||||
logger.Failuref("kubectl version can't be parsed")
|
||||
return false
|
||||
}
|
||||
|
||||
rng, _ := semver.ParseRange(version)
|
||||
if !rng(v) {
|
||||
logFailure("kubectl version must be %s", version)
|
||||
logger.Failuref("kubectl version must be %s", version)
|
||||
return false
|
||||
}
|
||||
|
||||
logSuccess("kubectl %s %s", v.String(), version)
|
||||
logger.Successf("kubectl %s %s", v.String(), version)
|
||||
return true
|
||||
}
|
||||
|
||||
func kubernetesCheck(version string) bool {
|
||||
cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
if err != nil {
|
||||
logFailure("kubernetes client initialization failed: %s", err.Error())
|
||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
client, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
logFailure("kubernetes client initialization failed: %s", err.Error())
|
||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
ver, err := client.Discovery().ServerVersion()
|
||||
if err != nil {
|
||||
logFailure("kubernetes API call failed %s", err.Error())
|
||||
logger.Failuref("Kubernetes API call failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
v, err := semver.ParseTolerant(ver.String())
|
||||
if err != nil {
|
||||
logFailure("kubernetes version can't be determined")
|
||||
logger.Failuref("Kubernetes version can't be determined")
|
||||
return false
|
||||
}
|
||||
|
||||
rng, _ := semver.ParseRange(version)
|
||||
if !rng(v) {
|
||||
logFailure("kubernetes version must be %s", version)
|
||||
logger.Failuref("Kubernetes version must be %s", version)
|
||||
return false
|
||||
}
|
||||
|
||||
logSuccess("kubernetes %s %s", v.String(), version)
|
||||
logger.Successf("Kubernetes %s %s", v.String(), version)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -143,14 +160,14 @@ func componentsCheck() bool {
|
||||
defer cancel()
|
||||
|
||||
ok := true
|
||||
for _, deployment := range components {
|
||||
for _, deployment := range checkComponents {
|
||||
command := fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
|
||||
namespace, deployment, timeout.String())
|
||||
if output, err := utils.execCommand(ctx, ModeCapture, command); err != nil {
|
||||
logFailure("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
|
||||
logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
|
||||
ok = false
|
||||
} else {
|
||||
logSuccess("%s is healthy", deployment)
|
||||
logger.Successf("%s is healthy", deployment)
|
||||
}
|
||||
}
|
||||
return ok
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -8,7 +24,8 @@ import (
|
||||
|
||||
var createCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create commands",
|
||||
Short: "Create or update sources and resources",
|
||||
Long: "The create sub-commands generate sources and resources.",
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -18,6 +35,6 @@ var (
|
||||
|
||||
func init() {
|
||||
createCmd.PersistentFlags().DurationVarP(&interval, "interval", "", time.Minute, "source sync interval")
|
||||
createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in yaml format to stdout")
|
||||
createCmd.PersistentFlags().BoolVar(&export, "export", false, "export in YAML format to stdout")
|
||||
rootCmd.AddCommand(createCmd)
|
||||
}
|
||||
|
||||
256
cmd/tk/create_helmrelease.go
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
var createHelmReleaseCmd = &cobra.Command{
|
||||
Use: "helmrelease [name]",
|
||||
Aliases: []string{"hr"},
|
||||
Short: "Create or update a HelmRelease resource",
|
||||
Long: "The helmrelease create command generates a HelmRelease resource for a given HelmRepository source.",
|
||||
Example: ` # Create a HelmRelease from a source
|
||||
tk create hr podinfo \
|
||||
--interval=10m \
|
||||
--release-name=podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=">4.0.0"
|
||||
|
||||
# Create a HelmRelease with values for a local YAML file
|
||||
tk create hr podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=4.0.5 \
|
||||
--values=./my-values.yaml
|
||||
|
||||
# Create a HelmRelease definition on disk without applying it on the cluster
|
||||
tk create hr podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=4.0.5 \
|
||||
--values=./values.yaml \
|
||||
--export > podinfo-release.yaml
|
||||
`,
|
||||
RunE: createHelmReleaseCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
hrName string
|
||||
hrSource string
|
||||
hrDependsOn []string
|
||||
hrChartName string
|
||||
hrChartVersion string
|
||||
hrTargetNamespace string
|
||||
hrValuesFile string
|
||||
)
|
||||
|
||||
func init() {
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrName, "release-name", "", "name used for the Helm release, defaults to a composition of '<target-namespace>-<hr-name>'")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrSource, "source", "", "HelmRepository name")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrChartName, "chart-name", "", "Helm chart name")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrChartVersion, "chart-version", "", "Helm chart version, accepts semver range")
|
||||
createHelmReleaseCmd.Flags().StringArrayVar(&hrDependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrTargetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
|
||||
createHelmReleaseCmd.Flags().StringVar(&hrValuesFile, "values", "", "local path to the values.yaml file")
|
||||
createCmd.AddCommand(createHelmReleaseCmd)
|
||||
}
|
||||
|
||||
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("release name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if hrSource == "" {
|
||||
return fmt.Errorf("source is required")
|
||||
}
|
||||
if hrChartName == "" {
|
||||
return fmt.Errorf("chart name is required")
|
||||
}
|
||||
if hrChartVersion == "" {
|
||||
return fmt.Errorf("chart version is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !export {
|
||||
logger.Generatef("generating release")
|
||||
}
|
||||
|
||||
helmRelease := helmv2.HelmRelease{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: helmv2.HelmReleaseSpec{
|
||||
ReleaseName: hrName,
|
||||
DependsOn: hrDependsOn,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
},
|
||||
TargetNamespace: hrTargetNamespace,
|
||||
Chart: helmv2.HelmChartTemplate{
|
||||
Name: hrChartName,
|
||||
Version: hrChartVersion,
|
||||
SourceRef: helmv2.CrossNamespaceObjectReference{
|
||||
Kind: sourcev1.HelmRepositoryKind,
|
||||
Name: hrSource,
|
||||
},
|
||||
},
|
||||
Suspend: false,
|
||||
},
|
||||
}
|
||||
|
||||
if hrValuesFile != "" {
|
||||
data, err := ioutil.ReadFile(hrValuesFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reading values from %s failed: %w", hrValuesFile, err)
|
||||
}
|
||||
|
||||
json, err := yaml.YAMLToJSON(data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("converting values to JSON from %s failed: %w", hrValuesFile, err)
|
||||
}
|
||||
|
||||
helmRelease.Spec.Values = apiextensionsv1.JSON{Raw: json}
|
||||
}
|
||||
|
||||
if export {
|
||||
return exportHelmRelease(helmRelease)
|
||||
}
|
||||
|
||||
logger.Actionf("applying release")
|
||||
if err := upsertHelmRelease(ctx, kubeClient, helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for reconciliation")
|
||||
chartName := fmt.Sprintf("%s-%s", namespace, name)
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmChartReady(ctx, kubeClient, chartName, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmReleaseReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("release %s is ready", name)
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return fmt.Errorf("release failed: %w", err)
|
||||
}
|
||||
|
||||
if helmRelease.Status.LastAppliedRevision != "" {
|
||||
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
|
||||
} else {
|
||||
return fmt.Errorf("reconciliation failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func upsertHelmRelease(ctx context.Context, kubeClient client.Client, helmRelease helmv2.HelmRelease) error {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: helmRelease.GetNamespace(),
|
||||
Name: helmRelease.GetName(),
|
||||
}
|
||||
|
||||
var existing helmv2.HelmRelease
|
||||
err := kubeClient.Get(ctx, namespacedName, &existing)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
if err := kubeClient.Create(ctx, &helmRelease); err != nil {
|
||||
return err
|
||||
} else {
|
||||
logger.Successf("release created")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
existing.Spec = helmRelease.Spec
|
||||
if err := kubeClient.Update(ctx, &existing); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("release updated")
|
||||
return nil
|
||||
}
|
||||
|
||||
func isHelmChartReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
var helmChart sourcev1.HelmChart
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err := kubeClient.Get(ctx, namespacedName, &helmChart)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, condition := range helmChart.Status.Conditions {
|
||||
if condition.Type == helmv2.ReadyCondition {
|
||||
if condition.Status == corev1.ConditionTrue {
|
||||
return true, nil
|
||||
} else if condition.Status == corev1.ConditionFalse {
|
||||
return false, fmt.Errorf(condition.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -21,37 +37,35 @@ import (
|
||||
var createKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Create or update a kustomization resource",
|
||||
Long: `
|
||||
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`,
|
||||
Example: ` # Create a kustomization from a source at a given path
|
||||
create kustomization contour \
|
||||
Short: "Create or update a Kustomization resource",
|
||||
Long: "The kustomization source create command generates a Kustomize resource for a given GitRepository source.",
|
||||
Example: ` # Create a Kustomization resource from a source at a given path
|
||||
tk create kustomization contour \
|
||||
--source=contour \
|
||||
--path="./examples/contour/" \
|
||||
--prune=true \
|
||||
--interval=10m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--health-check="Deployment/contour.projectcontour" \
|
||||
--health-check="DaemonSet/envoy.projectcontour" \
|
||||
--health-check-timeout=3m
|
||||
|
||||
# Create a kustomization that depends on the previous one
|
||||
create kustomization webapp \
|
||||
# Create a Kustomization resource that depends on the previous one
|
||||
tk create kustomization webapp \
|
||||
--depends-on=contour \
|
||||
--source=webapp \
|
||||
--path="./deploy/overlays/dev" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client
|
||||
--validation=client
|
||||
|
||||
# Create a kustomization that runs under a service account
|
||||
create kustomization webapp \
|
||||
# Create a Kustomization resource that runs under a service account
|
||||
tk create kustomization webapp \
|
||||
--source=webapp \
|
||||
--path="./deploy/overlays/staging" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--sa-name=reconclier \
|
||||
--sa-namespace=staging
|
||||
`,
|
||||
@@ -63,7 +77,7 @@ var (
|
||||
ksPath string
|
||||
ksPrune bool
|
||||
ksDependsOn []string
|
||||
ksValidate string
|
||||
ksValidation string
|
||||
ksHealthCheck []string
|
||||
ksHealthTimeout time.Duration
|
||||
ksSAName string
|
||||
@@ -72,12 +86,12 @@ var (
|
||||
|
||||
func init() {
|
||||
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().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
||||
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
||||
createKsCmd.Flags().StringVar(&ksValidate, "validate", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
|
||||
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "kustomization that must be ready before this kustomization can be applied")
|
||||
createKsCmd.Flags().StringVar(&ksValidation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
|
||||
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied")
|
||||
createKsCmd.Flags().StringVar(&ksSAName, "sa-name", "", "service account name")
|
||||
createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace")
|
||||
createCmd.AddCommand(createKsCmd)
|
||||
@@ -108,10 +122,9 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if !export {
|
||||
logGenerate("generating kustomization")
|
||||
logger.Generatef("generating kustomization")
|
||||
}
|
||||
|
||||
emptyAPIGroup := ""
|
||||
kustomization := kustomizev1.Kustomization{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
@@ -124,13 +137,12 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
},
|
||||
Path: ksPath,
|
||||
Prune: ksPrune,
|
||||
SourceRef: corev1.TypedLocalObjectReference{
|
||||
APIGroup: &emptyAPIGroup,
|
||||
Kind: "GitRepository",
|
||||
Name: ksSource,
|
||||
SourceRef: kustomizev1.CrossNamespaceObjectReference{
|
||||
Kind: sourcev1.GitRepositoryKind,
|
||||
Name: ksSource,
|
||||
},
|
||||
Suspend: false,
|
||||
Validation: ksValidate,
|
||||
Validation: ksValidation,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -178,18 +190,18 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
return exportKs(kustomization)
|
||||
}
|
||||
|
||||
logAction("applying kustomization")
|
||||
logger.Actionf("applying kustomization")
|
||||
if err := upsertKustomization(ctx, kubeClient, kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logWaiting("waiting for kustomization sync")
|
||||
logger.Waitingf("waiting for kustomization sync")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("kustomization %s is ready", name)
|
||||
logger.Successf("kustomization %s is ready", name)
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
@@ -201,7 +213,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if kustomization.Status.LastAppliedRevision != "" {
|
||||
logSuccess("applied revision %s", kustomization.Status.LastAppliedRevision)
|
||||
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
|
||||
} else {
|
||||
return fmt.Errorf("kustomization sync failed")
|
||||
}
|
||||
@@ -222,7 +234,7 @@ func upsertKustomization(ctx context.Context, kubeClient client.Client, kustomiz
|
||||
if err := kubeClient.Create(ctx, &kustomization); err != nil {
|
||||
return err
|
||||
} else {
|
||||
logSuccess("kustomization created")
|
||||
logger.Successf("kustomization created")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -234,7 +246,7 @@ func upsertKustomization(ctx context.Context, kubeClient client.Client, kustomiz
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("kustomization updated")
|
||||
logger.Successf("kustomization updated")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var createSourceCmd = &cobra.Command{
|
||||
Use: "source",
|
||||
Short: "Create source commands",
|
||||
Short: "Create or update sources",
|
||||
Long: "The create source sub-commands generate sources.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -19,46 +35,46 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/toolkit/pkg/ssh"
|
||||
"github.com/fluxcd/pkg/ssh"
|
||||
)
|
||||
|
||||
var createSourceGitCmd = &cobra.Command{
|
||||
Use: "git [name]",
|
||||
Short: "Create or update a git source",
|
||||
Short: "Create or update a GitRepository source",
|
||||
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 private Git repositories, the basic authentication credentials are stored in a Kubernetes secret.`,
|
||||
Example: ` # Create a source from a public Git repository master branch
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--branch=master
|
||||
|
||||
# Create a source from a Git repository pinned to specific git tag
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--tag="3.2.3"
|
||||
|
||||
# Create a source from a public Git repository tag that matches a semver range
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--tag-semver=">=3.2.0 <3.3.0"
|
||||
|
||||
# Create a source from a Git repository using SSH authentication
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||
--branch=master
|
||||
|
||||
# Create a source from a Git repository using SSH authentication and an
|
||||
# ECDSA P-521 curve public key
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||
--branch=master \
|
||||
--ssh-key-algorithm=ecdsa \
|
||||
--ssh-ecdsa-curve=p521
|
||||
|
||||
# Create a source from a Git repository using basic authentication
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--username=username \
|
||||
--password=password
|
||||
@@ -99,7 +115,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
if sourceGitURL == "" {
|
||||
return fmt.Errorf("git-url is required")
|
||||
return fmt.Errorf("url is required")
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", name)
|
||||
@@ -150,7 +166,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
withAuth := false
|
||||
// TODO(hidde): move all auth prep to separate func?
|
||||
if u.Scheme == "ssh" {
|
||||
logAction("generating deploy key pair")
|
||||
logger.Actionf("generating deploy key pair")
|
||||
pair, err := generateKeyPair(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -165,15 +181,15 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("collected public key from SSH server:")
|
||||
logger.Successf("collected public key from SSH server:")
|
||||
fmt.Printf("%s", hostKey)
|
||||
|
||||
logAction("applying secret with keys")
|
||||
logger.Actionf("applying secret with keys")
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
@@ -190,7 +206,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
withAuth = true
|
||||
} else if sourceGitUsername != "" && sourceGitPassword != "" {
|
||||
logAction("applying secret with basic auth credentials")
|
||||
logger.Actionf("applying secret with basic auth credentials")
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
@@ -208,10 +224,10 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if withAuth {
|
||||
logSuccess("authentication configured")
|
||||
logger.Successf("authentication configured")
|
||||
}
|
||||
|
||||
logGenerate("generating source")
|
||||
logger.Generatef("generating source")
|
||||
|
||||
if withAuth {
|
||||
gitRepository.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
@@ -219,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 {
|
||||
return err
|
||||
}
|
||||
|
||||
logWaiting("waiting for git sync")
|
||||
logger.Waitingf("waiting for git sync")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("git sync completed")
|
||||
logger.Successf("git sync completed")
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
@@ -242,7 +258,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if gitRepository.Status.Artifact != nil {
|
||||
logSuccess("fetched revision %s", gitRepository.Status.Artifact.Revision)
|
||||
logger.Successf("fetched revision: %s", gitRepository.Status.Artifact.Revision)
|
||||
} else {
|
||||
return fmt.Errorf("git sync failed, artifact not found")
|
||||
}
|
||||
@@ -252,7 +268,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
func generateKeyPair(ctx context.Context) (*ssh.KeyPair, error) {
|
||||
var keyGen ssh.KeyPairGenerator
|
||||
switch sourceGitKeyAlgorithm.String() {
|
||||
switch algorithm := sourceGitKeyAlgorithm.String(); algorithm {
|
||||
case "rsa":
|
||||
keyGen = ssh.NewRSAGenerator(int(sourceGitRSABits))
|
||||
case "ecdsa":
|
||||
@@ -260,11 +276,11 @@ func generateKeyPair(ctx context.Context) (*ssh.KeyPair, error) {
|
||||
case "ed25519":
|
||||
keyGen = ssh.NewEd25519Generator()
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported public key algorithm '%s'", sourceGitKeyAlgorithm.String())
|
||||
return nil, fmt.Errorf("unsupported public key algorithm: %s", algorithm)
|
||||
}
|
||||
pair, err := keyGen.Generate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("key pair generation failed: %w", err)
|
||||
return nil, fmt.Errorf("key pair generation failed, error: %w", err)
|
||||
}
|
||||
return pair, nil
|
||||
}
|
||||
@@ -276,7 +292,7 @@ func scanHostKey(ctx context.Context, url *url.URL) ([]byte, error) {
|
||||
}
|
||||
hostKey, err := ssh.ScanHostKey(host, 30*time.Second)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SSH key scan for host '%s' failed: %w", host, err)
|
||||
return nil, fmt.Errorf("SSH key scan for host %s failed, error: %w", host, err)
|
||||
}
|
||||
return hostKey, nil
|
||||
}
|
||||
@@ -320,7 +336,7 @@ func upsertGitRepository(ctx context.Context, kubeClient client.Client, gitRepos
|
||||
if err := kubeClient.Create(ctx, &gitRepository); err != nil {
|
||||
return err
|
||||
} else {
|
||||
logSuccess("source created")
|
||||
logger.Successf("source created")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -332,7 +348,7 @@ func upsertGitRepository(ctx context.Context, kubeClient client.Client, gitRepos
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("source updated")
|
||||
logger.Successf("source updated")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
229
cmd/tk/create_source_helm.go
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"io/ioutil"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"net/url"
|
||||
"os"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var createSourceHelmCmd = &cobra.Command{
|
||||
Use: "helm [name]",
|
||||
Short: "Create or update a HelmRepository source",
|
||||
Long: `
|
||||
The create source helm command generates a HelmRepository resource and waits for it to fetch the index.
|
||||
For private Helm repositories, the basic authentication credentials are stored in a Kubernetes secret.`,
|
||||
Example: ` # Create a source from a public Helm repository
|
||||
tk create source helm podinfo \
|
||||
--url=https://stefanprodan.github.io/podinfo \
|
||||
--interval=10m
|
||||
|
||||
# Create a source from a Helm repository using basic authentication
|
||||
tk create source helm podinfo \
|
||||
--url=https://stefanprodan.github.io/podinfo \
|
||||
--username=username \
|
||||
--password=password
|
||||
`,
|
||||
RunE: createSourceHelmCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
sourceHelmURL string
|
||||
sourceHelmUsername string
|
||||
sourceHelmPassword string
|
||||
)
|
||||
|
||||
func init() {
|
||||
createSourceHelmCmd.Flags().StringVar(&sourceHelmURL, "url", "", "Helm repository address")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmUsername, "username", "u", "", "basic authentication username")
|
||||
createSourceHelmCmd.Flags().StringVarP(&sourceHelmPassword, "password", "p", "", "basic authentication password")
|
||||
|
||||
createSourceCmd.AddCommand(createSourceHelmCmd)
|
||||
}
|
||||
|
||||
func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
secretName := fmt.Sprintf("helm-%s", name)
|
||||
|
||||
if sourceHelmURL == "" {
|
||||
return fmt.Errorf("url is required")
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if _, err := url.Parse(sourceHelmURL); err != nil {
|
||||
return fmt.Errorf("url parse failed: %w", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
helmRepository := sourcev1.HelmRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: sourcev1.HelmRepositorySpec{
|
||||
URL: sourceHelmURL,
|
||||
Interval: metav1.Duration{
|
||||
Duration: interval,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if export {
|
||||
return exportHelmRepository(helmRepository)
|
||||
}
|
||||
|
||||
withAuth := false
|
||||
if sourceHelmUsername != "" && sourceHelmPassword != "" {
|
||||
logger.Actionf("applying secret with basic auth credentials")
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
"username": sourceHelmUsername,
|
||||
"password": sourceHelmPassword,
|
||||
},
|
||||
}
|
||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
withAuth = true
|
||||
}
|
||||
|
||||
if withAuth {
|
||||
logger.Successf("authentication configured")
|
||||
}
|
||||
|
||||
logger.Generatef("generating source")
|
||||
|
||||
if withAuth {
|
||||
helmRepository.Spec.SecretRef = &corev1.LocalObjectReference{
|
||||
Name: secretName,
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("applying source")
|
||||
if err := upsertHelmRepository(ctx, kubeClient, helmRepository); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for index download")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("index download completed")
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
|
||||
if err != nil {
|
||||
return fmt.Errorf("helm index failed: %w", err)
|
||||
}
|
||||
|
||||
if helmRepository.Status.Artifact != nil {
|
||||
logger.Successf("fetched revision: %s", helmRepository.Status.Artifact.Revision)
|
||||
} else {
|
||||
return fmt.Errorf("index download failed, artifact not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func upsertHelmRepository(ctx context.Context, kubeClient client.Client, helmRepository sourcev1.HelmRepository) error {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: helmRepository.GetNamespace(),
|
||||
Name: helmRepository.GetName(),
|
||||
}
|
||||
|
||||
var existing sourcev1.HelmRepository
|
||||
err := kubeClient.Get(ctx, namespacedName, &existing)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
if err := kubeClient.Create(ctx, &helmRepository); err != nil {
|
||||
return err
|
||||
} else {
|
||||
logger.Successf("source created")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
existing.Spec = helmRepository.Spec
|
||||
if err := kubeClient.Update(ctx, &existing); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("source updated")
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportHelmRepository(source sourcev1.HelmRepository) error {
|
||||
gvk := sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)
|
||||
export := sourcev1.HelmRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: source.Name,
|
||||
Namespace: source.Namespace,
|
||||
},
|
||||
Spec: source.Spec,
|
||||
}
|
||||
|
||||
data, err := yaml.Marshal(export)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("---")
|
||||
fmt.Println(string(data))
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var deleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete commands",
|
||||
Short: "Delete sources and resources",
|
||||
Long: "The delete sub-commands delete sources and resources.",
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
91
cmd/tk/delete_helmrelease.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
)
|
||||
|
||||
var deleteHelmReleaseCmd = &cobra.Command{
|
||||
Use: "helmrelease [name]",
|
||||
Aliases: []string{"hr"},
|
||||
Short: "Delete a HelmRelease resource",
|
||||
Long: "The delete helmrelease command removes the given HelmRelease from the cluster.",
|
||||
Example: ` # Delete a Helm release and the Kubernetes resources created by it
|
||||
tk delete hr podinfo
|
||||
`,
|
||||
RunE: deleteHelmReleaseCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
deleteCmd.AddCommand(deleteHelmReleaseCmd)
|
||||
}
|
||||
|
||||
func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("release name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
if !helmRelease.Spec.Suspend {
|
||||
logger.Waitingf("This action will remove the Kubernetes objects previously applied by the %s Helm release!", name)
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this Helm release",
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
return fmt.Errorf("aborting")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting release %s in %s namespace", name, namespace)
|
||||
err = kubeClient.Delete(ctx, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("release deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -13,8 +29,12 @@ import (
|
||||
var deleteKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Delete kustomization",
|
||||
RunE: deleteKsCmdRun,
|
||||
Short: "Delete a Kustomization resource",
|
||||
Long: "The delete kustomization command deletes the given Kustomization from the cluster.",
|
||||
Example: ` # Delete a kustomization and the Kubernetes resources created by it
|
||||
tk delete kustomization podinfo
|
||||
`,
|
||||
RunE: deleteKsCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -48,7 +68,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if !deleteSilent {
|
||||
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{
|
||||
Label: "Are you sure you want to delete this kustomization",
|
||||
@@ -59,12 +79,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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("kustomization deleted")
|
||||
logger.Successf("kustomization deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var deleteSourceCmd = &cobra.Command{
|
||||
Use: "source",
|
||||
Short: "Delete sources commands",
|
||||
Short: "Delete sources",
|
||||
Long: "The delete source sub-commands delete sources.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -12,8 +28,12 @@ import (
|
||||
|
||||
var deleteSourceGitCmd = &cobra.Command{
|
||||
Use: "git [name]",
|
||||
Short: "Delete git source",
|
||||
RunE: deleteSourceGitCmdRun,
|
||||
Short: "Delete a GitRepository source",
|
||||
Long: "The delete source git command deletes the given GitRepository from the cluster.",
|
||||
Example: ` # Delete a Git repository
|
||||
tk delete source git podinfo
|
||||
`,
|
||||
RunE: deleteSourceGitCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -55,12 +75,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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("source deleted")
|
||||
logger.Successf("source deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
86
cmd/tk/delete_source_helm.go
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
var deleteSourceHelmCmd = &cobra.Command{
|
||||
Use: "helm [name]",
|
||||
Short: "Delete a HelmRepository source",
|
||||
Long: "The delete source helm command deletes the given HelmRepository from the cluster.",
|
||||
Example: ` # Delete a Helm repository
|
||||
tk delete source helm podinfo
|
||||
`,
|
||||
RunE: deleteSourceHelmCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
deleteSourceCmd.AddCommand(deleteSourceHelmCmd)
|
||||
}
|
||||
|
||||
func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var helmRepository sourcev1.HelmRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !deleteSilent {
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Are you sure you want to delete this source",
|
||||
IsConfirm: true,
|
||||
}
|
||||
if _, err := prompt.Run(); err != nil {
|
||||
return fmt.Errorf("aborting")
|
||||
}
|
||||
}
|
||||
|
||||
logger.Actionf("deleting source %s in %s namespace", name, namespace)
|
||||
err = kubeClient.Delete(ctx, &helmRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source deleted")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var exportCmd = &cobra.Command{
|
||||
Use: "export",
|
||||
Short: "Export commands",
|
||||
Short: "Export resources in YAML format",
|
||||
Long: "The export sub-commands export resources in YAML format.",
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
118
cmd/tk/export_helmrelease.go
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
)
|
||||
|
||||
var exportHelmReleaseCmd = &cobra.Command{
|
||||
Use: "helmrelease [name]",
|
||||
Aliases: []string{"hr"},
|
||||
Short: "Export HelmRelease resources in YAML format",
|
||||
Long: "The export helmrelease command exports one or all HelmRelease resources in YAML format.",
|
||||
Example: ` # Export all HelmRelease resources
|
||||
tk export helmrelease --all > kustomizations.yaml
|
||||
|
||||
# Export a HelmRelease
|
||||
tk export hr my-app > app-release.yaml
|
||||
`,
|
||||
RunE: exportHelmReleaseCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
exportCmd.AddCommand(exportHelmReleaseCmd)
|
||||
}
|
||||
|
||||
func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
var list helmv2.HelmReleaseList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no kustomizations found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, helmRelease := range list.Items {
|
||||
if err := exportHelmRelease(helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return exportHelmRelease(helmRelease)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportHelmRelease(helmRelease helmv2.HelmRelease) error {
|
||||
gvk := helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)
|
||||
export := helmv2.HelmRelease{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: helmRelease.Name,
|
||||
Namespace: helmRelease.Namespace,
|
||||
},
|
||||
Spec: helmRelease.Spec,
|
||||
}
|
||||
|
||||
data, err := yaml.Marshal(export)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("---")
|
||||
fmt.Println(string(data))
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -15,12 +31,13 @@ import (
|
||||
var exportKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Export kustomization in YAML format",
|
||||
Example: ` # Export all kustomizations
|
||||
export kustomization --all > kustomizations.yaml
|
||||
Short: "Export Kustomization resources in YAML format",
|
||||
Long: "The export kustomization command exports one or all Kustomization resources in YAML format.",
|
||||
Example: ` # Export all Kustomization resources
|
||||
tk export kustomization --all > kustomizations.yaml
|
||||
|
||||
# Export a kustomization
|
||||
export kustomization my-app > kustomization.yaml
|
||||
# Export a Kustomization
|
||||
tk export kustomization my-app > kustomization.yaml
|
||||
`,
|
||||
RunE: exportKsCmdRun,
|
||||
}
|
||||
@@ -50,7 +67,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logFailure("no kustomizations found in %s namespace", namespace)
|
||||
logger.Failuref("no kustomizations found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var exportSourceCmd = &cobra.Command{
|
||||
Use: "source",
|
||||
Short: "Export source commands",
|
||||
Short: "Export sources",
|
||||
Long: "The export source sub-commands export sources in YAML format.",
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -15,12 +31,13 @@ import (
|
||||
|
||||
var exportSourceGitCmd = &cobra.Command{
|
||||
Use: "git [name]",
|
||||
Short: "Export git sources in YAML format",
|
||||
Example: ` # Export all git sources
|
||||
export source git --all > sources.yaml
|
||||
Short: "Export GitRepository sources in YAML format",
|
||||
Long: "The export source git command exports on or all GitRepository sources in YAML format.",
|
||||
Example: ` # Export all GitRepository sources
|
||||
tk export source git --all > sources.yaml
|
||||
|
||||
# Export a git source including the SSH keys or basic auth credentials
|
||||
export source git my-private-repo --with-credentials > source.yaml
|
||||
# Export a GitRepository source including the SSH key pair or basic auth credentials
|
||||
tk export source git my-private-repo --with-credentials > source.yaml
|
||||
`,
|
||||
RunE: exportSourceGitCmdRun,
|
||||
}
|
||||
@@ -31,7 +48,7 @@ func init() {
|
||||
|
||||
func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
return fmt.Errorf("kustomization name is required")
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
@@ -50,7 +67,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logFailure("no source found in %s namespace", namespace)
|
||||
logger.Failuref("no source found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -86,7 +103,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
func exportGit(source sourcev1.GitRepository) error {
|
||||
gvk := sourcev1.GroupVersion.WithKind("GitRepository")
|
||||
gvk := sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind)
|
||||
export := sourcev1.GitRepository{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: gvk.Kind,
|
||||
@@ -109,16 +126,16 @@ func exportGit(source sourcev1.GitRepository) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportGitCredentials(ctx context.Context, kubeClinet client.Client, source sourcev1.GitRepository) error {
|
||||
func exportGitCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.GitRepository) error {
|
||||
if source.Spec.SecretRef != nil {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: source.Namespace,
|
||||
Name: source.Spec.SecretRef.Name,
|
||||
}
|
||||
var cred corev1.Secret
|
||||
err := kubeClinet.Get(ctx, namespacedName, &cred)
|
||||
err := kubeClient.Get(ctx, namespacedName, &cred)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get secret failed: %w", err)
|
||||
return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err)
|
||||
}
|
||||
|
||||
exported := corev1.Secret{
|
||||
|
||||
139
cmd/tk/export_source_helm.go
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
var exportSourceHelmCmd = &cobra.Command{
|
||||
Use: "helm [name]",
|
||||
Short: "Export HelmRepository sources in YAML format",
|
||||
Long: "The export source git command exports on or all HelmRepository sources in YAML format.",
|
||||
Example: ` # Export all HelmRepository sources
|
||||
tk export source helm --all > sources.yaml
|
||||
|
||||
# Export a HelmRepository source including the basic auth credentials
|
||||
tk export source helm my-private-repo --with-credentials > source.yaml
|
||||
`,
|
||||
RunE: exportSourceHelmCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
exportSourceCmd.AddCommand(exportSourceHelmCmd)
|
||||
}
|
||||
|
||||
func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if !exportAll && len(args) < 1 {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exportAll {
|
||||
var list sourcev1.HelmRepositoryList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no source found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, repository := range list.Items {
|
||||
if err := exportHelmRepository(repository); err != nil {
|
||||
return err
|
||||
}
|
||||
if exportSourceWithCred {
|
||||
if err := exportHelmCredentials(ctx, kubeClient, repository); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
name := args[0]
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var repository sourcev1.HelmRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := exportHelmRepository(repository); err != nil {
|
||||
return err
|
||||
}
|
||||
if exportSourceWithCred {
|
||||
return exportHelmCredentials(ctx, kubeClient, repository)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportHelmCredentials(ctx context.Context, kubeClient client.Client, source sourcev1.HelmRepository) error {
|
||||
if source.Spec.SecretRef != nil {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: source.Namespace,
|
||||
Name: source.Spec.SecretRef.Name,
|
||||
}
|
||||
var cred corev1.Secret
|
||||
err := kubeClient.Get(ctx, namespacedName, &cred)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve secret %s, error: %w", namespacedName.Name, err)
|
||||
}
|
||||
|
||||
exported := corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespacedName.Name,
|
||||
Namespace: namespacedName.Namespace,
|
||||
},
|
||||
Data: cred.Data,
|
||||
Type: cred.Type,
|
||||
}
|
||||
|
||||
data, err := yaml.Marshal(exported)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("---")
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,25 @@
|
||||
/*
|
||||
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 (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -108,5 +125,6 @@ func ecdsaCurves() []string {
|
||||
for k := range supportedECDSACurves {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var getCmd = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: "Get commands",
|
||||
Short: "Get sources and resources",
|
||||
Long: "The get sub-commands print the statuses of sources and resources.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
90
cmd/tk/get_helmrelease.go
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
)
|
||||
|
||||
var getHelmReleaseCmd = &cobra.Command{
|
||||
Use: "helmreleases",
|
||||
Aliases: []string{"hr"},
|
||||
Short: "Get HelmRelease statuses",
|
||||
Long: "The get helmreleases command prints the statuses of the resources.",
|
||||
Example: ` # List all Helm releases and their status
|
||||
tk get helmreleases
|
||||
`,
|
||||
RunE: getHelmReleaseCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getCmd.AddCommand(getHelmReleaseCmd)
|
||||
}
|
||||
|
||||
func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var list helmv2.HelmReleaseList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no releases found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, helmRelease := range list.Items {
|
||||
if helmRelease.Spec.Suspend {
|
||||
logger.Successf("%s is suspended", helmRelease.GetName())
|
||||
continue
|
||||
}
|
||||
isInitialized := false
|
||||
for _, condition := range helmRelease.Status.Conditions {
|
||||
if condition.Type == helmv2.ReadyCondition {
|
||||
if condition.Status != corev1.ConditionFalse {
|
||||
if helmRelease.Status.LastAppliedRevision != "" {
|
||||
logger.Successf("%s last applied revision %s", helmRelease.GetName(), helmRelease.Status.LastAppliedRevision)
|
||||
} else {
|
||||
logger.Successf("%s reconciling", helmRelease.GetName())
|
||||
}
|
||||
} else {
|
||||
logger.Failuref("%s %s", helmRelease.GetName(), condition.Message)
|
||||
}
|
||||
isInitialized = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isInitialized {
|
||||
logger.Failuref("%s is not ready", helmRelease.GetName())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -12,9 +28,11 @@ import (
|
||||
var getKsCmd = &cobra.Command{
|
||||
Use: "kustomizations",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Get kustomizations status",
|
||||
Long: `
|
||||
The get kustomizations command prints the status of the resources.`,
|
||||
Short: "Get Kustomization statuses",
|
||||
Long: "The get kustomizations command prints the statuses of the resources.",
|
||||
Example: ` # List all kustomizations and their status
|
||||
tk get kustomizations
|
||||
`,
|
||||
RunE: getKsCmdRun,
|
||||
}
|
||||
|
||||
@@ -38,29 +56,33 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logFailure("no kustomizations found in %s namespace", namespace)
|
||||
logger.Failuref("no kustomizations found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, kustomization := range list.Items {
|
||||
if kustomization.Spec.Suspend {
|
||||
logSuccess("%s is suspended", kustomization.GetName())
|
||||
logger.Successf("%s is suspended", kustomization.GetName())
|
||||
continue
|
||||
}
|
||||
isInitialized := false
|
||||
for _, condition := range kustomization.Status.Conditions {
|
||||
if condition.Type == kustomizev1.ReadyCondition {
|
||||
if condition.Status != corev1.ConditionFalse {
|
||||
logSuccess("%s last applied revision %s", kustomization.GetName(), kustomization.Status.LastAppliedRevision)
|
||||
if kustomization.Status.LastAppliedRevision != "" {
|
||||
logger.Successf("%s last applied revision %s", kustomization.GetName(), kustomization.Status.LastAppliedRevision)
|
||||
} else {
|
||||
logger.Successf("%s reconciling", kustomization.GetName())
|
||||
}
|
||||
} else {
|
||||
logFailure("%s %s", kustomization.GetName(), condition.Message)
|
||||
logger.Failuref("%s %s", kustomization.GetName(), condition.Message)
|
||||
}
|
||||
isInitialized = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isInitialized {
|
||||
logFailure("%s is not ready", kustomization.GetName())
|
||||
logger.Failuref("%s is not ready", kustomization.GetName())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var getSourceCmd = &cobra.Command{
|
||||
Use: "sources",
|
||||
Short: "Get sources commands",
|
||||
Short: "Get source statuses",
|
||||
Long: "The get source sub-commands print the statuses of the sources.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -11,9 +27,11 @@ import (
|
||||
|
||||
var getSourceGitCmd = &cobra.Command{
|
||||
Use: "git",
|
||||
Short: "Get git sources status",
|
||||
Long: `
|
||||
The get sources command prints the status of the git resources.`,
|
||||
Short: "Get GitRepository source statuses",
|
||||
Long: "The get sources git command prints the status of the GitRepository sources.",
|
||||
Example: ` # List all Git repositories and their status
|
||||
tk get sources git
|
||||
`,
|
||||
RunE: getSourceGitCmdRun,
|
||||
}
|
||||
|
||||
@@ -37,7 +55,7 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logFailure("no sources found in %s namespace", namespace)
|
||||
logger.Failuref("no sources found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -46,16 +64,16 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||
for _, condition := range source.Status.Conditions {
|
||||
if condition.Type == sourcev1.ReadyCondition {
|
||||
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 {
|
||||
logFailure("%s %s", source.GetName(), condition.Message)
|
||||
logger.Failuref("%s %s", source.GetName(), condition.Message)
|
||||
}
|
||||
isInitialized = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isInitialized {
|
||||
logFailure("%s is not ready", source.GetName())
|
||||
logger.Failuref("%s is not ready", source.GetName())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
80
cmd/tk/get_source_helm.go
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
var getSourceHelmCmd = &cobra.Command{
|
||||
Use: "helm",
|
||||
Short: "Get HelmRepository source statuses",
|
||||
Long: "The get sources helm command prints the status of the HelmRepository sources.",
|
||||
Example: ` # List all Helm repositories and their status
|
||||
tk get sources helm
|
||||
`,
|
||||
RunE: getSourceHelmCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
getSourceCmd.AddCommand(getSourceHelmCmd)
|
||||
}
|
||||
|
||||
func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var list sourcev1.HelmRepositoryList
|
||||
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list.Items) == 0 {
|
||||
logger.Failuref("no sources found in %s namespace", namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, source := range list.Items {
|
||||
isInitialized := false
|
||||
for _, condition := range source.Status.Conditions {
|
||||
if condition.Type == sourcev1.ReadyCondition {
|
||||
if condition.Status != corev1.ConditionFalse {
|
||||
logger.Successf("%s last fetched revision: %s", source.GetName(), source.Status.Artifact.Revision)
|
||||
} else {
|
||||
logger.Failuref("%s %s", source.GetName(), condition.Message)
|
||||
}
|
||||
isInitialized = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isInitialized {
|
||||
logger.Failuref("%s is not ready", source.GetName())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,13 +1,32 @@
|
||||
/*
|
||||
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/fluxcd/pkg/untar"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/api/filesys"
|
||||
@@ -17,32 +36,40 @@ import (
|
||||
var installCmd = &cobra.Command{
|
||||
Use: "install",
|
||||
Short: "Install the toolkit components",
|
||||
Long: `
|
||||
The install command deploys the toolkit components in the specified namespace.
|
||||
Long: `The install command deploys the toolkit components in the specified namespace.
|
||||
If a previous version is installed, then an in-place upgrade will be performed.`,
|
||||
Example: ` # Install the latest version in the gitops-systems namespace
|
||||
install --version=master --namespace=gitops-systems
|
||||
tk install --version=latest --namespace=gitops-systems
|
||||
|
||||
# Dry-run install for a specific version and a series of components
|
||||
install --dry-run --version=0.0.1 --components="source-controller,kustomize-controller"
|
||||
tk install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
|
||||
|
||||
# Dry-run install with manifests preview
|
||||
install --dry-run --verbose
|
||||
tk install --dry-run --verbose
|
||||
|
||||
# Write install manifests to file
|
||||
tk install --export > gitops-system.yaml
|
||||
`,
|
||||
RunE: installCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
installExport bool
|
||||
installDryRun bool
|
||||
installManifestsPath string
|
||||
installVersion string
|
||||
installComponents []string
|
||||
)
|
||||
|
||||
func init() {
|
||||
installCmd.Flags().BoolVar(&installExport, "export", false,
|
||||
"write the install manifests to stdout and exit")
|
||||
installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false,
|
||||
"only print the object that would be applied")
|
||||
installCmd.Flags().StringVarP(&installVersion, "version", "v", "master",
|
||||
"toolkit tag or branch")
|
||||
installCmd.Flags().StringVarP(&installVersion, "version", "v", defaultVersion,
|
||||
"toolkit version")
|
||||
installCmd.Flags().StringSliceVar(&installComponents, "components", defaultComponents,
|
||||
"list of components, accepts comma-separated values")
|
||||
installCmd.Flags().StringVarP(&installManifestsPath, "manifests", "", "",
|
||||
"path to the manifest directory, dev only")
|
||||
rootCmd.AddCommand(installCmd)
|
||||
@@ -66,9 +93,11 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
logGenerate("generating manifests")
|
||||
if !installExport {
|
||||
logger.Generatef("generating manifests")
|
||||
}
|
||||
if kustomizePath == "" {
|
||||
err = genInstallManifests(installVersion, namespace, components, tmpDir)
|
||||
err = genInstallManifests(installVersion, namespace, installComponents, tmpDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("install failed: %w", err)
|
||||
}
|
||||
@@ -86,11 +115,17 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
} else {
|
||||
if verbose {
|
||||
fmt.Print(yaml)
|
||||
} else if installExport {
|
||||
fmt.Println("---")
|
||||
fmt.Println("# GitOps Toolkit revision", installVersion, time.Now().Format(time.RFC3339))
|
||||
fmt.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
|
||||
if verbose {
|
||||
applyOutput = ModeOS
|
||||
@@ -106,24 +141,24 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if installDryRun {
|
||||
logSuccess("install dry-run finished")
|
||||
logger.Successf("install dry-run finished")
|
||||
return nil
|
||||
} else {
|
||||
logSuccess("install completed")
|
||||
logger.Successf("install completed")
|
||||
}
|
||||
|
||||
logWaiting("verifying installation")
|
||||
for _, deployment := range components {
|
||||
logger.Waitingf("verifying installation")
|
||||
for _, deployment := range installComponents {
|
||||
command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
|
||||
namespace, deployment, timeout.String())
|
||||
if _, err := utils.execCommand(ctx, applyOutput, command); err != nil {
|
||||
return fmt.Errorf("install failed")
|
||||
} else {
|
||||
logSuccess("%s ready", deployment)
|
||||
logger.Successf("%s ready", deployment)
|
||||
}
|
||||
}
|
||||
|
||||
logSuccess("install finished")
|
||||
logger.Successf("install finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -156,10 +191,10 @@ transformers:
|
||||
- labels.yaml
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- policies.yaml
|
||||
- roles
|
||||
- github.com/fluxcd/toolkit/manifests/policies?ref={{$version}}
|
||||
{{- range .Components }}
|
||||
- github.com/fluxcd/toolkit/manifests/bases/{{.}}?ref={{$version}}
|
||||
- {{.}}.yaml
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
@@ -167,10 +202,44 @@ var kustomizationRolesTmpl = `---
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- github.com/fluxcd/toolkit/manifests/rbac?ref={{.Version}}
|
||||
- rbac.yaml
|
||||
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 {
|
||||
model := struct {
|
||||
Version string
|
||||
@@ -182,6 +251,10 @@ func genInstallManifests(version string, namespace string, components []string,
|
||||
Components: components,
|
||||
}
|
||||
|
||||
if err := downloadManifests(version, tmpDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.execTemplate(model, namespaceTmpl, path.Join(tmpDir, "namespace.yaml")); err != nil {
|
||||
return fmt.Errorf("generate namespace failed: %w", err)
|
||||
}
|
||||
@@ -202,6 +275,10 @@ func genInstallManifests(version string, namespace string, components []string,
|
||||
return fmt.Errorf("generate roles failed: %w", err)
|
||||
}
|
||||
|
||||
if err := utils.copyFile(filepath.Join(tmpDir, "rbac.yaml"), filepath.Join(tmpDir, "roles/rbac.yaml")); err != nil {
|
||||
return fmt.Errorf("generate rbac failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,41 @@
|
||||
/*
|
||||
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 "fmt"
|
||||
|
||||
func logAction(format string, a ...interface{}) {
|
||||
type printLogger struct{}
|
||||
|
||||
func (l printLogger) Actionf(format string, a ...interface{}) {
|
||||
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...))
|
||||
}
|
||||
|
||||
func logWaiting(format string, a ...interface{}) {
|
||||
func (l printLogger) Waitingf(format string, a ...interface{}) {
|
||||
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...))
|
||||
}
|
||||
|
||||
func logFailure(format string, a ...interface{}) {
|
||||
func (l printLogger) Failuref(format string, a ...interface{}) {
|
||||
fmt.Println(`✗`, fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -9,6 +25,8 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/doc"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
|
||||
tklog "github.com/fluxcd/toolkit/pkg/log"
|
||||
)
|
||||
|
||||
var VERSION = "0.0.0-dev.0"
|
||||
@@ -32,42 +50,42 @@ var rootCmd = &cobra.Command{
|
||||
--branch=master \
|
||||
--interval=3m
|
||||
|
||||
# List git sources and their status
|
||||
# List GitRepository sources and their status
|
||||
tk get sources git
|
||||
|
||||
# Trigger a git sync
|
||||
# Trigger a GitRepository source sync
|
||||
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
|
||||
|
||||
# Create a kustomization for deploying a series of microservices
|
||||
# Create a Kustomization for deploying a series of microservices
|
||||
tk create kustomization webapp-dev \
|
||||
--source=webapp-latest \
|
||||
--path="./deploy/webapp/" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--health-check="Deployment/backend.webapp" \
|
||||
--health-check="Deployment/frontend.webapp" \
|
||||
--health-check-timeout=2m
|
||||
|
||||
# Trigger a git sync and apply changes if any
|
||||
tk sync kustomization webapp-dev --with-source
|
||||
# Trigger a git sync of the Kustomization's source and apply changes
|
||||
tk reconcile kustomization webapp-dev --with-source
|
||||
|
||||
# Suspend a kustomization reconciliation
|
||||
# Suspend a Kustomization reconciliation
|
||||
tk suspend kustomization webapp-dev
|
||||
|
||||
# Export kustomizations in YAML format
|
||||
# Export Kustomizations in YAML format
|
||||
tk export kustomization --all > kustomizations.yaml
|
||||
|
||||
# Resume a kustomization reconciliation
|
||||
# Resume a Kustomization reconciliation
|
||||
tk resume kustomization webapp-dev
|
||||
|
||||
# Delete a kustomization
|
||||
# Delete a Kustomization
|
||||
tk delete kustomization webapp-dev
|
||||
|
||||
# Delete a git source
|
||||
# Delete a GitRepository source
|
||||
tk delete source git webapp-latest
|
||||
|
||||
# Uninstall the toolkit and delete CRDs
|
||||
@@ -80,21 +98,24 @@ var (
|
||||
namespace string
|
||||
timeout time.Duration
|
||||
verbose bool
|
||||
components []string
|
||||
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() {
|
||||
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "", "gitops-system",
|
||||
rootCmd.PersistentFlags().StringVar(&namespace, "namespace", defaultNamespace,
|
||||
"the namespace scope for this operation")
|
||||
rootCmd.PersistentFlags().DurationVarP(&timeout, "timeout", "", 5*time.Minute,
|
||||
"timeout for this operation")
|
||||
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false,
|
||||
"print generated objects")
|
||||
rootCmd.PersistentFlags().StringSliceVar(&components, "components",
|
||||
[]string{"source-controller", "kustomize-controller"},
|
||||
"list of components, accepts comma-separated values")
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -102,7 +123,7 @@ func main() {
|
||||
generateDocs()
|
||||
kubeconfigFlag()
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
logFailure("%v", err)
|
||||
logger.Failuref("%v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -115,6 +136,10 @@ func kubeconfigFlag() {
|
||||
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", "",
|
||||
"absolute path to the kubeconfig file")
|
||||
}
|
||||
|
||||
if len(os.Getenv("KUBECONFIG")) > 0 {
|
||||
kubeconfig = os.Getenv("KUBECONFIG")
|
||||
}
|
||||
}
|
||||
|
||||
func generateDocs() {
|
||||
@@ -122,6 +147,7 @@ func generateDocs() {
|
||||
if len(args) > 0 && args[0] == "docgen" {
|
||||
rootCmd.PersistentFlags().StringVarP(&kubeconfig, "kubeconfig", "", "~/.kube/config",
|
||||
"path to the kubeconfig file")
|
||||
rootCmd.DisableAutoGenTag = true
|
||||
err := doc.GenMarkdownTree(rootCmd, "./docs/cmd")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
31
cmd/tk/reconcile.go
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var reconcileCmd = &cobra.Command{
|
||||
Use: "reconcile",
|
||||
Short: "Reconcile sources and resources",
|
||||
Long: "The reconcile sub-commands trigger a reconciliation of sources and resources.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(reconcileCmd)
|
||||
}
|
||||
148
cmd/tk/reconcile_helmrelease.go
Normal 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
|
||||
}
|
||||
}
|
||||
119
cmd/tk/reconcile_kustomization.go
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
var reconcileKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Reconcile a Kustomization resource",
|
||||
Long: `
|
||||
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
|
||||
tk reconcile kustomization podinfo
|
||||
|
||||
# Trigger a sync of the Kustomization's source and apply changes
|
||||
tk reconcile kustomization podinfo --with-source
|
||||
`,
|
||||
RunE: reconcileKsCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
syncKsWithSource bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
reconcileKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "reconcile kustomization source")
|
||||
|
||||
reconcileCmd.AddCommand(reconcileKsCmd)
|
||||
}
|
||||
|
||||
func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("kustomization name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var kustomization kustomizev1.Kustomization
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if syncKsWithSource {
|
||||
err := syncSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
logger.Actionf("annotating kustomization %s in %s namespace", name, namespace)
|
||||
if kustomization.Annotations == nil {
|
||||
kustomization.Annotations = map[string]string{
|
||||
kustomizev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
kustomization.Annotations[kustomizev1.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("kustomization annotated")
|
||||
}
|
||||
|
||||
logger.Waitingf("waiting for kustomization reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("kustomization reconciliation completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if kustomization.Status.LastAppliedRevision != "" {
|
||||
logger.Successf("reconciled revision %s", kustomization.Status.LastAppliedRevision)
|
||||
} else {
|
||||
return fmt.Errorf("kustomization sync failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
31
cmd/tk/reconcile_source.go
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var reconcileSourceCmd = &cobra.Command{
|
||||
Use: "source",
|
||||
Short: "Reconcile sources",
|
||||
Long: "The reconcile source sub-commands trigger a reconciliation of sources.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileCmd.AddCommand(reconcileSourceCmd)
|
||||
}
|
||||
100
cmd/tk/reconcile_source_git.go
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"time"
|
||||
)
|
||||
|
||||
var reconcileSourceGitCmd = &cobra.Command{
|
||||
Use: "git [name]",
|
||||
Short: "Reconcile a GitRepository source",
|
||||
Long: `The reconcile source command triggers a reconciliation of a GitRepository resource and waits for it to finish.`,
|
||||
Example: ` # Trigger a git pull for an existing source
|
||||
tk reconcile source git podinfo
|
||||
`,
|
||||
RunE: syncSourceGitCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileSourceCmd.AddCommand(reconcileSourceGitCmd)
|
||||
}
|
||||
|
||||
func syncSourceGitCmdRun(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 gitRepository sourcev1.GitRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gitRepository.Annotations == nil {
|
||||
gitRepository.Annotations = map[string]string{
|
||||
sourcev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
gitRepository.Annotations[sourcev1.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &gitRepository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source annotated")
|
||||
|
||||
logger.Waitingf("waiting for reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("git reconciliation completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gitRepository.Status.Artifact != nil {
|
||||
logger.Successf("fetched revision %s", gitRepository.Status.Artifact.Revision)
|
||||
} else {
|
||||
return fmt.Errorf("git reconciliation failed, artifact not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
130
cmd/tk/reconcile_source_helm.go
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
var reconcileSourceHelmCmd = &cobra.Command{
|
||||
Use: "helm [name]",
|
||||
Short: "Reconcile a HelmRepository source",
|
||||
Long: `The reconcile source command triggers a reconciliation of a HelmRepository resource and waits for it to finish.`,
|
||||
Example: ` # Trigger a reconciliation for an existing source
|
||||
tk reconcile source helm podinfo
|
||||
`,
|
||||
RunE: syncSourceHelmCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
reconcileSourceCmd.AddCommand(reconcileSourceHelmCmd)
|
||||
}
|
||||
|
||||
func syncSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("source name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
logger.Actionf("annotating source %s in %s namespace", name, namespace)
|
||||
var helmRepository sourcev1.HelmRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if helmRepository.Annotations == nil {
|
||||
helmRepository.Annotations = map[string]string{
|
||||
sourcev1.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||
}
|
||||
} else {
|
||||
helmRepository.Annotations[sourcev1.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &helmRepository); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("source annotated")
|
||||
|
||||
logger.Waitingf("waiting for reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("helm reconciliation completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if helmRepository.Status.Artifact != nil {
|
||||
logger.Successf("fetched revision %s", helmRepository.Status.Artifact.Revision)
|
||||
} else {
|
||||
return fmt.Errorf("helm reconciliation failed, artifact not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
var helmRepository sourcev1.HelmRepository
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err := kubeClient.Get(ctx, namespacedName, &helmRepository)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, condition := range helmRepository.Status.Conditions {
|
||||
if condition.Type == sourcev1.ReadyCondition {
|
||||
if condition.Status == corev1.ConditionTrue {
|
||||
return true, nil
|
||||
} else if condition.Status == corev1.ConditionFalse {
|
||||
return false, fmt.Errorf(condition.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var resumeCmd = &cobra.Command{
|
||||
Use: "resume",
|
||||
Short: "Resume commands",
|
||||
Short: "Resume suspended resources",
|
||||
Long: "The resume sub-commands resume a suspended resource.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
129
cmd/tk/resume_helmrelease.go
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
)
|
||||
|
||||
var resumeHrCmd = &cobra.Command{
|
||||
Use: "helmrelease [name]",
|
||||
Aliases: []string{"hr"},
|
||||
Short: "Resume a suspended HelmRelease",
|
||||
Long: `The resume command marks a previously suspended HelmRelease resource for reconciliation and waits for it to
|
||||
finish the apply.`,
|
||||
Example: ` # Resume reconciliation for an existing Helm release
|
||||
tk resume hr podinfo
|
||||
`,
|
||||
RunE: resumeHrCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
resumeCmd.AddCommand(resumeHrCmd)
|
||||
}
|
||||
|
||||
func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("HelmRelease name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("resuming HelmRelease %s in %s namespace", name, namespace)
|
||||
helmRelease.Spec.Suspend = false
|
||||
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease resumed")
|
||||
|
||||
logger.Waitingf("waiting for HelmRelease reconciliation")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isHelmReleaseResumed(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Successf("HelmRelease reconciliation completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if helmRelease.Status.LastAppliedRevision != "" {
|
||||
logger.Successf("applied revision %s", helmRelease.Status.LastAppliedRevision)
|
||||
} else {
|
||||
return fmt.Errorf("HelmRelease reconciliation failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client, name, namespace string) wait.ConditionFunc {
|
||||
return func() (bool, error) {
|
||||
var helmRelease helmv2.HelmRelease
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err := kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, condition := range helmRelease.Status.Conditions {
|
||||
if condition.Type == helmv2.ReadyCondition {
|
||||
if condition.Status == corev1.ConditionTrue {
|
||||
return true, nil
|
||||
} else if condition.Status == corev1.ConditionFalse {
|
||||
if condition.Reason == helmv2.SuspendedReason {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, fmt.Errorf(condition.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -16,9 +32,13 @@ import (
|
||||
var resumeKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Resume kustomization",
|
||||
Long: "The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to finish the apply.",
|
||||
RunE: resumeKsCmdRun,
|
||||
Short: "Resume a suspended Kustomization",
|
||||
Long: `The resume command marks a previously suspended Kustomization resource for reconciliation and waits for it to
|
||||
finish the apply.`,
|
||||
Example: ` # Resume reconciliation for an existing Kustomization
|
||||
tk resume ks podinfo
|
||||
`,
|
||||
RunE: resumeKsCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -49,20 +69,20 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
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
|
||||
if err := kubeClient.Update(ctx, &kustomization); err != nil {
|
||||
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,
|
||||
isKustomizationResumed(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("kustomization sync completed")
|
||||
logger.Successf("kustomization sync completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
@@ -70,7 +90,7 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if kustomization.Status.LastAppliedRevision != "" {
|
||||
logSuccess("applied revision %s", kustomization.Status.LastAppliedRevision)
|
||||
logger.Successf("applied revision %s", kustomization.Status.LastAppliedRevision)
|
||||
} else {
|
||||
return fmt.Errorf("kustomization sync failed")
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -6,7 +22,8 @@ import (
|
||||
|
||||
var suspendCmd = &cobra.Command{
|
||||
Use: "suspend",
|
||||
Short: "Suspend commands",
|
||||
Short: "Suspend resources",
|
||||
Long: "The suspend sub-commands suspend the reconciliation of a resource.",
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
76
cmd/tk/suspend_helmrelease.go
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright 2020 The Flux CD contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
)
|
||||
|
||||
var suspendHrCmd = &cobra.Command{
|
||||
Use: "helmrelease [name]",
|
||||
Aliases: []string{"hr"},
|
||||
Short: "Suspend reconciliation of HelmRelease",
|
||||
Long: "The suspend command disables the reconciliation of a HelmRelease resource.",
|
||||
Example: ` # Suspend reconciliation for an existing Helm release
|
||||
tk suspend hr podinfo
|
||||
`,
|
||||
RunE: suspendHrCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
suspendCmd.AddCommand(suspendHrCmd)
|
||||
}
|
||||
|
||||
func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("HelmRelease name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
var helmRelease helmv2.HelmRelease
|
||||
err = kubeClient.Get(ctx, namespacedName, &helmRelease)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Actionf("suspending HelmRelease %s in %s namespace", name, namespace)
|
||||
helmRelease.Spec.Suspend = true
|
||||
if err := kubeClient.Update(ctx, &helmRelease); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Successf("HelmRelease suspended")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -11,9 +27,12 @@ import (
|
||||
var suspendKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Suspend kustomization",
|
||||
Short: "Suspend reconciliation of Kustomization",
|
||||
Long: "The suspend command disables the reconciliation of a Kustomization resource.",
|
||||
RunE: suspendKsCmdRun,
|
||||
Example: ` # Suspend reconciliation for an existing Kustomization
|
||||
tk suspend ks podinfo
|
||||
`,
|
||||
RunE: suspendKsCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -44,12 +63,12 @@ func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
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
|
||||
if err := kubeClient.Update(ctx, &kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("kustomization suspended")
|
||||
logger.Successf("kustomization suspended")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var syncCmd = &cobra.Command{
|
||||
Use: "sync",
|
||||
Short: "Synchronize commands",
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(syncCmd)
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
var syncKsCmd = &cobra.Command{
|
||||
Use: "kustomization [name]",
|
||||
Aliases: []string{"ks"},
|
||||
Short: "Synchronize kustomization",
|
||||
Long: `
|
||||
The sync kustomization command triggers a reconciliation of a Kustomization resource and waits for it to finish.`,
|
||||
Example: ` # Trigger a kustomization apply outside of the reconciliation interval
|
||||
sync kustomization podinfo
|
||||
|
||||
# Trigger a git sync of the kustomization source and apply changes
|
||||
sync kustomization podinfo --with-source
|
||||
`,
|
||||
RunE: syncKsCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
syncKsWithSource bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
syncKsCmd.Flags().BoolVar(&syncKsWithSource, "with-source", false, "synchronize kustomization source")
|
||||
|
||||
syncCmd.AddCommand(syncKsCmd)
|
||||
}
|
||||
|
||||
func syncKsCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("kustomization name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.kubeClient(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
var kustomization kustomizev1.Kustomization
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if syncKsWithSource {
|
||||
err := syncSourceGitCmdRun(nil, []string{kustomization.Spec.SourceRef.Name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
logAction("annotating kustomization %s in %s namespace", name, namespace)
|
||||
if kustomization.Annotations == nil {
|
||||
kustomization.Annotations = map[string]string{
|
||||
kustomizev1.SyncAtAnnotation: time.Now().String(),
|
||||
}
|
||||
} else {
|
||||
kustomization.Annotations[kustomizev1.SyncAtAnnotation] = time.Now().String()
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &kustomization); err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("kustomization annotated")
|
||||
}
|
||||
|
||||
logWaiting("waiting for kustomization sync")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isKustomizationReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("kustomization sync completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if kustomization.Status.LastAppliedRevision != "" {
|
||||
logSuccess("applied revision %s", kustomization.Status.LastAppliedRevision)
|
||||
} else {
|
||||
return fmt.Errorf("kustomization sync failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var syncSourceCmd = &cobra.Command{
|
||||
Use: "source",
|
||||
Short: "Synchronize source commands",
|
||||
}
|
||||
|
||||
func init() {
|
||||
syncCmd.AddCommand(syncSourceCmd)
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"time"
|
||||
)
|
||||
|
||||
var syncSourceGitCmd = &cobra.Command{
|
||||
Use: "git [name]",
|
||||
Short: "Synchronize git source",
|
||||
Long: `
|
||||
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
|
||||
sync source git podinfo
|
||||
`,
|
||||
RunE: syncSourceGitCmdRun,
|
||||
}
|
||||
|
||||
func init() {
|
||||
syncSourceCmd.AddCommand(syncSourceGitCmd)
|
||||
}
|
||||
|
||||
func syncSourceGitCmdRun(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,
|
||||
}
|
||||
|
||||
logAction("annotating source %s in %s namespace", name, namespace)
|
||||
var gitRepository sourcev1.GitRepository
|
||||
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gitRepository.Annotations == nil {
|
||||
gitRepository.Annotations = map[string]string{
|
||||
sourcev1.SyncAtAnnotation: time.Now().String(),
|
||||
}
|
||||
} else {
|
||||
gitRepository.Annotations[sourcev1.SyncAtAnnotation] = time.Now().String()
|
||||
}
|
||||
if err := kubeClient.Update(ctx, &gitRepository); err != nil {
|
||||
return err
|
||||
}
|
||||
logSuccess("source annotated")
|
||||
|
||||
logWaiting("waiting for git sync")
|
||||
if err := wait.PollImmediate(pollInterval, timeout,
|
||||
isGitRepositoryReady(ctx, kubeClient, name, namespace)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logSuccess("git sync completed")
|
||||
|
||||
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gitRepository.Status.Artifact != nil {
|
||||
logSuccess("fetched revision %s", gitRepository.Status.Artifact.Revision)
|
||||
} else {
|
||||
return fmt.Errorf("git sync failed, artifact not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,25 @@
|
||||
/*
|
||||
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/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -11,25 +28,26 @@ import (
|
||||
var uninstallCmd = &cobra.Command{
|
||||
Use: "uninstall",
|
||||
Short: "Uninstall the toolkit components",
|
||||
Long: `
|
||||
The uninstall command removes the namespace, cluster roles,
|
||||
cluster role bindings and CRDs.`,
|
||||
Long: "The uninstall command removes the namespace, cluster roles, cluster role bindings and CRDs from the cluster.",
|
||||
Example: ` # Dry-run uninstall of all components
|
||||
uninstall --dry-run --namespace=gitops-system
|
||||
tk uninstall --dry-run --namespace=gitops-system
|
||||
|
||||
# Uninstall all components and delete custom resource definitions
|
||||
uninstall --crds --namespace=gitops-system
|
||||
tk uninstall --crds --namespace=gitops-system
|
||||
`,
|
||||
RunE: uninstallCmdRun,
|
||||
}
|
||||
|
||||
var (
|
||||
uninstallCRDs bool
|
||||
uninstallDryRun bool
|
||||
uninstallSilent bool
|
||||
uninstallCRDs bool
|
||||
uninstallKustomizations bool
|
||||
uninstallDryRun bool
|
||||
uninstallSilent bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
uninstallCmd.Flags().BoolVarP(&uninstallKustomizations, "kustomizations", "", false,
|
||||
"removes all Kustomizations previously installed")
|
||||
uninstallCmd.Flags().BoolVarP(&uninstallCRDs, "crds", "", false,
|
||||
"removes all CRDs previously installed")
|
||||
uninstallCmd.Flags().BoolVarP(&uninstallDryRun, "dry-run", "", false,
|
||||
@@ -57,18 +75,32 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if uninstallKustomizations {
|
||||
logger.Actionf("uninstalling kustomizations")
|
||||
command := fmt.Sprintf("kubectl -n %s delete kustomizations --all --timeout=%s %s",
|
||||
namespace, timeout.String(), dryRun)
|
||||
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
|
||||
return fmt.Errorf("uninstall failed")
|
||||
}
|
||||
|
||||
// TODO: use the kustomizations snapshots to create a list of objects
|
||||
// that are subject to deletion and wait for all of them to be terminated
|
||||
logger.Waitingf("waiting on GC")
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
|
||||
kinds := "namespace,clusterroles,clusterrolebindings"
|
||||
if uninstallCRDs {
|
||||
kinds += ",crds"
|
||||
}
|
||||
|
||||
logAction("uninstalling components")
|
||||
logger.Actionf("uninstalling components")
|
||||
command := fmt.Sprintf("kubectl delete %s -l app.kubernetes.io/instance=%s --timeout=%s %s",
|
||||
kinds, namespace, timeout.String(), dryRun)
|
||||
if _, err := utils.execCommand(ctx, ModeOS, command); err != nil {
|
||||
return fmt.Errorf("uninstall failed")
|
||||
}
|
||||
|
||||
logSuccess("uninstall finished")
|
||||
logger.Successf("uninstall finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
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 (
|
||||
@@ -10,12 +26,14 @@ import (
|
||||
"os/exec"
|
||||
"text/template"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2alpha1"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
|
||||
)
|
||||
|
||||
type Utils struct {
|
||||
@@ -95,19 +113,20 @@ func (*Utils) execTemplate(obj interface{}, tmpl, filename string) error {
|
||||
func (*Utils) kubeClient(config string) (client.Client, error) {
|
||||
cfg, err := clientcmd.BuildConfigFromFlags("", config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
||||
return nil, fmt.Errorf("Kubernetes client initialization failed: %w", err)
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
_ = corev1.AddToScheme(scheme)
|
||||
_ = sourcev1.AddToScheme(scheme)
|
||||
_ = kustomizev1.AddToScheme(scheme)
|
||||
_ = helmv2.AddToScheme(scheme)
|
||||
|
||||
kubeClient, err := client.New(cfg, client.Options{
|
||||
Scheme: scheme,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
||||
return nil, fmt.Errorf("Kubernetes client initialization failed: %w", err)
|
||||
}
|
||||
|
||||
return kubeClient, nil
|
||||
@@ -127,3 +146,23 @@ func (*Utils) writeFile(content, filename string) error {
|
||||
|
||||
return file.Sync()
|
||||
}
|
||||
|
||||
func (*Utils) copyFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return out.Close()
|
||||
}
|
||||
|
||||
22
docs/_files/flux-icon.svg
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64px" height="64px" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 56.3 (81716) - https://sketch.com -->
|
||||
<title>flux-icon</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="flux-icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group" transform="translate(11.000000, 2.000000)">
|
||||
<path d="M0.803134615,15.7791346 C-0.246288462,15.0966346 -0.246288462,13.5602885 0.803134615,12.8783654 L20.1819808,0.279519231 C20.7554423,-0.0931730769 21.4944808,-0.0931730769 22.0679423,0.279519231 L41.4473654,12.8783654 C42.4967885,13.5602885 42.4967885,15.0966346 41.4473654,15.7791346 L22.0679423,28.3779808 C21.4944808,28.7506731 20.7554423,28.7506731 20.1819808,28.3779808 L0.803134615,15.7791346 Z" id="Fill-1" fill="#326CE5"></path>
|
||||
<path d="M24.1851346,18.0023077 L25.5293654,18.0023077 C26.3145577,18.0023077 26.8055192,17.1525 26.4126346,16.4728846 L22.0084038,8.84423077 C21.6160962,8.16461538 20.63475,8.16461538 20.2418654,8.84423077 L15.8376346,16.4728846 C15.4453269,17.1525 15.9357115,18.0023077 16.7209038,18.0023077 L18.0657115,18.0023077 C18.6287885,18.0023077 19.0851346,18.4592308 19.0851346,19.0223077 L19.0851346,27.7298077 L19.9874423,28.3165385 C20.6791731,28.7665385 21.5710962,28.7665385 22.2628269,28.3165385 L23.1651346,27.7298077 L23.1651346,19.0223077 C23.1651346,18.4592308 23.6214808,18.0023077 24.1851346,18.0023077" id="Fill-3" fill="#C1D2F7"></path>
|
||||
<path d="M27.8390769,34.8375577 L23.1648462,31.7989038 L23.1648462,33.2389038 C24.6902308,33.8919808 26.2588846,34.4008269 27.8390769,34.8375577" id="Fill-5" fill="#326CE5"></path>
|
||||
<path d="M23.1650769,35.8280192 L23.1650769,37.8495577 C24.7095,38.3209038 26.2723846,38.7080192 27.8191154,39.0893654 C32.8706538,40.3349423 37.6418077,41.5107115 41.4783462,45.3478269 C41.6733462,45.54225 41.8562308,45.7407115 42.0373846,45.93975 C42.4308462,45.1880192 42.2335385,44.1957115 41.4466154,43.6845577 L33.8560385,38.7489808 C32.0133462,38.1409038 30.1360385,37.6759038 28.2806538,37.2189808 C26.5308462,36.7874423 24.8196923,36.3570577 23.1650769,35.8280192" id="Fill-7" fill="#326CE5"></path>
|
||||
<path d="M19.08525,34.1699423 C18.4304423,33.8318654 17.7854423,33.4689808 17.1629423,33.0489808 L15.4269808,34.1774423 C16.5975577,35.0382115 17.8235192,35.7362885 19.08525,36.3212885 L19.08525,34.1699423 Z" id="Fill-9" fill="#326CE5"></path>
|
||||
<path d="M24.8941731,40.6051154 C24.3137885,40.4620385 23.7374423,40.3195385 23.1651346,40.1735769 L23.1651346,42.1605 C23.5885962,42.2666538 24.0114808,42.3722308 24.4326346,42.4760769 C29.4841731,43.7210769 34.2553269,44.8968462 38.0924423,48.7339615 C38.0987885,48.7408846 38.1045577,48.7472308 38.1114808,48.7541538 L39.75225,47.6868462 C39.6524423,47.5824231 39.5584038,47.4751154 39.4545577,47.3718462 C35.2384038,43.1551154 29.9791731,41.8587692 24.8941731,40.6051154" id="Fill-11" fill="#326CE5"></path>
|
||||
<path d="M19.08525,38.9907115 C16.8900577,38.2389808 14.8096731,37.2714808 12.9115962,35.8124423 L11.2119808,36.9178269 C13.6287115,38.9110962 16.3194808,40.1203269 19.08525,41.0168654 L19.08525,38.9907115 Z" id="Fill-13" fill="#326CE5"></path>
|
||||
<path d="M19.08525,43.3809808 C15.3069808,42.3909808 11.7537115,41.18175 8.71794231,38.5388654 L7.04717308,39.6252115 C10.6125577,42.9102115 14.8540962,44.2832885 19.08525,45.3707885 L19.08525,43.3809808 Z" id="Fill-15" fill="#326CE5"></path>
|
||||
<path d="M23.1650769,46.3935 C27.1175769,47.4140769 30.8341154,48.6342692 33.9823846,51.4381154 L35.6439231,50.3581154 C31.9654615,46.9000385 27.5514231,45.5194615 23.1650769,44.4048462 L23.1650769,46.3935 Z" id="Fill-17" fill="#326CE5"></path>
|
||||
<path d="M4.57875,41.2299231 L2.92990385,42.3018462 C2.98759615,42.3612692 3.04009615,42.423 3.09951923,42.4818462 C7.31625,46.6985769 12.5743269,47.9949231 17.6599038,49.2485769 C22.0641346,50.3337692 26.2543269,51.3687692 29.7989423,54.1581923 L31.4893269,53.0591538 C27.4958654,49.6968462 22.7385577,48.5158846 18.1214423,47.3781923 C13.1206731,46.1453077 8.39567308,44.9758846 4.57875,41.2299231" id="Fill-19" fill="#326CE5"></path>
|
||||
<path d="M1.07555769,44.5060962 C0.883442308,44.3139808 0.702865385,44.1184038 0.524019231,43.9216731 C-0.227711538,44.6745577 -0.139442308,45.9726346 0.80325,46.5853269 L6.50959615,50.2955192 C9.03536538,51.3409038 11.6765192,51.9945577 14.2738269,52.6349423 C18.3284423,53.6341731 22.2019038,54.5924423 25.5578654,56.9157115 L27.2834423,55.7930192 C23.4676731,52.9245577 19.0403654,51.8255192 14.7347885,50.7639808 C9.68382692,49.5189808 4.91267308,48.3432115 1.07555769,44.5060962" id="Fill-21" fill="#326CE5"></path>
|
||||
<path d="M19.6441154,58.8342692 C20.0243077,59.0188846 20.3998846,59.2133077 20.7691154,59.4221538 C21.2093077,59.5150385 21.6771923,59.4383077 22.0683462,59.1838846 L23.0260385,58.5613846 C19.9493077,56.5035 16.5287308,55.461 13.1196923,54.5927308 L19.6441154,58.8342692 Z" id="Fill-23" fill="#326CE5"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
BIN
docs/_files/flux-icon@2x.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
docs/_files/helm-controller.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
docs/_files/kustomize-controller.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/_files/notification-controller.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/_files/source-controller.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/_files/toolkit-icon.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
24
docs/_static/custom.css
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
@import url("https://fonts.googleapis.com/css?family=Montserrat&display=swap");
|
||||
|
||||
body {
|
||||
font-family: "Montserrat", sans-serif;
|
||||
}
|
||||
|
||||
.md-logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding-bottom: 2px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.md-logo img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.md-header, .md-footer-nav {
|
||||
background-image: linear-gradient(45deg, rgb(0, 150, 225) 0%, rgb(27, 141, 226) 24%, rgb(42, 125, 227) 53%, rgb(53, 112, 227) 78%, rgb(53, 112, 227) 100%);
|
||||
}
|
||||
|
||||
.md-header-nav__title {
|
||||
font-size: .85rem;
|
||||
}
|
||||
@@ -21,42 +21,42 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
|
||||
--branch=master \
|
||||
--interval=3m
|
||||
|
||||
# List git sources and their status
|
||||
# List GitRepository sources and their status
|
||||
tk get sources git
|
||||
|
||||
# Trigger a git sync
|
||||
# Trigger a GitRepository source sync
|
||||
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
|
||||
|
||||
# Create a kustomization for deploying a series of microservices
|
||||
# Create a Kustomization for deploying a series of microservices
|
||||
tk create kustomization webapp-dev \
|
||||
--source=webapp-latest \
|
||||
--path="./deploy/webapp/" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--health-check="Deployment/backend.webapp" \
|
||||
--health-check="Deployment/frontend.webapp" \
|
||||
--health-check-timeout=2m
|
||||
|
||||
# Trigger a git sync and apply changes if any
|
||||
tk sync kustomization webapp-dev --with-source
|
||||
# Trigger a git sync of the Kustomization's source and apply changes
|
||||
tk reconcile kustomization webapp-dev --with-source
|
||||
|
||||
# Suspend a kustomization reconciliation
|
||||
# Suspend a Kustomization reconciliation
|
||||
tk suspend kustomization webapp-dev
|
||||
|
||||
# Export kustomizations in YAML format
|
||||
# Export Kustomizations in YAML format
|
||||
tk export kustomization --all > kustomizations.yaml
|
||||
|
||||
# Resume a kustomization reconciliation
|
||||
# Resume a Kustomization reconciliation
|
||||
tk resume kustomization webapp-dev
|
||||
|
||||
# Delete a kustomization
|
||||
# Delete a Kustomization
|
||||
tk delete kustomization webapp-dev
|
||||
|
||||
# Delete a git source
|
||||
# Delete a GitRepository source
|
||||
tk delete source git webapp-latest
|
||||
|
||||
# Uninstall the toolkit and delete CRDs
|
||||
@@ -67,27 +67,25 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
|
||||
### Options
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
-h, --help help for tk
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
-h, --help help for tk
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [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 completion](tk_completion.md) - Generates bash completion scripts
|
||||
* [tk create](tk_create.md) - Create commands
|
||||
* [tk delete](tk_delete.md) - Delete commands
|
||||
* [tk export](tk_export.md) - Export commands
|
||||
* [tk get](tk_get.md) - Get commands
|
||||
* [tk create](tk_create.md) - Create or update sources and resources
|
||||
* [tk delete](tk_delete.md) - Delete sources and resources
|
||||
* [tk export](tk_export.md) - Export resources in YAML format
|
||||
* [tk get](tk_get.md) - Get sources and resources
|
||||
* [tk install](tk_install.md) - Install the toolkit components
|
||||
* [tk resume](tk_resume.md) - Resume commands
|
||||
* [tk suspend](tk_suspend.md) - Suspend commands
|
||||
* [tk sync](tk_sync.md) - Synchronize commands
|
||||
* [tk reconcile](tk_reconcile.md) - Reconcile sources and resources
|
||||
* [tk resume](tk_resume.md) - Resume suspended resources
|
||||
* [tk suspend](tk_suspend.md) - Suspend resources
|
||||
* [tk uninstall](tk_uninstall.md) - Uninstall the toolkit components
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
## tk bootstrap
|
||||
|
||||
Bootstrap commands
|
||||
Bootstrap toolkit components
|
||||
|
||||
### Synopsis
|
||||
|
||||
Bootstrap commands
|
||||
The bootstrap sub-commands bootstrap the toolkit components on the targeted Git provider.
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for bootstrap
|
||||
--version string toolkit tag or branch (default "master")
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
||||
-h, --help help for bootstrap
|
||||
-v, --version string toolkit version (default "latest")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
* [tk 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 toolkit components in a GitLab repository
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
## tk bootstrap github
|
||||
|
||||
Bootstrap GitHub repository
|
||||
Bootstrap toolkit components in a GitHub repository
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
The bootstrap command creates the GitHub repository if it doesn't exists and
|
||||
The bootstrap github command creates the GitHub repository if it doesn't exists and
|
||||
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,
|
||||
the bootstrap command will perform an upgrade if needed.
|
||||
|
||||
@@ -22,13 +21,19 @@ tk bootstrap github [flags]
|
||||
export GITHUB_TOKEN=<my-token>
|
||||
|
||||
# Run bootstrap for a private repo owned by a GitHub organization
|
||||
bootstrap github --owner=<organization> --repository=<repo name>
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name>
|
||||
|
||||
# Run bootstrap for a private repo and assign organization teams to it
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name> --team=<team1 slug> --team=<team2 slug>
|
||||
|
||||
# Run bootstrap for a repository path
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name> --path=dev-cluster
|
||||
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
tk bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
|
||||
# Run bootstrap for a private repo hosted on GitHub Enterprise
|
||||
bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
|
||||
tk bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
|
||||
|
||||
```
|
||||
|
||||
@@ -39,24 +44,25 @@ tk bootstrap github [flags]
|
||||
--hostname string GitHub hostname (default "github.com")
|
||||
--interval duration sync interval (default 1m0s)
|
||||
--owner string GitHub user or organization name
|
||||
--path string repository path, when specified the cluster sync will be scoped to this path
|
||||
--personal is personal repository
|
||||
--private is private repository (default true)
|
||||
--repository string GitHub repository name
|
||||
--team stringArray GitHub team to be given maintainer access
|
||||
```
|
||||
|
||||
### 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--version string toolkit tag or branch (default "master")
|
||||
-v, --version string toolkit version (default "latest")
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk bootstrap](tk_bootstrap.md) - Bootstrap commands
|
||||
* [tk bootstrap](tk_bootstrap.md) - Bootstrap toolkit components
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
64
docs/cmd/tk_bootstrap_gitlab.md
Normal file
@@ -0,0 +1,64 @@
|
||||
## tk bootstrap gitlab
|
||||
|
||||
Bootstrap toolkit components in a GitLab repository
|
||||
|
||||
### Synopsis
|
||||
|
||||
The bootstrap gitlab command creates the GitLab repository if it doesn't exists and
|
||||
commits the toolkit components manifests to the master branch.
|
||||
Then it configures the target cluster to synchronize with the repository.
|
||||
If the toolkit components are present on the cluster,
|
||||
the bootstrap command will perform an upgrade if needed.
|
||||
|
||||
```
|
||||
tk bootstrap gitlab [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Create a GitLab API token and export it as an env var
|
||||
export GITLAB_TOKEN=<my-token>
|
||||
|
||||
# Run bootstrap for a private repo owned by a GitLab group
|
||||
tk bootstrap gitlab --owner=<group> --repository=<repo name>
|
||||
|
||||
# Run bootstrap for a repository path
|
||||
tk bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
|
||||
|
||||
# Run bootstrap for a public repository on a personal account
|
||||
tk bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||
|
||||
# Run bootstrap for a private repo hosted on a GitLab server
|
||||
tk bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for gitlab
|
||||
--hostname string GitLab hostname (default "gitlab.com")
|
||||
--interval duration sync interval (default 1m0s)
|
||||
--owner string GitLab user or group name
|
||||
--path string repository path, when specified the cluster sync will be scoped to this path
|
||||
--personal is personal repository
|
||||
--private is private repository (default true)
|
||||
--repository string GitLab repository name
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
-v, --version string toolkit version (default "latest")
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk bootstrap](tk_bootstrap.md) - Bootstrap toolkit components
|
||||
|
||||
@@ -4,7 +4,6 @@ Check requirements and installation
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -16,32 +15,31 @@ tk check [flags]
|
||||
|
||||
```
|
||||
# Run pre-installation checks
|
||||
check --pre
|
||||
tk check --pre
|
||||
|
||||
# Run installation checks
|
||||
check
|
||||
tk check
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for check
|
||||
--pre only run pre-installation checks
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
||||
-h, --help help for check
|
||||
--pre only run pre-installation checks
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -33,15 +33,13 @@ To configure your bash shell to load completions for each session add to your ba
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
## tk create
|
||||
|
||||
Create commands
|
||||
Create or update sources and resources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Create commands
|
||||
The create sub-commands generate sources and resources.
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--export export in yaml format to stdout
|
||||
--export export in YAML format to stdout
|
||||
-h, --help help for create
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
```
|
||||
@@ -17,17 +17,16 @@ Create 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
* [tk create kustomization](tk_create_kustomization.md) - Create or update a kustomization resource
|
||||
* [tk create source](tk_create_source.md) - Create source commands
|
||||
* [tk create helmrelease](tk_create_helmrelease.md) - Create or update a HelmRelease resource
|
||||
* [tk create kustomization](tk_create_kustomization.md) - Create or update a Kustomization resource
|
||||
* [tk create source](tk_create_source.md) - Create or update sources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
71
docs/cmd/tk_create_helmrelease.md
Normal file
@@ -0,0 +1,71 @@
|
||||
## tk create helmrelease
|
||||
|
||||
Create or update a HelmRelease resource
|
||||
|
||||
### Synopsis
|
||||
|
||||
The helmrelease create command generates a HelmRelease resource for a given HelmRepository source.
|
||||
|
||||
```
|
||||
tk create helmrelease [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Create a HelmRelease from a source
|
||||
tk create hr podinfo \
|
||||
--interval=10m \
|
||||
--release-name=podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=">4.0.0"
|
||||
|
||||
# Create a HelmRelease with values for a local YAML file
|
||||
tk create hr podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=4.0.5 \
|
||||
--values=./my-values.yaml
|
||||
|
||||
# Create a HelmRelease definition on disk without applying it on the cluster
|
||||
tk create hr podinfo \
|
||||
--target-namespace=default \
|
||||
--source=podinfo \
|
||||
--chart-name=podinfo \
|
||||
--chart-version=4.0.5 \
|
||||
--values=./values.yaml \
|
||||
--export > podinfo-release.yaml
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--chart-name string Helm chart name
|
||||
--chart-version string Helm chart version, accepts semver range
|
||||
--depends-on stringArray HelmReleases that must be ready before this release can be installed
|
||||
-h, --help help for helmrelease
|
||||
--release-name string name used for the Helm release, defaults to a composition of '<target-namespace>-<hr-name>'
|
||||
--source string HelmRepository name
|
||||
--target-namespace string namespace to install this release, defaults to the HelmRelease namespace
|
||||
--values string local path to the values.yaml file
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--export export in YAML format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk create](tk_create.md) - Create or update sources and resources
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
## tk create kustomization
|
||||
|
||||
Create or update a kustomization resource
|
||||
Create or update a Kustomization resource
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
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
|
||||
The kustomization source create command generates a Kustomize resource for a given GitRepository source.
|
||||
|
||||
```
|
||||
tk create kustomization [name] [flags]
|
||||
@@ -15,33 +13,33 @@ tk create kustomization [name] [flags]
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Create a kustomization from a source at a given path
|
||||
create kustomization contour \
|
||||
# Create a Kustomization resource from a source at a given path
|
||||
tk create kustomization contour \
|
||||
--source=contour \
|
||||
--path="./examples/contour/" \
|
||||
--prune=true \
|
||||
--interval=10m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--health-check="Deployment/contour.projectcontour" \
|
||||
--health-check="DaemonSet/envoy.projectcontour" \
|
||||
--health-check-timeout=3m
|
||||
|
||||
# Create a kustomization that depends on the previous one
|
||||
create kustomization webapp \
|
||||
# Create a Kustomization resource that depends on the previous one
|
||||
tk create kustomization webapp \
|
||||
--depends-on=contour \
|
||||
--source=webapp \
|
||||
--path="./deploy/overlays/dev" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client
|
||||
--validation=client
|
||||
|
||||
# Create a kustomization that runs under a service account
|
||||
create kustomization webapp \
|
||||
# Create a Kustomization resource that runs under a service account
|
||||
tk create kustomization webapp \
|
||||
--source=webapp \
|
||||
--path="./deploy/overlays/staging" \
|
||||
--prune=true \
|
||||
--interval=5m \
|
||||
--validate=client \
|
||||
--validation=client \
|
||||
--sa-name=reconclier \
|
||||
--sa-namespace=staging
|
||||
|
||||
@@ -50,32 +48,30 @@ tk create kustomization [name] [flags]
|
||||
### 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-timeout duration timeout of health checking operations (default 2m0s)
|
||||
-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
|
||||
--sa-name string service account name
|
||||
--sa-namespace string service account namespace
|
||||
--source string GitRepository name
|
||||
--validate string validate the manifests before applying them on the cluster, can be 'client' or 'server'
|
||||
--validation string validate the manifests before applying them on the cluster, can be 'client' or 'server'
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--export export in yaml format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--export export in YAML format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk create](tk_create.md) - Create commands
|
||||
* [tk create](tk_create.md) - Create or update sources and resources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk create source
|
||||
|
||||
Create source commands
|
||||
Create or update sources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Create source commands
|
||||
The create source sub-commands generate sources.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -15,18 +15,17 @@ Create source 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
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--export export in YAML format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk create](tk_create.md) - Create commands
|
||||
* [tk create source git](tk_create_source_git.md) - Create or update a git source
|
||||
* [tk create](tk_create.md) - Create or update sources and resources
|
||||
* [tk create source git](tk_create_source_git.md) - Create or update a GitRepository source
|
||||
* [tk create source helm](tk_create_source_helm.md) - Create or update a HelmRepository source
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
## tk create source git
|
||||
|
||||
Create or update a git source
|
||||
Create or update a GitRepository source
|
||||
|
||||
### 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 private Git repositories, the basic authentication credentials are stored in a Kubernetes secret.
|
||||
|
||||
@@ -17,35 +17,35 @@ tk create source git [name] [flags]
|
||||
|
||||
```
|
||||
# Create a source from a public Git repository master branch
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--branch=master
|
||||
|
||||
# Create a source from a Git repository pinned to specific git tag
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--tag="3.2.3"
|
||||
|
||||
# Create a source from a public Git repository tag that matches a semver range
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--tag-semver=">=3.2.0 <3.3.0"
|
||||
|
||||
# Create a source from a Git repository using SSH authentication
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||
--branch=master
|
||||
|
||||
# Create a source from a Git repository using SSH authentication and an
|
||||
# ECDSA P-521 curve public key
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||
--branch=master \
|
||||
--ssh-key-algorithm=ecdsa \
|
||||
--ssh-ecdsa-curve=p521
|
||||
|
||||
# Create a source from a Git repository using basic authentication
|
||||
create source git podinfo \
|
||||
tk create source git podinfo \
|
||||
--url=https://github.com/stefanprodan/podinfo \
|
||||
--username=username \
|
||||
--password=password
|
||||
@@ -58,7 +58,7 @@ tk create source git [name] [flags]
|
||||
--branch string git branch (default "master")
|
||||
-h, --help help for git
|
||||
-p, --password string basic authentication password
|
||||
--ssh-ecdsa-curve ecdsaCurve SSH ECDSA public key curve (p521, p256, p384) (default p384)
|
||||
--ssh-ecdsa-curve ecdsaCurve SSH ECDSA public key curve (p256, p384, p521) (default p384)
|
||||
--ssh-key-algorithm publicKeyAlgorithm SSH public key algorithm (rsa, ecdsa, ed25519) (default rsa)
|
||||
--ssh-rsa-bits rsaKeyBits SSH RSA public key bit size (multiplies of 8) (default 2048)
|
||||
--tag string git tag
|
||||
@@ -70,17 +70,15 @@ tk create source git [name] [flags]
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--export export in yaml format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--export export in YAML format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk create source](tk_create_source.md) - Create source commands
|
||||
* [tk create source](tk_create_source.md) - Create or update sources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
54
docs/cmd/tk_create_source_helm.md
Normal file
@@ -0,0 +1,54 @@
|
||||
## tk create source helm
|
||||
|
||||
Create or update a HelmRepository source
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
The create source helm command generates a HelmRepository resource and waits for it to fetch the index.
|
||||
For private Helm repositories, the basic authentication credentials are stored in a Kubernetes secret.
|
||||
|
||||
```
|
||||
tk create source helm [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Create a source from a public Helm repository
|
||||
tk create source helm podinfo \
|
||||
--url=https://stefanprodan.github.io/podinfo \
|
||||
--interval=10m
|
||||
|
||||
# Create a source from a Helm repository using basic authentication
|
||||
tk create source helm podinfo \
|
||||
--url=https://stefanprodan.github.io/podinfo \
|
||||
--username=username \
|
||||
--password=password
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helm
|
||||
-p, --password string basic authentication password
|
||||
--url string Helm repository address
|
||||
-u, --username string basic authentication username
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--export export in YAML format to stdout
|
||||
--interval duration source sync interval (default 1m0s)
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk create source](tk_create_source.md) - Create or update sources
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk delete
|
||||
|
||||
Delete commands
|
||||
Delete sources and resources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Delete commands
|
||||
The delete sub-commands delete sources and resources.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -16,17 +16,16 @@ Delete 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
* [tk delete kustomization](tk_delete_kustomization.md) - Delete kustomization
|
||||
* [tk delete source](tk_delete_source.md) - Delete sources commands
|
||||
* [tk delete helmrelease](tk_delete_helmrelease.md) - Delete a HelmRelease resource
|
||||
* [tk delete kustomization](tk_delete_kustomization.md) - Delete a Kustomization resource
|
||||
* [tk delete source](tk_delete_source.md) - Delete sources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
40
docs/cmd/tk_delete_helmrelease.md
Normal file
@@ -0,0 +1,40 @@
|
||||
## tk delete helmrelease
|
||||
|
||||
Delete a HelmRelease resource
|
||||
|
||||
### Synopsis
|
||||
|
||||
The delete helmrelease command removes the given HelmRelease from the cluster.
|
||||
|
||||
```
|
||||
tk delete helmrelease [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Delete a Helm release and the Kubernetes resources created by it
|
||||
tk delete hr podinfo
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helmrelease
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk delete](tk_delete.md) - Delete sources and resources
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
## tk delete kustomization
|
||||
|
||||
Delete kustomization
|
||||
Delete a Kustomization resource
|
||||
|
||||
### Synopsis
|
||||
|
||||
Delete kustomization
|
||||
The delete kustomization command deletes the given Kustomization from the cluster.
|
||||
|
||||
```
|
||||
tk delete kustomization [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Delete a kustomization and the Kubernetes resources created by it
|
||||
tk delete kustomization podinfo
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
@@ -19,16 +27,14 @@ tk delete kustomization [name] [flags]
|
||||
### 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")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk delete](tk_delete.md) - Delete commands
|
||||
* [tk delete](tk_delete.md) - Delete sources and resources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk delete source
|
||||
|
||||
Delete sources commands
|
||||
Delete sources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Delete sources commands
|
||||
The delete source sub-commands delete sources.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -15,17 +15,16 @@ Delete sources 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk delete](tk_delete.md) - Delete commands
|
||||
* [tk delete source git](tk_delete_source_git.md) - Delete git source
|
||||
* [tk delete](tk_delete.md) - Delete sources and resources
|
||||
* [tk delete source git](tk_delete_source_git.md) - Delete a GitRepository source
|
||||
* [tk delete source helm](tk_delete_source_helm.md) - Delete a HelmRepository source
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
## tk delete source git
|
||||
|
||||
Delete git source
|
||||
Delete a GitRepository source
|
||||
|
||||
### Synopsis
|
||||
|
||||
Delete git source
|
||||
The delete source git command deletes the given GitRepository from the cluster.
|
||||
|
||||
```
|
||||
tk delete source git [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Delete a Git repository
|
||||
tk delete source git podinfo
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
@@ -19,16 +27,14 @@ tk delete source git [name] [flags]
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk delete source](tk_delete_source.md) - Delete sources commands
|
||||
* [tk delete source](tk_delete_source.md) - Delete sources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
40
docs/cmd/tk_delete_source_helm.md
Normal file
@@ -0,0 +1,40 @@
|
||||
## tk delete source helm
|
||||
|
||||
Delete a HelmRepository source
|
||||
|
||||
### Synopsis
|
||||
|
||||
The delete source helm command deletes the given HelmRepository from the cluster.
|
||||
|
||||
```
|
||||
tk delete source helm [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Delete a Helm repository
|
||||
tk delete source helm podinfo
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helm
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
-s, --silent delete resource without asking for confirmation
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk delete source](tk_delete_source.md) - Delete sources
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk export
|
||||
|
||||
Export commands
|
||||
Export resources in YAML format
|
||||
|
||||
### Synopsis
|
||||
|
||||
Export commands
|
||||
The export sub-commands export resources in YAML format.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -16,17 +16,16 @@ Export 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
* [tk export kustomization](tk_export_kustomization.md) - Export kustomization in YAML format
|
||||
* [tk export source](tk_export_source.md) - Export source commands
|
||||
* [tk export helmrelease](tk_export_helmrelease.md) - Export HelmRelease resources in YAML format
|
||||
* [tk export kustomization](tk_export_kustomization.md) - Export Kustomization resources in YAML format
|
||||
* [tk export source](tk_export_source.md) - Export sources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
43
docs/cmd/tk_export_helmrelease.md
Normal file
@@ -0,0 +1,43 @@
|
||||
## tk export helmrelease
|
||||
|
||||
Export HelmRelease resources in YAML format
|
||||
|
||||
### Synopsis
|
||||
|
||||
The export helmrelease command exports one or all HelmRelease resources in YAML format.
|
||||
|
||||
```
|
||||
tk export helmrelease [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Export all HelmRelease resources
|
||||
tk export helmrelease --all > kustomizations.yaml
|
||||
|
||||
# Export a HelmRelease
|
||||
tk export hr my-app > app-release.yaml
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helmrelease
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--all select all resources
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk export](tk_export.md) - Export resources in YAML format
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk export kustomization
|
||||
|
||||
Export kustomization in YAML format
|
||||
Export Kustomization resources in YAML format
|
||||
|
||||
### Synopsis
|
||||
|
||||
Export kustomization in YAML format
|
||||
The export kustomization command exports one or all Kustomization resources in YAML format.
|
||||
|
||||
```
|
||||
tk export kustomization [name] [flags]
|
||||
@@ -13,11 +13,11 @@ tk export kustomization [name] [flags]
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Export all kustomizations
|
||||
export kustomization --all > kustomizations.yaml
|
||||
# Export all Kustomization resources
|
||||
tk export kustomization --all > kustomizations.yaml
|
||||
|
||||
# Export a kustomization
|
||||
export kustomization my-app > kustomization.yaml
|
||||
# Export a Kustomization
|
||||
tk export kustomization my-app > kustomization.yaml
|
||||
|
||||
```
|
||||
|
||||
@@ -30,16 +30,14 @@ tk export kustomization [name] [flags]
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--all select all resources
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--all select all resources
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk export](tk_export.md) - Export commands
|
||||
* [tk export](tk_export.md) - Export resources in YAML format
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk export source
|
||||
|
||||
Export source commands
|
||||
Export sources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Export source commands
|
||||
The export source sub-commands export sources in YAML format.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -16,17 +16,16 @@ Export source commands
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--all select all resources
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk export](tk_export.md) - Export commands
|
||||
* [tk export source git](tk_export_source_git.md) - Export git sources in YAML format
|
||||
* [tk export](tk_export.md) - Export resources in YAML format
|
||||
* [tk export source git](tk_export_source_git.md) - Export GitRepository sources in YAML format
|
||||
* [tk export source helm](tk_export_source_helm.md) - Export HelmRepository sources in YAML format
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk export source git
|
||||
|
||||
Export git sources in YAML format
|
||||
Export GitRepository sources in YAML format
|
||||
|
||||
### 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]
|
||||
@@ -13,11 +13,11 @@ tk export source git [name] [flags]
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Export all git sources
|
||||
export source git --all > sources.yaml
|
||||
# Export all GitRepository sources
|
||||
tk export source git --all > sources.yaml
|
||||
|
||||
# Export a git source including the SSH keys or basic auth credentials
|
||||
export source git my-private-repo --with-credentials > source.yaml
|
||||
# Export a GitRepository source including the SSH key pair or basic auth credentials
|
||||
tk export source git my-private-repo --with-credentials > source.yaml
|
||||
|
||||
```
|
||||
|
||||
@@ -30,17 +30,15 @@ tk export source git [name] [flags]
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--all select all resources
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--with-credentials include credential secrets
|
||||
--all select all resources
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--with-credentials include credential secrets
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk export source](tk_export_source.md) - Export source commands
|
||||
* [tk export source](tk_export_source.md) - Export sources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
44
docs/cmd/tk_export_source_helm.md
Normal file
@@ -0,0 +1,44 @@
|
||||
## tk export source helm
|
||||
|
||||
Export HelmRepository sources in YAML format
|
||||
|
||||
### Synopsis
|
||||
|
||||
The export source git command exports on or all HelmRepository sources in YAML format.
|
||||
|
||||
```
|
||||
tk export source helm [name] [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# Export all HelmRepository sources
|
||||
tk export source helm --all > sources.yaml
|
||||
|
||||
# Export a HelmRepository source including the basic auth credentials
|
||||
tk export source helm my-private-repo --with-credentials > source.yaml
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helm
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--all select all resources
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--with-credentials include credential secrets
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk export source](tk_export_source.md) - Export sources
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk get
|
||||
|
||||
Get commands
|
||||
Get sources and resources
|
||||
|
||||
### Synopsis
|
||||
|
||||
Get commands
|
||||
The get sub-commands print the statuses of sources and resources.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -15,17 +15,16 @@ Get 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
* [tk get kustomizations](tk_get_kustomizations.md) - Get kustomizations status
|
||||
* [tk get sources](tk_get_sources.md) - Get sources commands
|
||||
* [tk get helmreleases](tk_get_helmreleases.md) - Get HelmRelease statuses
|
||||
* [tk get kustomizations](tk_get_kustomizations.md) - Get Kustomization statuses
|
||||
* [tk get sources](tk_get_sources.md) - Get source statuses
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
39
docs/cmd/tk_get_helmreleases.md
Normal file
@@ -0,0 +1,39 @@
|
||||
## tk get helmreleases
|
||||
|
||||
Get HelmRelease statuses
|
||||
|
||||
### Synopsis
|
||||
|
||||
The get helmreleases command prints the statuses of the resources.
|
||||
|
||||
```
|
||||
tk get helmreleases [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# List all Helm releases and their status
|
||||
tk get helmreleases
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helmreleases
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk get](tk_get.md) - Get sources and resources
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
## tk get kustomizations
|
||||
|
||||
Get kustomizations status
|
||||
Get Kustomization statuses
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
The get kustomizations command prints the status of the resources.
|
||||
The get kustomizations command prints the statuses of the resources.
|
||||
|
||||
```
|
||||
tk get kustomizations [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# List all kustomizations and their status
|
||||
tk get kustomizations
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
@@ -20,15 +27,13 @@ tk get kustomizations [flags]
|
||||
### 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
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk get](tk_get.md) - Get commands
|
||||
* [tk get](tk_get.md) - Get sources and resources
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## tk get sources
|
||||
|
||||
Get sources commands
|
||||
Get source statuses
|
||||
|
||||
### Synopsis
|
||||
|
||||
Get sources commands
|
||||
The get source sub-commands print the statuses of the sources.
|
||||
|
||||
### Options
|
||||
|
||||
@@ -15,16 +15,15 @@ Get sources 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")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk get](tk_get.md) - Get commands
|
||||
* [tk get sources git](tk_get_sources_git.md) - Get git sources status
|
||||
* [tk get](tk_get.md) - Get sources and resources
|
||||
* [tk get sources git](tk_get_sources_git.md) - Get GitRepository source statuses
|
||||
* [tk get sources helm](tk_get_sources_helm.md) - Get HelmRepository source statuses
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
## tk get sources git
|
||||
|
||||
Get git sources status
|
||||
Get GitRepository source statuses
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
The get sources command prints the status of the git resources.
|
||||
The get sources git command prints the status of the GitRepository sources.
|
||||
|
||||
```
|
||||
tk get sources git [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# List all Git repositories and their status
|
||||
tk get sources git
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
@@ -20,15 +27,13 @@ tk get sources git [flags]
|
||||
### 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
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk get sources](tk_get_sources.md) - Get sources commands
|
||||
* [tk get sources](tk_get_sources.md) - Get source statuses
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
39
docs/cmd/tk_get_sources_helm.md
Normal file
@@ -0,0 +1,39 @@
|
||||
## tk get sources helm
|
||||
|
||||
Get HelmRepository source statuses
|
||||
|
||||
### Synopsis
|
||||
|
||||
The get sources helm command prints the status of the HelmRepository sources.
|
||||
|
||||
```
|
||||
tk get sources helm [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
# List all Helm repositories and their status
|
||||
tk get sources helm
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for helm
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk get sources](tk_get_sources.md) - Get source statuses
|
||||
|
||||
@@ -4,7 +4,6 @@ Install the toolkit components
|
||||
|
||||
### Synopsis
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -16,37 +15,40 @@ tk install [flags]
|
||||
|
||||
```
|
||||
# Install the latest version in the gitops-systems namespace
|
||||
install --version=master --namespace=gitops-systems
|
||||
tk install --version=latest --namespace=gitops-systems
|
||||
|
||||
# Dry-run install for a specific version and a series of components
|
||||
install --dry-run --version=0.0.1 --components="source-controller,kustomize-controller"
|
||||
tk install --dry-run --version=v0.0.7 --components="source-controller,kustomize-controller"
|
||||
|
||||
# Dry-run install with manifests preview
|
||||
install --dry-run --verbose
|
||||
tk install --dry-run --verbose
|
||||
|
||||
# Write install manifests to file
|
||||
tk install --export > gitops-system.yaml
|
||||
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--dry-run only print the object that would be applied
|
||||
-h, --help help for install
|
||||
--manifests string path to the manifest directory, dev only
|
||||
-v, --version string toolkit tag or branch (default "master")
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
||||
--dry-run only print the object that would be applied
|
||||
--export write the install manifests to stdout and exit
|
||||
-h, --help help for install
|
||||
--manifests string path to the manifest directory, dev only
|
||||
-v, --version string toolkit version (default "latest")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller])
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||
--namespace string the namespace scope for this operation (default "gitops-system")
|
||||
--timeout duration timeout for this operation (default 5m0s)
|
||||
--verbose print generated objects
|
||||
```
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [tk](tk.md) - Command line utility for assembling Kubernetes CD pipelines
|
||||
|
||||
###### Auto generated by spf13/cobra on 9-Jun-2020
|
||||
|
||||
30
docs/cmd/tk_reconcile.md
Normal 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
|
||||
|
||||
44
docs/cmd/tk_reconcile_helmrelease.md
Normal 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
|
||||
|
||||
44
docs/cmd/tk_reconcile_kustomization.md
Normal 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
|
||||
|
||||