mirror of https://github.com/fluxcd/flux2.git
				
				
				
			Merge pull request #1 from fluxcd/install
Implement check, install, uninstall and create source commandspull/3/head
						commit
						38cc918a2f
					
				@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					FROM giantswarm/tiny-tools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY entrypoint.sh /entrypoint.sh
 | 
				
			||||||
 | 
					RUN chmod +x /entrypoint.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENTRYPOINT ["/entrypoint.sh"]
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					name: 'kustomize'
 | 
				
			||||||
 | 
					description: 'A GitHub Action to run kustomize commands'
 | 
				
			||||||
 | 
					author: 'Stefan Prodan'
 | 
				
			||||||
 | 
					branding:
 | 
				
			||||||
 | 
					  icon: 'command'
 | 
				
			||||||
 | 
					  color: 'blue'
 | 
				
			||||||
 | 
					runs:
 | 
				
			||||||
 | 
					  using: 'docker'
 | 
				
			||||||
 | 
					  image: 'Dockerfile'
 | 
				
			||||||
@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					#!/bin/sh -l
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VERSION=3.5.4
 | 
				
			||||||
 | 
					curl -sL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${VERSION}/kustomize_v${VERSION}_linux_amd64.tar.gz | tar xz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mkdir -p $GITHUB_WORKSPACE/bin
 | 
				
			||||||
 | 
					cp ./kustomize $GITHUB_WORKSPACE/bin
 | 
				
			||||||
 | 
					chmod +x $GITHUB_WORKSPACE/bin/kustomize
 | 
				
			||||||
 | 
					ls -lh $GITHUB_WORKSPACE/bin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "::add-path::$GITHUB_WORKSPACE/bin"
 | 
				
			||||||
 | 
					echo "::add-path::$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin"
 | 
				
			||||||
@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					name: e2e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  pull_request:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    branches:
 | 
				
			||||||
 | 
					      - master
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  kind:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout
 | 
				
			||||||
 | 
					        uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      - name: Restore Go cache
 | 
				
			||||||
 | 
					        uses: actions/cache@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          path: ~/go/pkg/mod
 | 
				
			||||||
 | 
					          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
 | 
				
			||||||
 | 
					          restore-keys: |
 | 
				
			||||||
 | 
					            ${{ runner.os }}-go-
 | 
				
			||||||
 | 
					      - name: Setup Go
 | 
				
			||||||
 | 
					        uses: actions/setup-go@v2-beta
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          go-version: 1.14.x
 | 
				
			||||||
 | 
					      - name: Setup Kubernetes
 | 
				
			||||||
 | 
					        uses: engineerd/setup-kind@v0.3.0
 | 
				
			||||||
 | 
					      - name: Setup Kustomize
 | 
				
			||||||
 | 
					        uses: ./.github/actions/kustomize
 | 
				
			||||||
 | 
					      - name: Run test
 | 
				
			||||||
 | 
					        run: make test
 | 
				
			||||||
 | 
					      - name: Check if working tree is dirty
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          if [[ $(git diff --stat) != '' ]]; then
 | 
				
			||||||
 | 
					            echo 'run make test and commit changes'
 | 
				
			||||||
 | 
					            exit 1
 | 
				
			||||||
 | 
					          fi
 | 
				
			||||||
 | 
					      - name: Build
 | 
				
			||||||
 | 
					        run: sudo go build -o ./bin/tk ./cmd/tk
 | 
				
			||||||
 | 
					      - name: Run integration tests
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          ./bin/tk check
 | 
				
			||||||
 | 
					          ./bin/tk install --manifests ./manifests/install/
 | 
				
			||||||
 | 
					          ./bin/tk create source podinfo --git-url https://github.com/stefanprodan/podinfo-deploy  --git-semver=">=0.0.1-rc.1 <0.1.0"
 | 
				
			||||||
 | 
					      - name: Debug failure
 | 
				
			||||||
 | 
					        if: failure()
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          kubectl version --client --short
 | 
				
			||||||
 | 
					          kustomize version --short
 | 
				
			||||||
 | 
					          kubectl -n gitops-system get all
 | 
				
			||||||
@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					name: release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    tags:
 | 
				
			||||||
 | 
					      - '*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  goreleaser:
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Checkout
 | 
				
			||||||
 | 
					        uses: actions/checkout@v2
 | 
				
			||||||
 | 
					      - name: Unshallow
 | 
				
			||||||
 | 
					        run: git fetch --prune --unshallow
 | 
				
			||||||
 | 
					      - name: Setup Go
 | 
				
			||||||
 | 
					        uses: actions/setup-go@v2-beta
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          go-version: 1.14.x
 | 
				
			||||||
 | 
					      - name: Download release notes utility
 | 
				
			||||||
 | 
					        env:
 | 
				
			||||||
 | 
					          GH_REL_URL: https://github.com/buchanae/github-release-notes/releases/download/0.2.0/github-release-notes-linux-amd64-0.2.0.tar.gz
 | 
				
			||||||
 | 
					        run: cd /tmp && curl -sSL ${GH_REL_URL} | tar xz && sudo mv github-release-notes /usr/local/bin/
 | 
				
			||||||
 | 
					      - name: Generate release notes
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          echo 'CHANGELOG' > /tmp/release.txt
 | 
				
			||||||
 | 
					          github-release-notes -org fluxcd -repo toolkit -since-latest-release >> /tmp/release.txt
 | 
				
			||||||
 | 
					      - name: Run GoReleaser
 | 
				
			||||||
 | 
					        uses: goreleaser/goreleaser-action@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          version: latest
 | 
				
			||||||
 | 
					          args: release --release-notes=/tmp/release.txt
 | 
				
			||||||
 | 
					        env:
 | 
				
			||||||
 | 
					          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					builds:
 | 
				
			||||||
 | 
					  - main: ./cmd/tk
 | 
				
			||||||
 | 
					    binary: tk
 | 
				
			||||||
 | 
					    goos:
 | 
				
			||||||
 | 
					      - darwin
 | 
				
			||||||
 | 
					      - linux
 | 
				
			||||||
 | 
					    goarch:
 | 
				
			||||||
 | 
					      - amd64
 | 
				
			||||||
 | 
					    env:
 | 
				
			||||||
 | 
					      - CGO_ENABLED=0
 | 
				
			||||||
 | 
					archives:
 | 
				
			||||||
 | 
					  - name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
 | 
				
			||||||
 | 
					    files:
 | 
				
			||||||
 | 
					      - none*
 | 
				
			||||||
@ -1,2 +1,9 @@
 | 
				
			|||||||
# toolkit
 | 
					# toolkit
 | 
				
			||||||
Experimental toolkit for assembling CD pipelines
 | 
					
 | 
				
			||||||
 | 
					[](https://github.com/fluxcd/toolkit/actions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Experimental toolkit for assembling CD pipelines.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Components:
 | 
				
			||||||
 | 
					* [source-controller](https://github.com/fluxcd/source-controller)
 | 
				
			||||||
 | 
					* [kustomize-controller](https://github.com/fluxcd/kustomize-controller)
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var createCmd = &cobra.Command{
 | 
				
			||||||
 | 
						Use:   "create",
 | 
				
			||||||
 | 
						Short: "Create commands",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						interval string
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						createCmd.PersistentFlags().StringVar(&interval, "interval", "1m", "source sync interval")
 | 
				
			||||||
 | 
						rootCmd.AddCommand(createCmd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,236 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"text/template"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/manifoldco/promptui"
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var createSourceCmd = &cobra.Command{
 | 
				
			||||||
 | 
						Use:   "source [name]",
 | 
				
			||||||
 | 
						Short: "Create source resource",
 | 
				
			||||||
 | 
						Long: `
 | 
				
			||||||
 | 
					The create source command generates a source.fluxcd.io resource and waits for it to sync.
 | 
				
			||||||
 | 
					For Git over SSH, host and SSH keys are automatically generated.`,
 | 
				
			||||||
 | 
						Example: `  # Create a gitrepository.source.fluxcd.io for a public repository
 | 
				
			||||||
 | 
					  create source podinfo --git-url https://github.com/stefanprodan/podinfo-deploy --git-branch master
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create a gitrepository.source.fluxcd.io that syncs tags based on a semver range
 | 
				
			||||||
 | 
					  create source podinfo --git-url https://github.com/stefanprodan/podinfo-deploy  --git-semver=">=0.0.1-rc.1 <0.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create a gitrepository.source.fluxcd.io with SSH authentication
 | 
				
			||||||
 | 
					  create source podinfo --git-url ssh://git@github.com/stefanprodan/podinfo-deploy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create a gitrepository.source.fluxcd.io with basic authentication
 | 
				
			||||||
 | 
					  create source podinfo --git-url https://github.com/stefanprodan/podinfo-deploy -u username -p password
 | 
				
			||||||
 | 
					`,
 | 
				
			||||||
 | 
						RunE: createSourceCmdRun,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						sourceGitURL    string
 | 
				
			||||||
 | 
						sourceGitBranch string
 | 
				
			||||||
 | 
						sourceGitSemver string
 | 
				
			||||||
 | 
						sourceUsername  string
 | 
				
			||||||
 | 
						sourcePassword  string
 | 
				
			||||||
 | 
						sourceVerbose   bool
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						createSourceCmd.Flags().StringVar(&sourceGitURL, "git-url", "", "git address, e.g. ssh://git@host/org/repository")
 | 
				
			||||||
 | 
						createSourceCmd.Flags().StringVar(&sourceGitBranch, "git-branch", "master", "git branch")
 | 
				
			||||||
 | 
						createSourceCmd.Flags().StringVar(&sourceGitSemver, "git-semver", "", "git tag semver range")
 | 
				
			||||||
 | 
						createSourceCmd.Flags().StringVarP(&sourceUsername, "username", "u", "", "basic authentication username")
 | 
				
			||||||
 | 
						createSourceCmd.Flags().StringVarP(&sourcePassword, "password", "p", "", "basic authentication password")
 | 
				
			||||||
 | 
						createSourceCmd.Flags().BoolVarP(&sourceVerbose, "verbose", "", false, "print generated source object")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						createCmd.AddCommand(createSourceCmd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createSourceCmdRun(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
						if len(args) < 1 {
 | 
				
			||||||
 | 
							return fmt.Errorf("source name is required")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						name := args[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if sourceGitURL == "" {
 | 
				
			||||||
 | 
							return fmt.Errorf("git-url is required")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmpDir, err := ioutil.TempDir("", name)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(tmpDir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u, err := url.Parse(sourceGitURL)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("git URL parse failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx, cancel := context.WithTimeout(context.Background(), timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						withAuth := false
 | 
				
			||||||
 | 
						if strings.HasPrefix(sourceGitURL, "ssh") {
 | 
				
			||||||
 | 
							if err := generateSSH(name, u.Host, tmpDir); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							withAuth = true
 | 
				
			||||||
 | 
						} else if sourceUsername != "" && sourcePassword != "" {
 | 
				
			||||||
 | 
							if err := generateBasicAuth(name); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							withAuth = true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("generating source %s in %s namespace", name, namespace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t, err := template.New("tmpl").Parse(gitSource)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("template parse error: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						source := struct {
 | 
				
			||||||
 | 
							Name      string
 | 
				
			||||||
 | 
							Namespace string
 | 
				
			||||||
 | 
							URL       string
 | 
				
			||||||
 | 
							Branch    string
 | 
				
			||||||
 | 
							Semver    string
 | 
				
			||||||
 | 
							Interval  string
 | 
				
			||||||
 | 
							WithAuth  bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							Name:      name,
 | 
				
			||||||
 | 
							Namespace: namespace,
 | 
				
			||||||
 | 
							URL:       sourceGitURL,
 | 
				
			||||||
 | 
							Branch:    sourceGitBranch,
 | 
				
			||||||
 | 
							Semver:    sourceGitSemver,
 | 
				
			||||||
 | 
							Interval:  interval,
 | 
				
			||||||
 | 
							WithAuth:  withAuth,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var data bytes.Buffer
 | 
				
			||||||
 | 
						writer := bufio.NewWriter(&data)
 | 
				
			||||||
 | 
						if err := t.Execute(writer, source); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("template execution failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := writer.Flush(); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("source flush failed: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if sourceVerbose {
 | 
				
			||||||
 | 
							fmt.Print(data.String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						command := fmt.Sprintf("echo '%s' | kubectl apply -f-", data.String())
 | 
				
			||||||
 | 
						c := exec.CommandContext(ctx, "/bin/sh", "-c", command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var stdoutBuf, stderrBuf bytes.Buffer
 | 
				
			||||||
 | 
						c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
 | 
				
			||||||
 | 
						c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = c.Run()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("source apply failed")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("waiting for source sync")
 | 
				
			||||||
 | 
						if output, err := execCommand(fmt.Sprintf(
 | 
				
			||||||
 | 
							"kubectl -n %s wait gitrepository/%s --for=condition=ready --timeout=1m",
 | 
				
			||||||
 | 
							namespace, name)); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("source sync failed: %s", output)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							fmt.Print(output)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generateBasicAuth(name string) error {
 | 
				
			||||||
 | 
						logAction("saving credentials")
 | 
				
			||||||
 | 
						credentials := fmt.Sprintf("--from-literal=username='%s' --from-literal=password='%s'",
 | 
				
			||||||
 | 
							sourceUsername, sourcePassword)
 | 
				
			||||||
 | 
						secret := fmt.Sprintf("kubectl -n %s create secret generic %s %s --dry-run=client -oyaml | kubectl apply -f-",
 | 
				
			||||||
 | 
							namespace, name, credentials)
 | 
				
			||||||
 | 
						if output, err := execCommand(secret); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("kubectl create secret failed: %s", output)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							fmt.Print(output)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generateSSH(name, host, tmpDir string) error {
 | 
				
			||||||
 | 
						logAction("generating host key for %s", host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keyscan := fmt.Sprintf("ssh-keyscan %s > %s/known_hosts", host, tmpDir)
 | 
				
			||||||
 | 
						if output, err := execCommand(keyscan); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("ssh-keyscan failed: %s", output)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("generating deploy key")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keygen := fmt.Sprintf("ssh-keygen -b 2048 -t rsa -f %s/identity -q -N \"\"", tmpDir)
 | 
				
			||||||
 | 
						if output, err := execCommand(keygen); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("ssh-keygen failed: %s", output)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						deployKey, err := execCommand(fmt.Sprintf("cat %s/identity.pub", tmpDir))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("unable to read identity.pub: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fmt.Print(deployKey)
 | 
				
			||||||
 | 
						prompt := promptui.Prompt{
 | 
				
			||||||
 | 
							Label:     "Have you added the deploy key to your repository",
 | 
				
			||||||
 | 
							IsConfirm: true,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := prompt.Run(); err != nil {
 | 
				
			||||||
 | 
							logFailure("aborting")
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("saving deploy key")
 | 
				
			||||||
 | 
						files := fmt.Sprintf("--from-file=%s/identity --from-file=%s/identity.pub --from-file=%s/known_hosts",
 | 
				
			||||||
 | 
							tmpDir, tmpDir, tmpDir)
 | 
				
			||||||
 | 
						secret := fmt.Sprintf("kubectl -n %s create secret generic %s %s --dry-run=client -oyaml | kubectl apply -f-",
 | 
				
			||||||
 | 
							namespace, name, files)
 | 
				
			||||||
 | 
						if output, err := execCommand(secret); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("kubectl create secret failed: %s", output)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							fmt.Print(output)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var gitSource = `---
 | 
				
			||||||
 | 
					apiVersion: source.fluxcd.io/v1alpha1
 | 
				
			||||||
 | 
					kind: GitRepository
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: {{.Name}}
 | 
				
			||||||
 | 
					  namespace: {{.Namespace}}
 | 
				
			||||||
 | 
					spec:
 | 
				
			||||||
 | 
					  interval: {{.Interval}}
 | 
				
			||||||
 | 
					  url: {{.URL}}
 | 
				
			||||||
 | 
					  ref:
 | 
				
			||||||
 | 
					{{- if .Semver }}
 | 
				
			||||||
 | 
					    semver: "{{.Semver}}"
 | 
				
			||||||
 | 
					{{- else }}
 | 
				
			||||||
 | 
					    branch: {{.Branch}}
 | 
				
			||||||
 | 
					{{- end }}
 | 
				
			||||||
 | 
					{{- if .WithAuth }}
 | 
				
			||||||
 | 
					  secretRef:
 | 
				
			||||||
 | 
					    name: {{.Name}}
 | 
				
			||||||
 | 
					{{- end }}
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var installCmd = &cobra.Command{
 | 
				
			||||||
 | 
						Use:   "install",
 | 
				
			||||||
 | 
						Short: "Install the toolkit components",
 | 
				
			||||||
 | 
						Long: `
 | 
				
			||||||
 | 
					The Install command deploys the toolkit components
 | 
				
			||||||
 | 
					on the configured Kubernetes cluster in ~/.kube/config`,
 | 
				
			||||||
 | 
						Example: `  install --manifests github.com/fluxcd/toolkit//manifests/install --dry-run`,
 | 
				
			||||||
 | 
						RunE:    installCmdRun,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						installDryRun        bool
 | 
				
			||||||
 | 
						installManifestsPath string
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						installCmd.Flags().BoolVarP(&installDryRun, "dry-run", "", false,
 | 
				
			||||||
 | 
							"only print the object that would be applied")
 | 
				
			||||||
 | 
						installCmd.Flags().StringVarP(&installManifestsPath, "manifests", "", "",
 | 
				
			||||||
 | 
							"path to the manifest directory")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rootCmd.AddCommand(installCmd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func installCmdRun(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
						if installManifestsPath == "" {
 | 
				
			||||||
 | 
							return fmt.Errorf("no manifests specified")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !strings.HasPrefix(installManifestsPath, "github.com/") {
 | 
				
			||||||
 | 
							if _, err := os.Stat(installManifestsPath); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("manifests not found: %w", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx, cancel := context.WithTimeout(context.Background(), timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dryRun := ""
 | 
				
			||||||
 | 
						if installDryRun {
 | 
				
			||||||
 | 
							dryRun = "--dry-run=client"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						command := fmt.Sprintf("kustomize build %s | kubectl apply -f- %s",
 | 
				
			||||||
 | 
							installManifestsPath, dryRun)
 | 
				
			||||||
 | 
						c := exec.CommandContext(ctx, "/bin/sh", "-c", command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var stdoutBuf, stderrBuf bytes.Buffer
 | 
				
			||||||
 | 
						c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
 | 
				
			||||||
 | 
						c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("installing components in %s namespace", namespace)
 | 
				
			||||||
 | 
						err := c.Run()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logFailure("install failed")
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if installDryRun {
 | 
				
			||||||
 | 
							logSuccess("install dry-run finished")
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("verifying installation")
 | 
				
			||||||
 | 
						for _, deployment := range []string{"source-controller", "kustomize-controller"} {
 | 
				
			||||||
 | 
							command = fmt.Sprintf("kubectl -n %s rollout status deployment %s --timeout=%s",
 | 
				
			||||||
 | 
								namespace, deployment, timeout.String())
 | 
				
			||||||
 | 
							c = exec.CommandContext(ctx, "/bin/sh", "-c", command)
 | 
				
			||||||
 | 
							c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
 | 
				
			||||||
 | 
							c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 | 
				
			||||||
 | 
							err := c.Run()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logFailure("install failed")
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logSuccess("install finished")
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/manifoldco/promptui"
 | 
				
			||||||
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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`,
 | 
				
			||||||
 | 
						Example: `  uninstall --namespace=gitops-system --crds --dry-run`,
 | 
				
			||||||
 | 
						RunE:    uninstallCmdRun,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						uninstallCRDs   bool
 | 
				
			||||||
 | 
						uninstallDryRun bool
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						uninstallCmd.Flags().BoolVarP(&uninstallCRDs, "crds", "", false,
 | 
				
			||||||
 | 
							"removes all CRDs previously installed")
 | 
				
			||||||
 | 
						uninstallCmd.Flags().BoolVarP(&uninstallDryRun, "dry-run", "", false,
 | 
				
			||||||
 | 
							"only print the object that would be deleted")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rootCmd.AddCommand(uninstallCmd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func uninstallCmdRun(cmd *cobra.Command, args []string) error {
 | 
				
			||||||
 | 
						ctx, cancel := context.WithTimeout(context.Background(), timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dryRun := ""
 | 
				
			||||||
 | 
						if uninstallDryRun {
 | 
				
			||||||
 | 
							dryRun = "--dry-run=client"
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							prompt := promptui.Prompt{
 | 
				
			||||||
 | 
								Label:     fmt.Sprintf("Are you sure you want to delete the %s namespace", namespace),
 | 
				
			||||||
 | 
								IsConfirm: true,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := prompt.Run(); err != nil {
 | 
				
			||||||
 | 
								logFailure("aborting")
 | 
				
			||||||
 | 
								os.Exit(1)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kinds := "namespace,clusterroles,clusterrolebindings"
 | 
				
			||||||
 | 
						if uninstallCRDs {
 | 
				
			||||||
 | 
							kinds += ",crds"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						command := fmt.Sprintf("kubectl delete %s -l app.kubernetes.io/instance=%s --timeout=%s %s",
 | 
				
			||||||
 | 
							kinds, namespace, timeout.String(), dryRun)
 | 
				
			||||||
 | 
						c := exec.CommandContext(ctx, "/bin/sh", "-c", command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var stdoutBuf, stderrBuf bytes.Buffer
 | 
				
			||||||
 | 
						c.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf)
 | 
				
			||||||
 | 
						c.Stderr = io.MultiWriter(os.Stderr, &stderrBuf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logAction("uninstalling components")
 | 
				
			||||||
 | 
						err := c.Run()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logFailure("uninstall failed")
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logSuccess("uninstall finished")
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					apiVersion: kustomize.config.k8s.io/v1beta1
 | 
				
			||||||
 | 
					kind: Kustomization
 | 
				
			||||||
 | 
					resources:
 | 
				
			||||||
 | 
					- github.com/fluxcd/kustomize-controller/config//crd?ref=v0.0.1-alpha.4
 | 
				
			||||||
 | 
					- github.com/fluxcd/kustomize-controller/config//manager?ref=v0.0.1-alpha.4
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					apiVersion: kustomize.config.k8s.io/v1beta1
 | 
				
			||||||
 | 
					kind: Kustomization
 | 
				
			||||||
 | 
					resources:
 | 
				
			||||||
 | 
					- github.com/fluxcd/source-controller/config//crd?ref=v0.0.1-alpha.2
 | 
				
			||||||
 | 
					- github.com/fluxcd/source-controller/config//manager?ref=v0.0.1-alpha.2
 | 
				
			||||||
@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					apiVersion: kustomize.config.k8s.io/v1beta1
 | 
				
			||||||
 | 
					kind: Kustomization
 | 
				
			||||||
 | 
					namespace: gitops-system
 | 
				
			||||||
 | 
					resources:
 | 
				
			||||||
 | 
					  - namespace.yaml
 | 
				
			||||||
 | 
					  - ../bases/source-controller
 | 
				
			||||||
 | 
					  - ../bases/kustomize-controller
 | 
				
			||||||
 | 
					  - ../rbac
 | 
				
			||||||
 | 
					  - ../policies
 | 
				
			||||||
 | 
					transformers:
 | 
				
			||||||
 | 
					  - labels.yaml
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					apiVersion: builtin
 | 
				
			||||||
 | 
					kind: LabelTransformer
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: labels
 | 
				
			||||||
 | 
					labels:
 | 
				
			||||||
 | 
					  app.kubernetes.io/instance: gitops-system
 | 
				
			||||||
 | 
					fieldSpecs:
 | 
				
			||||||
 | 
					  - path: metadata/labels
 | 
				
			||||||
 | 
					    create: true
 | 
				
			||||||
@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					apiVersion: v1
 | 
				
			||||||
 | 
					kind: Namespace
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: gitops-system
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					apiVersion: networking.k8s.io/v1
 | 
				
			||||||
 | 
					kind: NetworkPolicy
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: deny-ingress
 | 
				
			||||||
 | 
					spec:
 | 
				
			||||||
 | 
					  podSelector: {}
 | 
				
			||||||
 | 
					  policyTypes:
 | 
				
			||||||
 | 
					    - Ingress
 | 
				
			||||||
@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					apiVersion: kustomize.config.k8s.io/v1beta1
 | 
				
			||||||
 | 
					kind: Kustomization
 | 
				
			||||||
 | 
					resources:
 | 
				
			||||||
 | 
					  - deny-ingress.yaml
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					apiVersion: rbac.authorization.k8s.io/v1
 | 
				
			||||||
 | 
					kind: ClusterRole
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: cluster-reconciler
 | 
				
			||||||
 | 
					rules:
 | 
				
			||||||
 | 
					  - apiGroups: ['*']
 | 
				
			||||||
 | 
					    resources: ['*']
 | 
				
			||||||
 | 
					    verbs: ['*']
 | 
				
			||||||
 | 
					  - nonResourceURLs: ['*']
 | 
				
			||||||
 | 
					    verbs: ['*']
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					apiVersion: rbac.authorization.k8s.io/v1
 | 
				
			||||||
 | 
					kind: ClusterRoleBinding
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: cluster-reconciler
 | 
				
			||||||
 | 
					roleRef:
 | 
				
			||||||
 | 
					  apiGroup: rbac.authorization.k8s.io
 | 
				
			||||||
 | 
					  kind: ClusterRole
 | 
				
			||||||
 | 
					  name: cluster-reconciler
 | 
				
			||||||
 | 
					subjects:
 | 
				
			||||||
 | 
					  - kind: ServiceAccount
 | 
				
			||||||
 | 
					    name: default
 | 
				
			||||||
 | 
					    namespace: system
 | 
				
			||||||
@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					apiVersion: kustomize.config.k8s.io/v1beta1
 | 
				
			||||||
 | 
					kind: Kustomization
 | 
				
			||||||
 | 
					resources:
 | 
				
			||||||
 | 
					  - cluster_role.yaml
 | 
				
			||||||
 | 
					  - role.yaml
 | 
				
			||||||
@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					apiVersion: rbac.authorization.k8s.io/v1
 | 
				
			||||||
 | 
					kind: Role
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: crd-controller
 | 
				
			||||||
 | 
					rules:
 | 
				
			||||||
 | 
					- apiGroups: ['source.fluxcd.io']
 | 
				
			||||||
 | 
					  resources: ['*']
 | 
				
			||||||
 | 
					  verbs: ['*']
 | 
				
			||||||
 | 
					- apiGroups: ['kustomize.fluxcd.io']
 | 
				
			||||||
 | 
					  resources: ['*']
 | 
				
			||||||
 | 
					  verbs: ['*']
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					apiVersion: rbac.authorization.k8s.io/v1
 | 
				
			||||||
 | 
					kind: RoleBinding
 | 
				
			||||||
 | 
					metadata:
 | 
				
			||||||
 | 
					  name: crd-controller
 | 
				
			||||||
 | 
					roleRef:
 | 
				
			||||||
 | 
					  apiGroup: rbac.authorization.k8s.io
 | 
				
			||||||
 | 
					  kind: Role
 | 
				
			||||||
 | 
					  name: crd-controller
 | 
				
			||||||
 | 
					subjects:
 | 
				
			||||||
 | 
					  - kind: ServiceAccount
 | 
				
			||||||
 | 
					    name: default
 | 
				
			||||||
 | 
					    namespace: system
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue