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
 | 
			
		||||
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