From f127adc8ea49f47d4e60a4fc4824c0f8c69d81d2 Mon Sep 17 00:00:00 2001 From: stefanprodan Date: Thu, 30 Apr 2020 00:12:16 +0300 Subject: [PATCH] Implement export to YAML - add export commands for git sources and kustomizations - add export e2e tests --- .github/workflows/e2e.yaml | 4 ++ cmd/tk/delete_source_git.go | 2 +- cmd/tk/export.go | 20 ++++++++ cmd/tk/export_kustomization.go | 94 ++++++++++++++++++++++++++++++++++ cmd/tk/export_source.go | 14 +++++ cmd/tk/export_source_git.go | 93 +++++++++++++++++++++++++++++++++ cmd/tk/main.go | 6 +++ go.mod | 1 + 8 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 cmd/tk/export.go create mode 100644 cmd/tk/export_kustomization.go create mode 100644 cmd/tk/export_source.go create mode 100644 cmd/tk/export_source_git.go diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 004f731f..42e9e6eb 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -80,6 +80,10 @@ jobs: - name: tk resume kustomization run: | ./bin/tk resume kustomization podinfo + - name: tk export + run: | + ./bin/tk export source git --all + ./bin/tk export kustomization --all - name: tk delete kustomization run: | ./bin/tk delete kustomization podinfo --silent diff --git a/cmd/tk/delete_source_git.go b/cmd/tk/delete_source_git.go index ea9fb5a1..9ff9bb39 100644 --- a/cmd/tk/delete_source_git.go +++ b/cmd/tk/delete_source_git.go @@ -3,8 +3,8 @@ package main import ( "context" "fmt" - sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" "github.com/manifoldco/promptui" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/types" diff --git a/cmd/tk/export.go b/cmd/tk/export.go new file mode 100644 index 00000000..55aebbec --- /dev/null +++ b/cmd/tk/export.go @@ -0,0 +1,20 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +var exportCmd = &cobra.Command{ + Use: "export", + Short: "Export commands", +} + +var ( + exportAll bool +) + +func init() { + exportCmd.PersistentFlags().BoolVar(&exportAll, "all", false, "select all resources") + + rootCmd.AddCommand(exportCmd) +} diff --git a/cmd/tk/export_kustomization.go b/cmd/tk/export_kustomization.go new file mode 100644 index 00000000..b100297d --- /dev/null +++ b/cmd/tk/export_kustomization.go @@ -0,0 +1,94 @@ +package main + +import ( + "context" + "fmt" + + kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1alpha1" + "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" +) + +var exportKsCmd = &cobra.Command{ + Use: "kustomization [name]", + Aliases: []string{"ks"}, + Short: "Export kustomization in YAML format", + RunE: exportKsCmdRun, +} + +func init() { + exportCmd.AddCommand(exportKsCmd) +} + +func exportKsCmdRun(cmd *cobra.Command, args []string) error { + if !exportAll && len(args) < 1 { + return fmt.Errorf("kustomization 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 kustomizev1.KustomizationList + err = kubeClient.List(ctx, &list, client.InNamespace(namespace)) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logFailure("no kustomizations found in %s namespace", namespace) + return nil + } + + for _, kustomization := range list.Items { + if err := exportKs(kustomization); err != nil { + return err + } + } + } else { + name := args[0] + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var kustomization kustomizev1.Kustomization + err = kubeClient.Get(ctx, namespacedName, &kustomization) + if err != nil { + return err + } + return exportKs(kustomization) + } + return nil +} + +func exportKs(kustomization kustomizev1.Kustomization) error { + gvk := kustomizev1.GroupVersion.WithKind("Kustomization") + export := kustomizev1.Kustomization{ + TypeMeta: metav1.TypeMeta{ + Kind: gvk.Kind, + APIVersion: gvk.GroupVersion().String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: kustomization.Name, + Namespace: kustomization.Namespace, + }, + Spec: kustomization.Spec, + } + + data, err := yaml.Marshal(export) + if err != nil { + return err + } + + fmt.Println("---") + fmt.Println(string(data)) + return nil +} diff --git a/cmd/tk/export_source.go b/cmd/tk/export_source.go new file mode 100644 index 00000000..9412d16b --- /dev/null +++ b/cmd/tk/export_source.go @@ -0,0 +1,14 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +var exportSourceCmd = &cobra.Command{ + Use: "source", + Short: "Export source commands", +} + +func init() { + exportCmd.AddCommand(exportSourceCmd) +} diff --git a/cmd/tk/export_source_git.go b/cmd/tk/export_source_git.go new file mode 100644 index 00000000..18facc57 --- /dev/null +++ b/cmd/tk/export_source_git.go @@ -0,0 +1,93 @@ +package main + +import ( + "context" + "fmt" + + sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1" + "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" +) + +var exportSourceGitCmd = &cobra.Command{ + Use: "git [name]", + Short: "Export git source in YAML format", + RunE: exportSourceGitCmdRun, +} + +func init() { + exportSourceCmd.AddCommand(exportSourceGitCmd) +} + +func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error { + if !exportAll && len(args) < 1 { + return fmt.Errorf("kustomization 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.GitRepositoryList + err = kubeClient.List(ctx, &list, client.InNamespace(namespace)) + if err != nil { + return err + } + + if len(list.Items) == 0 { + logFailure("no source found in %s namespace", namespace) + return nil + } + + for _, repository := range list.Items { + if err := exportGit(repository); err != nil { + return err + } + } + } else { + name := args[0] + namespacedName := types.NamespacedName{ + Namespace: namespace, + Name: name, + } + var repository sourcev1.GitRepository + err = kubeClient.Get(ctx, namespacedName, &repository) + if err != nil { + return err + } + return exportGit(repository) + } + return nil +} + +func exportGit(source sourcev1.GitRepository) error { + gvk := sourcev1.GroupVersion.WithKind("GitRepository") + export := sourcev1.GitRepository{ + 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 +} diff --git a/cmd/tk/main.go b/cmd/tk/main.go index 5ea1f48b..cedadbd1 100644 --- a/cmd/tk/main.go +++ b/cmd/tk/main.go @@ -38,6 +38,9 @@ var rootCmd = &cobra.Command{ # Trigger a git sync tk sync source git webapp-latest + # Export git sources in YAML format + tk export source git --all > sources.yaml + # Create a kustomization for deploying a series of microservices tk create kustomization webapp-dev \ --source=webapp-latest \ @@ -56,6 +59,9 @@ var rootCmd = &cobra.Command{ # Suspend a kustomization reconciliation tk suspend kustomization webapp-dev + # Export kustomizations in YAML format + tk export kustomization --all > kustomizations.yaml + # Resume a kustomization reconciliation tk resume kustomization webapp-dev diff --git a/go.mod b/go.mod index e5d8063a..867428c3 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( k8s.io/apimachinery v0.18.2 k8s.io/client-go v0.18.2 sigs.k8s.io/controller-runtime v0.6.0 + sigs.k8s.io/yaml v1.2.0 ) // fix AKS auth