1
0
mirror of synced 2026-03-02 11:36:56 +00:00

Compare commits

...

8 Commits

Author SHA1 Message Date
Stefan Prodan
62e4b03342 Merge pull request #40 from fluxcd/gh-deploy-key
Rotate GitHub deploy key during bootstrap
2020-06-15 10:25:37 +03:00
stefanprodan
dca7b0ba91 Recreate GitHub deploy key during bootstrap 2020-06-12 18:05:00 +03:00
Stefan Prodan
2a61befbfd Merge pull request #39 from fluxcd/bootstrap-path
Add target path to the bootstrap cmd
2020-06-12 16:11:09 +03:00
Stefan Prodan
287be26190 Merge pull request #38 from fluxcd/uninstall-ks
Add kustomizations removal to uninstall cmd
2020-06-12 15:59:42 +03:00
stefanprodan
4992e11383 Add target path to the bootstrap cmd 2020-06-12 15:57:34 +03:00
stefanprodan
727734850e Add kustomizations removal to uninstall cmd 2020-06-10 18:49:38 +03:00
Hidde Beydals
e042d25062 Merge pull request #37 from fluxcd/go-license
Add Go license to forked package
2020-06-10 12:19:14 +02:00
Hidde Beydals
ba7a11d0e5 Add Go license to forked package 2020-06-10 12:10:04 +02:00
3 changed files with 123 additions and 30 deletions

View File

@@ -43,6 +43,9 @@ the bootstrap command will perform an upgrade if needed.`,
# Run bootstrap for a private repo owned by a GitHub organization
bootstrap github --owner=<organization> --repository=<repo name>
# Run bootstrap for a repository path
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
@@ -59,12 +62,13 @@ var (
ghPersonal bool
ghPrivate bool
ghHostname string
ghPath string
)
const (
ghTokenName = "GITHUB_TOKEN"
ghBranch = "master"
ghInstallManifest = "toolkit.yaml"
ghInstallManifest = "toolkit-components.yaml"
ghSourceManifest = "toolkit-source.yaml"
ghKustomizationManifest = "toolkit-kustomization.yaml"
ghDefaultHostname = "github.com"
@@ -77,6 +81,8 @@ func init() {
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(&ghPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
bootstrapCmd.AddCommand(bootstrapGitHubCmd)
}
@@ -121,13 +127,13 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// generate install manifests
logGenerate("generating manifests")
manifest, err := generateGitHubInstall(namespace, tmpDir)
manifest, err := generateGitHubInstall(ghPath, namespace, tmpDir)
if err != nil {
return err
}
// stage install manifests
changed, err := commitGitHubManifests(repo, namespace)
changed, err := commitGitHubManifests(repo, ghPath, namespace)
if err != nil {
return err
}
@@ -180,7 +186,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("generating deploy key failed: %w", err)
}
if err := createGitHubDeployKey(ctx, key, ghHostname, ghOwner, ghRepository, ghToken, ghPersonal); err != nil {
if err := createGitHubDeployKey(ctx, key, ghHostname, ghOwner, ghRepository, ghPath, ghToken); err != nil {
return err
}
logSuccess("deploy key configured")
@@ -190,12 +196,12 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
if isInstall {
// generate source and kustomization manifests
logAction("generating sync manifests")
if err := generateGitHubKustomization(sshURL, namespace, namespace, tmpDir, ghInterval); err != nil {
if err := generateGitHubKustomization(sshURL, namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
return err
}
// stage manifests
changed, err = commitGitHubManifests(repo, namespace)
changed, err = commitGitHubManifests(repo, ghPath, namespace)
if err != nil {
return err
}
@@ -210,7 +216,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
// apply manifests and waiting for sync
logAction("applying sync manifests")
if err := applyGitHubKustomization(ctx, kubeClient, namespace, namespace, tmpDir); err != nil {
if err := applyGitHubKustomization(ctx, kubeClient, namespace, namespace, ghPath, tmpDir); err != nil {
return err
}
}
@@ -296,7 +302,7 @@ func checkoutGitHubRepository(ctx context.Context, url, branch, token, path stri
return repo, nil
}
func generateGitHubInstall(namespace, tmpDir string) (string, error) {
func generateGitHubInstall(targetPath, namespace, tmpDir string) (string, error) {
tkDir := path.Join(tmpDir, ".tk")
defer os.RemoveAll(tkDir)
@@ -308,7 +314,7 @@ func generateGitHubInstall(namespace, tmpDir string) (string, error) {
return "", fmt.Errorf("generating manifests failed: %w", err)
}
manifestsDir := path.Join(tmpDir, namespace)
manifestsDir := path.Join(tmpDir, targetPath, namespace)
if err := os.MkdirAll(manifestsDir, os.ModePerm); err != nil {
return "", fmt.Errorf("generating manifests failed: %w", err)
}
@@ -321,13 +327,13 @@ func generateGitHubInstall(namespace, tmpDir string) (string, error) {
return manifest, nil
}
func commitGitHubManifests(repo *git.Repository, namespace string) (bool, error) {
func commitGitHubManifests(repo *git.Repository, targetPath, namespace string) (bool, error) {
w, err := repo.Worktree()
if err != nil {
return false, err
}
_, err = w.Add(namespace)
_, err = w.Add(path.Join(targetPath, namespace))
if err != nil {
return false, err
}
@@ -368,7 +374,7 @@ func pushGitHubRepository(ctx context.Context, repo *git.Repository, token strin
return nil
}
func generateGitHubKustomization(url, name, namespace, tmpDir string, interval time.Duration) error {
func generateGitHubKustomization(url, name, namespace, targetPath, tmpDir string, interval time.Duration) error {
gvk := sourcev1.GroupVersion.WithKind("GitRepository")
gitRepository := sourcev1.GitRepository{
TypeMeta: metav1.TypeMeta{
@@ -398,7 +404,7 @@ func generateGitHubKustomization(url, name, namespace, tmpDir string, interval t
return err
}
if err := utils.writeFile(string(gitData), filepath.Join(tmpDir, namespace, ghSourceManifest)); err != nil {
if err := utils.writeFile(string(gitData), filepath.Join(tmpDir, targetPath, namespace, ghSourceManifest)); err != nil {
return err
}
@@ -417,7 +423,7 @@ func generateGitHubKustomization(url, name, namespace, tmpDir string, interval t
Interval: metav1.Duration{
Duration: 10 * time.Minute,
},
Path: "./",
Path: "./" + strings.TrimPrefix("./", targetPath),
Prune: true,
SourceRef: corev1.TypedLocalObjectReference{
APIGroup: &emptyAPIGroup,
@@ -432,15 +438,15 @@ func generateGitHubKustomization(url, name, namespace, tmpDir string, interval t
return err
}
if err := utils.writeFile(string(ksData), filepath.Join(tmpDir, namespace, ghKustomizationManifest)); err != nil {
if err := utils.writeFile(string(ksData), filepath.Join(tmpDir, targetPath, 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))
func applyGitHubKustomization(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
}
@@ -515,20 +521,62 @@ func generateGitHubDeployKey(ctx context.Context, kubeClient client.Client, url
return string(pair.PublicKey), nil
}
func createGitHubDeployKey(ctx context.Context, key, hostname, owner, name, token string, isPersonal bool) error {
func createGitHubDeployKey(ctx context.Context, key, hostname, owner, repository, targetPath, token string) 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)
keyName := "tk"
if targetPath != "" {
keyName = fmt.Sprintf("tk-%s", targetPath)
}
// list deploy keys
keys, resp, err := gh.Repositories.ListKeys(ctx, owner, repository, nil)
if err != nil {
return fmt.Errorf("github list deploy keys error: %w", err)
}
if resp.StatusCode >= 300 {
return fmt.Errorf("github list deploy keys failed with status code: %s", resp.Status)
}
// check if the key exists
shouldCreateKey := true
var existingKey *github.Key
for _, k := range keys {
if k.Title != nil && k.Key != nil && *k.Title == keyName {
if *k.Key != key {
existingKey = k
} else {
shouldCreateKey = false
}
break
}
}
// delete existing key if the value differs
if existingKey != nil {
resp, err := gh.Repositories.DeleteKey(ctx, owner, repository, *existingKey.ID)
if err != nil {
return fmt.Errorf("github delete deploy key error: %w", err)
}
if resp.StatusCode >= 300 {
return fmt.Errorf("github delete deploy key failed with status code: %s", resp.Status)
}
}
// create key
if shouldCreateKey {
isReadOnly := true
_, _, err = gh.Repositories.CreateKey(ctx, owner, repository, &github.Key{
Title: &keyName,
Key: &key,
ReadOnly: &isReadOnly,
})
if err != nil {
return fmt.Errorf("github create deploy key error: %w", err)
}
}
return nil
}

View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"time"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
@@ -24,12 +25,15 @@ cluster role bindings and CRDs.`,
}
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,6 +61,20 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
}
}
if uninstallKustomizations {
logAction("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
logWaiting("waiting on GC")
time.Sleep(30 * time.Second)
}
kinds := "namespace,clusterroles,clusterrolebindings"
if uninstallCRDs {
kinds += ",crds"

View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.