diff --git a/pkg/cmd/get/clusters.go b/pkg/cmd/get/clusters.go index 6c3bac36..5c29d628 100644 --- a/pkg/cmd/get/clusters.go +++ b/pkg/cmd/get/clusters.go @@ -1,7 +1,6 @@ package get import ( - "bytes" "context" "fmt" "github.com/cnoe-io/idpbuilder/api/v1alpha1" @@ -14,7 +13,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/cli-runtime/pkg/printers" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/controller-runtime/pkg/client" @@ -74,9 +72,27 @@ func list(cmd *cobra.Command, args []string) error { if err != nil { return err } else { - // Convert the list of the clusters to Table of clusters - printTable(printers.PrintOptions{}, generateClusterTable(clusters)) - return nil + // Convert the list of the clusters to a Table of clusters and print the table using the format selected + err := printClustersOutput(clusters, outputFormat) + if err != nil { + return err + } else { + return nil + } + } +} + +func printClustersOutput(clusters []Cluster, format string) error { + switch format { + case "json": + return util.PrintDataAsJson(clusters) + case "yaml": + return util.PrintDataAsYaml(clusters) + case "": + return util.PrintTable(generateClusterTable(clusters)) + default: + + return fmt.Errorf("output format %s is not supported", format) } } @@ -232,18 +248,6 @@ func generateClusterTable(clusterTable []Cluster) metav1.Table { return *table } -func printTable(opts printers.PrintOptions, table metav1.Table) { - logger := helpers.CmdLogger - out := bytes.NewBuffer([]byte{}) - printer := printers.NewTablePrinter(opts) - err := printer.PrintObj(&table, out) - if err != nil { - logger.Error(err, "failed to print the table.") - return - } - fmt.Println(out.String()) -} - func generateNodeData(nodes []Node) string { var result string for i, aNode := range nodes { diff --git a/pkg/cmd/get/root.go b/pkg/cmd/get/root.go index c767b8c4..23ea8c15 100644 --- a/pkg/cmd/get/root.go +++ b/pkg/cmd/get/root.go @@ -22,7 +22,7 @@ func init() { GetCmd.AddCommand(ClustersCmd) GetCmd.AddCommand(SecretsCmd) GetCmd.PersistentFlags().StringSliceVarP(&packages, "packages", "p", []string{}, "names of packages.") - GetCmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "", "Output format. json or yaml.") + GetCmd.PersistentFlags().StringVarP(&outputFormat, "output", "o", "", "Output format. table or json.") GetCmd.PersistentFlags().StringVarP(&helpers.KubeConfigPath, "kubeconfig", "", "", "kube config file Path.") } diff --git a/pkg/cmd/get/secrets.go b/pkg/cmd/get/secrets.go index dc6d94c2..f9f2edab 100644 --- a/pkg/cmd/get/secrets.go +++ b/pkg/cmd/get/secrets.go @@ -2,13 +2,10 @@ package get import ( "context" - "embed" - "encoding/json" "fmt" - "io" - "os" + "github.com/cnoe-io/idpbuilder/pkg/util" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "path/filepath" - "text/template" "github.com/cnoe-io/idpbuilder/api/v1alpha1" "github.com/cnoe-io/idpbuilder/pkg/build" @@ -20,19 +17,14 @@ import ( "k8s.io/apimachinery/pkg/selection" "k8s.io/client-go/util/homedir" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" ) const ( - secretTemplatePath = "templates/secrets.tmpl" argoCDAdminUsername = "admin" argoCDInitialAdminSecretName = "argocd-initial-admin-secret" giteaAdminSecretName = "gitea-credential" ) -//go:embed templates -var templates embed.FS - var SecretsCmd = &cobra.Command{ Use: "secrets", Short: "retrieve secrets from the cluster", @@ -42,10 +34,12 @@ var SecretsCmd = &cobra.Command{ } // well known secrets that are part of the core packages -var corePkgSecrets = map[string][]string{ - "argocd": []string{argoCDInitialAdminSecretName}, - "gitea": []string{giteaAdminSecretName}, -} +var ( + corePkgSecrets = map[string][]string{ + "argocd": []string{argoCDInitialAdminSecretName}, + "gitea": []string{giteaAdminSecretName}, + } +) type TemplateData struct { Name string `json:"name"` @@ -53,6 +47,14 @@ type TemplateData struct { Data map[string]string `json:"data"` } +type Secret struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Username string `json:"username"` + Password string `json:"password"` + Token string `json:"token"` +} + func getSecretsE(cmd *cobra.Command, args []string) error { ctx, ctxCancel := context.WithCancel(cmd.Context()) defer ctxCancel() @@ -77,15 +79,15 @@ func getSecretsE(cmd *cobra.Command, args []string) error { } if len(packages) == 0 { - return printAllPackageSecrets(ctx, os.Stdout, kubeClient, outputFormat) + return printAllPackageSecrets(ctx, kubeClient, outputFormat) } - return printPackageSecrets(ctx, os.Stdout, kubeClient, outputFormat) + return printPackageSecrets(ctx, kubeClient, outputFormat) } -func printAllPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient client.Client, format string) error { +func printAllPackageSecrets(ctx context.Context, kubeClient client.Client, format string) error { selector := labels.NewSelector() - secretsToPrint := make([]any, 0, 2) + secrets := []Secret{} for k, v := range corePkgSecrets { for i := range v { @@ -96,29 +98,29 @@ func printAllPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient } return fmt.Errorf("getting secret %s in %s: %w", v[i], k, sErr) } - secretsToPrint = append(secretsToPrint, secretToTemplateData(secret)) + secrets = append(secrets, generateSecret(secret)) } } - secrets, err := getSecretsByCNOELabel(ctx, kubeClient, selector) + cnoeLabelSecrets, err := getSecretsByCNOELabel(ctx, kubeClient, selector) if err != nil { return fmt.Errorf("listing secrets: %w", err) } - for i := range secrets.Items { - secretsToPrint = append(secretsToPrint, secretToTemplateData(secrets.Items[i])) + for i := range cnoeLabelSecrets.Items { + secrets = append(secrets, generateSecret(cnoeLabelSecrets.Items[i])) } - if len(secretsToPrint) == 0 { + if len(secrets) == 0 { fmt.Println("no secrets found") return nil } - return printOutput(secretTemplatePath, outWriter, secretsToPrint, format) + return printSecretsOutput(secrets, format) } -func printPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient client.Client, format string) error { +func printPackageSecrets(ctx context.Context, kubeClient client.Client, format string) error { selector := labels.NewSelector() - secretsToPrint := make([]any, 0, 2) + secrets := []Secret{} for i := range packages { p := packages[i] @@ -132,7 +134,7 @@ func printPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient cl } return fmt.Errorf("getting secret %s in %s: %w", secretNames[j], p, sErr) } - secretsToPrint = append(secretsToPrint, secretToTemplateData(secret)) + secrets = append(secrets, generateSecret(secret)) } continue } @@ -144,69 +146,71 @@ func printPackageSecrets(ctx context.Context, outWriter io.Writer, kubeClient cl pkgSelector := selector.Add(*req) - secrets, pErr := getSecretsByCNOELabel(ctx, kubeClient, pkgSelector) - if pErr != nil { - return fmt.Errorf("listing secrets: %w", pErr) + cnoeLabelSecrets, err := getSecretsByCNOELabel(ctx, kubeClient, pkgSelector) + if err != nil { + return fmt.Errorf("listing secrets: %w", err) + } + + for i := range cnoeLabelSecrets.Items { + secrets = append(secrets, generateSecret(cnoeLabelSecrets.Items[i])) } - for j := range secrets.Items { - secretsToPrint = append(secretsToPrint, secretToTemplateData(secrets.Items[j])) + if len(secrets) == 0 { + fmt.Println("no secrets found") + return nil } } - return printOutput(secretTemplatePath, outWriter, secretsToPrint, format) + return printSecretsOutput(secrets, format) } -func renderTemplate(templatePath string, outWriter io.Writer, data []any) error { - tmpl, err := templates.ReadFile(templatePath) - if err != nil { - return fmt.Errorf("failed to read template: %w", err) - } - - t, err := template.New("secrets").Parse(string(tmpl)) - if err != nil { - return fmt.Errorf("parsing template: %w", err) - } - for i := range data { - tErr := t.Execute(outWriter, data[i]) - if tErr != nil { - return fmt.Errorf("executing template for data %s : %w", data[i], tErr) +func generateSecretTable(secretTable []Secret) metav1.Table { + table := &metav1.Table{} + table.ColumnDefinitions = []metav1.TableColumnDefinition{ + {Name: "Name", Type: "string"}, + {Name: "Namespace", Type: "string"}, + {Name: "Username", Type: "string"}, + {Name: "Password", Type: "string"}, + {Name: "Token", Type: "string"}, + } + for _, secret := range secretTable { + row := metav1.TableRow{ + Cells: []interface{}{ + secret.Name, + secret.Namespace, + secret.Username, + secret.Password, + secret.Token, + }, } + table.Rows = append(table.Rows, row) } - return nil + return *table } -func printOutput(templatePath string, outWriter io.Writer, data []any, format string) error { +func printSecretsOutput(secrets []Secret, format string) error { switch format { case "json": - enc := json.NewEncoder(outWriter) - enc.SetEscapeHTML(false) - enc.SetIndent("", " ") - return enc.Encode(data) + return util.PrintDataAsJson(secrets) case "yaml": - b, err := yaml.Marshal(data) - if err != nil { - return err - } - _, err = outWriter.Write(b) - return err + return util.PrintDataAsYaml(secrets) case "": - return renderTemplate(templatePath, outWriter, data) + return util.PrintTable(generateSecretTable(secrets)) default: + return fmt.Errorf("output format %s is not supported", format) } } -func secretToTemplateData(s v1.Secret) TemplateData { - data := TemplateData{ +func generateSecret(s v1.Secret) Secret { + secret := Secret{ Name: s.Name, Namespace: s.Namespace, - Data: make(map[string]string), - } - for k, v := range s.Data { - data.Data[k] = string(v) + Username: string(s.Data["username"]), + Password: string(s.Data["password"]), + Token: string(s.Data["token"]), } - return data + return secret } func getSecretsByCNOELabel(ctx context.Context, kubeClient client.Client, l labels.Selector) (v1.SecretList, error) { diff --git a/pkg/cmd/get/secrets_test.go b/pkg/cmd/get/secrets_test.go index 6bd3d0f0..83e7a23a 100644 --- a/pkg/cmd/get/secrets_test.go +++ b/pkg/cmd/get/secrets_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "io" "testing" "github.com/cnoe-io/idpbuilder/api/v1alpha1" @@ -97,7 +96,7 @@ func TestPrintPackageSecrets(t *testing.T) { fClient.On("Get", ctx, c.getKeys[j], mock.Anything, mock.Anything).Return(c.err) } - err := printPackageSecrets(ctx, io.Discard, fClient, "") + err := printPackageSecrets(ctx, fClient, "") fClient.AssertExpectations(t) assert.Nil(t, err) } @@ -134,7 +133,7 @@ func TestPrintAllPackageSecrets(t *testing.T) { for j := range c.getKeys { fClient.On("Get", ctx, c.getKeys[j], mock.Anything, mock.Anything).Return(c.err) } - err := printAllPackageSecrets(ctx, io.Discard, fClient, "") + err := printAllPackageSecrets(ctx, fClient, "") fClient.AssertExpectations(t) assert.Nil(t, err) } @@ -212,7 +211,7 @@ func TestOutput(t *testing.T) { var b []byte buffer := bytes.NewBuffer(b) - err := printAllPackageSecrets(ctx, buffer, fClient, "json") + err := printAllPackageSecrets(ctx, fClient, "json") fClient.AssertExpectations(t) assert.Nil(t, err) diff --git a/pkg/cmd/get/templates/secrets.tmpl b/pkg/cmd/get/templates/secrets.tmpl deleted file mode 100644 index 18bc9029..00000000 --- a/pkg/cmd/get/templates/secrets.tmpl +++ /dev/null @@ -1,7 +0,0 @@ ---------------------------- -Name: {{ .Name }} -Namespace: {{ .Namespace }} -Data: -{{- range $key, $value := .Data }} - {{ $key }} : {{ $value }} -{{- end }} diff --git a/pkg/util/util.go b/pkg/util/util.go index dbd606fe..a89839af 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -1,10 +1,13 @@ package util import ( + "bytes" "context" "crypto/rand" "crypto/tls" + "encoding/json" "fmt" + "k8s.io/cli-runtime/pkg/printers" "math" "math/big" mathrand "math/rand" @@ -16,9 +19,11 @@ import ( "time" "github.com/cnoe-io/idpbuilder/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/kind/pkg/cluster" + "sigs.k8s.io/yaml" ) const ( @@ -183,3 +188,43 @@ func SetPackageLabels(obj client.Object) { labels[v1alpha1.PackageTypeLabelKey] = v1alpha1.PackageTypeLabelCustom } } + +func PrintTable(table metav1.Table) error { + out := bytes.NewBuffer([]byte{}) + printer := printers.NewTablePrinter(printers.PrintOptions{}) + err := printer.PrintObj(&table, out) + if err != nil { + return fmt.Errorf("failed to print the table %w", err) + } + fmt.Println(out) + return nil +} + +func PrintDataAsJson(data any) error { + out := bytes.NewBuffer([]byte{}) + enc := json.NewEncoder(out) + enc.SetEscapeHTML(false) + enc.SetIndent("", " ") + if err := enc.Encode(data); err != nil { + return err + } else { + fmt.Println(out) + return nil + } + +} + +func PrintDataAsYaml(data any) error { + out := bytes.NewBuffer([]byte{}) + b, err := yaml.Marshal(data) + if err != nil { + return err + } + _, err = out.Write(b) + if err != nil { + return err + } else { + fmt.Println(out) + return nil + } +}