-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve the code to print the secrets using printTable #464
Changes from 5 commits
9fb9c76
666bfc7
cc43fcc
08cbf2d
913f60a
288284e
771fd89
813c0cd
580042f
13b4ad9
358c83b
3a2c119
4127914
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 (default if not specified), json or yaml.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's name the default as "table" instead of "". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. Fixed: 288284e |
||
GetCmd.PersistentFlags().StringVarP(&helpers.KubeConfigPath, "kubeconfig", "", "", "kube config file Path.") | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,13 @@ package get | |
|
||
import ( | ||
"context" | ||
"embed" | ||
"encoding/json" | ||
"fmt" | ||
"github.com/cnoe-io/idpbuilder/pkg/util" | ||
"io" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"os" | ||
"path/filepath" | ||
"text/template" | ||
"strings" | ||
|
||
"github.com/cnoe-io/idpbuilder/api/v1alpha1" | ||
"github.com/cnoe-io/idpbuilder/pkg/build" | ||
|
@@ -20,19 +20,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,17 +37,29 @@ 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"` | ||
Namespace string `json:"namespace"` | ||
Data map[string]string `json:"data"` | ||
} | ||
|
||
type Secret struct { | ||
isCore bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the use of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It is used to figure out when we have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not really |
||
Name string `json:"name"` | ||
Namespace string `json:"namespace"` | ||
Username string `json:"username,omitempty"` | ||
Password string `json:"password,omitempty"` | ||
Token string `json:"token,omitempty"` | ||
Data map[string]string `json:"data,omitempty"` | ||
} | ||
|
||
func getSecretsE(cmd *cobra.Command, args []string) error { | ||
ctx, ctxCancel := context.WithCancel(cmd.Context()) | ||
defer ctxCancel() | ||
|
@@ -85,7 +92,7 @@ func getSecretsE(cmd *cobra.Command, args []string) error { | |
|
||
func printAllPackageSecrets(ctx context.Context, outWriter io.Writer, 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 +103,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, true)) | ||
} | ||
} | ||
|
||
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], false)) | ||
} | ||
|
||
if len(secretsToPrint) == 0 { | ||
if len(secrets) == 0 { | ||
fmt.Println("no secrets found") | ||
return nil | ||
} | ||
return printOutput(secretTemplatePath, outWriter, secretsToPrint, format) | ||
return printSecretsOutput(outWriter, secrets, format) | ||
} | ||
|
||
func printPackageSecrets(ctx context.Context, outWriter io.Writer, 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 +139,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, true)) | ||
} | ||
continue | ||
} | ||
|
@@ -144,69 +151,94 @@ 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], false)) | ||
} | ||
|
||
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(outWriter, 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) | ||
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"}, | ||
{Name: "Data", Type: "string"}, | ||
} | ||
for _, secret := range secretTable { | ||
var dataEntries []string | ||
|
||
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) | ||
if !secret.isCore { | ||
for key, value := range secret.Data { | ||
dataEntries = append(dataEntries, fmt.Sprintf("%s=%s", key, value)) | ||
} | ||
} | ||
dataString := strings.Join(dataEntries, ", ") | ||
row := metav1.TableRow{ | ||
Cells: []interface{}{ | ||
secret.Name, | ||
secret.Namespace, | ||
secret.Username, | ||
secret.Password, | ||
secret.Token, | ||
dataString, | ||
}, | ||
} | ||
table.Rows = append(table.Rows, row) | ||
} | ||
return nil | ||
return *table | ||
} | ||
|
||
func printOutput(templatePath string, outWriter io.Writer, data []any, format string) error { | ||
func printSecretsOutput(outWriter io.Writer, 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, outWriter) | ||
case "yaml": | ||
b, err := yaml.Marshal(data) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = outWriter.Write(b) | ||
return err | ||
case "": | ||
return renderTemplate(templatePath, outWriter, data) | ||
return util.PrintDataAsYaml(secrets, outWriter) | ||
case "", "table": | ||
return util.PrintTable(generateSecretTable(secrets), outWriter) | ||
default: | ||
return fmt.Errorf("output format %s is not supported", format) | ||
} | ||
} | ||
|
||
func secretToTemplateData(s v1.Secret) TemplateData { | ||
data := TemplateData{ | ||
func generateSecret(s v1.Secret, isCoreSecret bool) Secret { | ||
secret := Secret{ | ||
Name: s.Name, | ||
Namespace: s.Namespace, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should name this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed: 813c0cd |
||
Data: make(map[string]string), | ||
} | ||
for k, v := range s.Data { | ||
data.Data[k] = string(v) | ||
|
||
if isCoreSecret { | ||
secret.isCore = true | ||
secret.Username = string(s.Data["username"]) | ||
secret.Password = string(s.Data["password"]) | ||
secret.Token = string(s.Data["token"]) | ||
secret.Data = nil | ||
} else { | ||
newData := make(map[string]string) | ||
for key, value := range s.Data { | ||
newData[key] = string(value) | ||
} | ||
if len(newData) > 0 { | ||
secret.Data = newData | ||
} | ||
} | ||
return data | ||
|
||
return secret | ||
} | ||
|
||
func getSecretsByCNOELabel(ctx context.Context, kubeClient client.Client, l labels.Selector) (v1.SecretList, error) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we combine this function for secret and cluster both and add it in utils package to avoid duplicate code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is what I did which is still a WIP: 580042f, 13b4ad9
Improvements are welcome ;-) @punkwalker