From 746248e11c3d6193e933d16163fc41969514dcd8 Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 13 Mar 2023 14:47:55 -0500 Subject: [PATCH 01/22] Add base kube command Signed-off-by: versilis --- cmd/internal/kube/kube.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 cmd/internal/kube/kube.go diff --git a/cmd/internal/kube/kube.go b/cmd/internal/kube/kube.go new file mode 100644 index 00000000..f866ab1d --- /dev/null +++ b/cmd/internal/kube/kube.go @@ -0,0 +1,15 @@ +package kube + +import ( + "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var Cmd = &cobra.Command{ + Use: "kube", + Short: "Gateway to Kubernetes related utilities", + RunE: func(_ *cobra.Command, _ []string) error { + return cmderr.AkitaErr{Err: errors.New("no subcommand specified")} + }, +} From ad244de30b47b93e4a29a0bf2e39e5d6d0583933 Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 13 Mar 2023 21:21:07 -0500 Subject: [PATCH 02/22] Refactor API credential check into a function Signed-off-by: versilis --- cmd/internal/cmderr/checks.go | 26 ++++++++++++++++++++++++++ cmd/internal/ecs/ecs.go | 8 +++++--- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 cmd/internal/cmderr/checks.go diff --git a/cmd/internal/cmderr/checks.go b/cmd/internal/cmderr/checks.go new file mode 100644 index 00000000..0e718234 --- /dev/null +++ b/cmd/internal/cmderr/checks.go @@ -0,0 +1,26 @@ +package cmderr + +import ( + "errors" + "github.com/akitasoftware/akita-cli/cfg" + "github.com/akitasoftware/akita-cli/env" + "github.com/akitasoftware/akita-cli/printer" +) + +// Checks that a user has configured their API key and secret and returned them. +// If the user has not configured their API key, a user-friendly error message is printed and an error is returned. +func RequireAPICredentials(explanation string) (string, string, error) { + key, secret := cfg.GetAPIKeyAndSecret() + if key == "" || secret == "" { + printer.Errorf("No Akita API key configured. %s\n", explanation) + if env.InDocker() { + printer.Infof("Please set the AKITA_API_KEY_ID and AKITA_API_KEY_SECRET environment variables on the Docker command line.\n") + } else { + printer.Infof("Use the AKITA_API_KEY_ID and AKITA_API_KEY_SECRET environment variables, or run 'akita login'.\n") + } + + return "", "", AkitaErr{Err: errors.New("could not find an Akita API key to use")} + } + + return key, secret, nil +} diff --git a/cmd/internal/ecs/ecs.go b/cmd/internal/ecs/ecs.go index 86f9c771..d6de0181 100644 --- a/cmd/internal/ecs/ecs.go +++ b/cmd/internal/ecs/ecs.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/akitasoftware/akita-cli/cfg" "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" "github.com/akitasoftware/akita-cli/env" "github.com/akitasoftware/akita-cli/printer" @@ -84,7 +83,10 @@ func init() { func addAgentToECS(cmd *cobra.Command, args []string) error { // Check for API key - key, secret := cfg.GetAPIKeyAndSecret() + key, secret, err := cmderr.RequireAPICredentials("The Akita agent must have an API key in order to capture traces.") + if err != nil { + return err + } if key == "" || secret == "" { printer.Errorf("No Akita API key configured. The Akita agent must have an API key in order to capture traces.\n") if env.InDocker() { @@ -100,7 +102,7 @@ func addAgentToECS(cmd *cobra.Command, args []string) error { return errors.New("Must specify the name of your Akita project with the --project flag.") } frontClient := rest.NewFrontClient(rest.Domain, telemetry.GetClientID()) - _, err := util.GetServiceIDByName(frontClient, projectFlag) + _, err = util.GetServiceIDByName(frontClient, projectFlag) if err != nil { // TODO: we _could_ offer to create it, instead. if strings.Contains(err.Error(), "cannot determine project ID") { From 3789778de379c2f76a09af6132a2800777943f8b Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 11:12:11 -0500 Subject: [PATCH 03/22] Add template to generate secrets Signed-off-by: versilis --- cmd/internal/kube/template.go | 6 ++++++ cmd/internal/kube/template/akita-secret.tmpl | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 cmd/internal/kube/template.go create mode 100644 cmd/internal/kube/template/akita-secret.tmpl diff --git a/cmd/internal/kube/template.go b/cmd/internal/kube/template.go new file mode 100644 index 00000000..c024a4fd --- /dev/null +++ b/cmd/internal/kube/template.go @@ -0,0 +1,6 @@ +package kube + +import "embed" + +//go:embed template +var templateFS embed.FS diff --git a/cmd/internal/kube/template/akita-secret.tmpl b/cmd/internal/kube/template/akita-secret.tmpl new file mode 100644 index 00000000..25cc44ea --- /dev/null +++ b/cmd/internal/kube/template/akita-secret.tmpl @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: akita-secrets + namespace: {{.Namespace}} +type: Opaque +data: + akita-api-key: {{.APIKey}} + akita-api-secret: {{.APISecret}} From e5b4a8871ccd0fc2e201c0ef1b453c6f298cdc16 Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 11:51:37 -0500 Subject: [PATCH 04/22] Add kube secret command Signed-off-by: versilis --- cmd/internal/kube/secret.go | 89 +++++++++++++++++++ cmd/internal/kube/secret_test.go | 38 ++++++++ .../kube/test_resource/akita-secret.yml | 9 ++ 3 files changed, 136 insertions(+) create mode 100644 cmd/internal/kube/secret.go create mode 100644 cmd/internal/kube/secret_test.go create mode 100644 cmd/internal/kube/test_resource/akita-secret.yml diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go new file mode 100644 index 00000000..a3a06406 --- /dev/null +++ b/cmd/internal/kube/secret.go @@ -0,0 +1,89 @@ +package kube + +import ( + "encoding/base64" + "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "log" + "os" + "text/template" +) + + +var ( + output string + namespace string + // Store a parsed representation of /template/akita-secret.tmpl + secretTemplate *template.Template +) + +var secretCmd = &cobra.Command{ + Use: "secret", + Short: "Generate a Kubernetes secret config for Akita", + RunE: func(cmd *cobra.Command, args []string) error { + if namespace == "" { + return cmderr.AkitaErr{Err: errors.New("namespace flag not set")} + } + + key, secret, err := cmderr.RequireAPICredentials("Akita API key is required for Kubernetes Secret generation") + if err != nil { + return err + } + + return handleSecretGeneration(namespace, key, secret, output) + }, +} + +// Represents the input used by secretTemplate +type secretTemplateInput struct { + // + Namespace string + APIKey string + APISecret string +} + +func handleSecretGeneration(namespace, key, secret, output string) error { + + input := secretTemplateInput{ + Namespace: namespace, + APIKey: base64.StdEncoding.EncodeToString([]byte(key)), + APISecret: base64.StdEncoding.EncodeToString([]byte(secret)), + } + + file, err := os.Create(output) + if err != nil { + return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} + } + + defer file.Close() + + err = secretTemplate.Execute(file, input) + if err != nil { + return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} + } + + return nil +} + +func init() { + var err error + + secretTemplate, err = template.ParseFS(templateFS, "template/akita-secret.tmpl") + if err != nil { + log.Fatalf("unable to parse kube secret template: %v", err) + } + + // Create a flag on the root subcommand to avoid + secretCmd.Flags().StringVarP( + &namespace, + "namespace", + "n", + "", + "The Kuberenetes namespace the secret should be applied to", + ) + + secretCmd.Flags().StringVarP(&output, "output", "o", "akita-secret.yml", "File to output the generated secret.") + + Cmd.AddCommand(secretCmd) +} diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go new file mode 100644 index 00000000..dfb04067 --- /dev/null +++ b/cmd/internal/kube/secret_test.go @@ -0,0 +1,38 @@ +package kube + +import ( + _ "embed" + "github.com/stretchr/testify/assert" + "os" + "path/filepath" + "testing" +) + +//go:embed test_resource/akita-secret.yml +var testAkitaSecretYAML []byte + +func Test_secretGeneration(t *testing.T) { + // GIVEN + const ( + namespace = "default" + key = "api-key" + secret = "api-secret" + ) + + dir := t.TempDir() + actualOutput := filepath.Join(dir, "akita-secret.yml") + + // WHEN + err := handleSecretGeneration(namespace, key, secret, actualOutput) + if err != nil { + t.Errorf("Unexpected error: %s", err) + } + + // THEN + actualFile, err := os.ReadFile(actualOutput) + if err != nil { + t.Errorf("Failed to read generated file: %v", err) + } + + assert.Equal(t, string(testAkitaSecretYAML), string(actualFile)) +} diff --git a/cmd/internal/kube/test_resource/akita-secret.yml b/cmd/internal/kube/test_resource/akita-secret.yml new file mode 100644 index 00000000..f2627273 --- /dev/null +++ b/cmd/internal/kube/test_resource/akita-secret.yml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: akita-secrets + namespace: default +type: Opaque +data: + akita-api-key: YXBpLWtleQ== + akita-api-secret: YXBpLXNlY3JldA== From 10ad02d346deec509bda474e6e673dbd0914dad5 Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 17:17:36 -0500 Subject: [PATCH 05/22] Add to root command --- cmd/root.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index 97a6fe67..70127fc8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -22,6 +22,7 @@ import ( "github.com/akitasoftware/akita-cli/cmd/internal/daemon" "github.com/akitasoftware/akita-cli/cmd/internal/ecs" "github.com/akitasoftware/akita-cli/cmd/internal/get" + "github.com/akitasoftware/akita-cli/cmd/internal/kube" "github.com/akitasoftware/akita-cli/cmd/internal/learn" "github.com/akitasoftware/akita-cli/cmd/internal/legacy" "github.com/akitasoftware/akita-cli/cmd/internal/login" @@ -279,6 +280,7 @@ func init() { rootCmd.AddCommand(ci_guard.GuardCommand(get.Cmd)) rootCmd.AddCommand(ecs.Cmd) rootCmd.AddCommand(nginx.Cmd) + rootCmd.AddCommand(kube.Cmd) // Legacy commands, included for backward compatibility but are hidden. legacy.SessionsCmd.Hidden = true From 0caeed3fc85e43a350f87d271aaa1e85c4f2a0fb Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 19:11:52 -0500 Subject: [PATCH 06/22] Print success message when secret config is generated --- cmd/internal/kube/secret.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index a3a06406..9481d7ff 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -2,12 +2,15 @@ package kube import ( "encoding/base64" - "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" - "github.com/pkg/errors" - "github.com/spf13/cobra" "log" "os" "text/template" + + "github.com/akitasoftware/akita-cli/printer" + + "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" + "github.com/pkg/errors" + "github.com/spf13/cobra" ) @@ -31,7 +34,14 @@ var secretCmd = &cobra.Command{ return err } - return handleSecretGeneration(namespace, key, secret, output) + err = handleSecretGeneration(namespace, key, secret, output) + if err != nil { + return err + } + + + printer.Infof("Generated Kubernetes secret config to %s", output) + return nil }, } From e651574f4cf0ff551cd64c2b14d5d1c47211a15b Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 21:04:28 -0500 Subject: [PATCH 07/22] Fix issues with output generation --- cmd/internal/kube/secret.go | 43 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 9481d7ff..9d72ae2e 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "log" "os" + "path/filepath" "text/template" "github.com/akitasoftware/akita-cli/printer" @@ -40,14 +41,13 @@ var secretCmd = &cobra.Command{ } - printer.Infof("Generated Kubernetes secret config to %s", output) + printer.Infoln("Generated Kubernetes secret config to ", output) return nil }, } // Represents the input used by secretTemplate type secretTemplateInput struct { - // Namespace string APIKey string APISecret string @@ -61,14 +61,14 @@ func handleSecretGeneration(namespace, key, secret, output string) error { APISecret: base64.StdEncoding.EncodeToString([]byte(secret)), } - file, err := os.Create(output) + secretFile, err := createSecretFile(output) if err != nil { return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} } - defer file.Close() + defer secretFile.Close() - err = secretTemplate.Execute(file, input) + err = secretTemplate.Execute(secretFile, input) if err != nil { return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} } @@ -76,6 +76,39 @@ func handleSecretGeneration(namespace, key, secret, output string) error { return nil } +// Creates a file at the give path to be used for storing of the generated Secret config +// If any child dicrectories do not exist, it will be created. +func createSecretFile(path string) (*os.File, error) { + // Split the outut flag value into directory and filename + outputDir, outputName := filepath.Split(path) + + // Get the absolute path of the output directory + absOutputDir, err := filepath.Abs(outputDir) + if err != nil { + return nil, errors.Wrapf(err, "failed to resolve the absolute path of the output directory") + } + + // Check if the output file already exists + outputFilePath := filepath.Join(absOutputDir, outputName) + if _, statErr := os.Stat(outputFilePath); statErr == nil { + return nil, errors.Errorf("output file %s already exists", outputFilePath) + } + + // Create the output directory if it doesn't exist + err = os.MkdirAll(absOutputDir, 0755) + if err != nil { + return nil, errors.Wrapf(err, "failed to create the output directory") + } + + // Create the output file in the output directory + outputFile, err := os.Create(outputFilePath) + if err != nil { + return nil, errors.Wrap(err, "failed to create the output file") + } + + return outputFile, nil +} + func init() { var err error From 1c7ae51a2323ff36bbee5b8ade1db3aaa1ada353 Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 21:05:02 -0500 Subject: [PATCH 08/22] Mark namespace flag as required --- cmd/internal/kube/secret.go | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 9d72ae2e..e3750ad3 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -14,33 +14,27 @@ import ( "github.com/spf13/cobra" ) - var ( - output string - namespace string + output string + namespace string // Store a parsed representation of /template/akita-secret.tmpl - secretTemplate *template.Template + secretTemplate *template.Template ) var secretCmd = &cobra.Command{ - Use: "secret", + Use: "secret", Short: "Generate a Kubernetes secret config for Akita", RunE: func(cmd *cobra.Command, args []string) error { - if namespace == "" { - return cmderr.AkitaErr{Err: errors.New("namespace flag not set")} - } - key, secret, err := cmderr.RequireAPICredentials("Akita API key is required for Kubernetes Secret generation") if err != nil { return err } - err = handleSecretGeneration(namespace, key, secret, output) + err = handleSecretGeneration(namespace, key, secret, output) if err != nil { return err } - printer.Infoln("Generated Kubernetes secret config to ", output) return nil }, @@ -125,6 +119,7 @@ func init() { "", "The Kuberenetes namespace the secret should be applied to", ) + _ = secretCmd.MarkFlagRequired("namespace") secretCmd.Flags().StringVarP(&output, "output", "o", "akita-secret.yml", "File to output the generated secret.") From 0fd9974bc5ec2455b15025f28b5fb1cc165845bc Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 21:12:47 -0500 Subject: [PATCH 09/22] Add comment --- cmd/internal/kube/secret.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index e3750ad3..d2107b91 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -47,6 +47,7 @@ type secretTemplateInput struct { APISecret string } +// Generates a Kubernetes secret config file for Akita func handleSecretGeneration(namespace, key, secret, output string) error { input := secretTemplateInput{ @@ -111,7 +112,6 @@ func init() { log.Fatalf("unable to parse kube secret template: %v", err) } - // Create a flag on the root subcommand to avoid secretCmd.Flags().StringVarP( &namespace, "namespace", From a7a2c07253e46faac0268342ddbec195e001500d Mon Sep 17 00:00:00 2001 From: versilis Date: Wed, 15 Mar 2023 21:14:49 -0500 Subject: [PATCH 10/22] Update unit test --- cmd/internal/kube/secret_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go index dfb04067..b49a3216 100644 --- a/cmd/internal/kube/secret_test.go +++ b/cmd/internal/kube/secret_test.go @@ -20,7 +20,7 @@ func Test_secretGeneration(t *testing.T) { ) dir := t.TempDir() - actualOutput := filepath.Join(dir, "akita-secret.yml") + actualOutput := filepath.Join(dir, "configurations", "akita-secret.yml") // WHEN err := handleSecretGeneration(namespace, key, secret, actualOutput) From ed0dfc8e2f702c1be36144090a0da261ddd4bd38 Mon Sep 17 00:00:00 2001 From: Versilis Tyson <100976287+versilis@users.noreply.github.com> Date: Mon, 20 Mar 2023 10:06:38 -0500 Subject: [PATCH 11/22] Apply suggestions from code review Co-authored-by: Mark Gritter --- cmd/internal/kube/kube.go | 2 +- cmd/internal/kube/secret.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/internal/kube/kube.go b/cmd/internal/kube/kube.go index f866ab1d..75590d54 100644 --- a/cmd/internal/kube/kube.go +++ b/cmd/internal/kube/kube.go @@ -8,7 +8,7 @@ import ( var Cmd = &cobra.Command{ Use: "kube", - Short: "Gateway to Kubernetes related utilities", + Short: "Install Akita in your Kubernetes cluster", RunE: func(_ *cobra.Command, _ []string) error { return cmderr.AkitaErr{Err: errors.New("no subcommand specified")} }, diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index d2107b91..359ce058 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -23,7 +23,7 @@ var ( var secretCmd = &cobra.Command{ Use: "secret", - Short: "Generate a Kubernetes secret config for Akita", + Short: "Generate a Kubernetes secret containing the Akita credentials", RunE: func(cmd *cobra.Command, args []string) error { key, secret, err := cmderr.RequireAPICredentials("Akita API key is required for Kubernetes Secret generation") if err != nil { @@ -117,7 +117,7 @@ func init() { "namespace", "n", "", - "The Kuberenetes namespace the secret should be applied to", + "The Kubernetes namespace the secret should be applied to", ) _ = secretCmd.MarkFlagRequired("namespace") From 8d661256aba02387c10e5efe17e37b9897feaada Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 20 Mar 2023 09:45:15 -0500 Subject: [PATCH 12/22] Remove old credential check in addAgentToECS --- cmd/internal/ecs/ecs.go | 42 +++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/cmd/internal/ecs/ecs.go b/cmd/internal/ecs/ecs.go index d6de0181..6683b997 100644 --- a/cmd/internal/ecs/ecs.go +++ b/cmd/internal/ecs/ecs.go @@ -5,8 +5,6 @@ import ( "strings" "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" - "github.com/akitasoftware/akita-cli/env" - "github.com/akitasoftware/akita-cli/printer" "github.com/akitasoftware/akita-cli/rest" "github.com/akitasoftware/akita-cli/telemetry" "github.com/akitasoftware/akita-cli/util" @@ -70,8 +68,18 @@ func init() { Cmd.PersistentFlags().StringVar(&awsRegionFlag, "region", "", "The AWS region in which your ECS cluster resides.") Cmd.PersistentFlags().StringVar(&ecsClusterFlag, "cluster", "", "The name or ARN of your ECS cluster.") Cmd.PersistentFlags().StringVar(&ecsServiceFlag, "service", "", "The name or ARN of your ECS service.") - Cmd.PersistentFlags().StringVar(&ecsTaskDefinitionFlag, "task", "", "The name of your ECS task definition to modify.") - Cmd.PersistentFlags().BoolVar(&dryRunFlag, "dry-run", false, "Perform a dry run: show what will be done, but do not modify ECS.") + Cmd.PersistentFlags().StringVar( + &ecsTaskDefinitionFlag, + "task", + "", + "The name of your ECS task definition to modify.", + ) + Cmd.PersistentFlags().BoolVar( + &dryRunFlag, + "dry-run", + false, + "Perform a dry run: show what will be done, but do not modify ECS.", + ) // Support for credentials in a nonstandard location Cmd.PersistentFlags().StringVar(&awsCredentialsFlag, "aws-credentials", "", "Location of AWS credentials file.") @@ -83,19 +91,10 @@ func init() { func addAgentToECS(cmd *cobra.Command, args []string) error { // Check for API key - key, secret, err := cmderr.RequireAPICredentials("The Akita agent must have an API key in order to capture traces.") + _, _, err := cmderr.RequireAPICredentials("The Akita agent must have an API key in order to capture traces.") if err != nil { return err } - if key == "" || secret == "" { - printer.Errorf("No Akita API key configured. The Akita agent must have an API key in order to capture traces.\n") - if env.InDocker() { - printer.Infof("Please set the AKITA_API_KEY_ID and AKITA_API_KEY_SECRET environment variables on the Docker command line.\n") - } else { - printer.Infof("Use the AKITA_API_KEY_ID and AKITA_API_KEY_SECRET environment variables, or run 'akita login'.\n") - } - return cmderr.AkitaErr{Err: errors.New("Could not find an Akita API key to use.")} - } // Check project's existence if projectFlag == "" { @@ -106,9 +105,20 @@ func addAgentToECS(cmd *cobra.Command, args []string) error { if err != nil { // TODO: we _could_ offer to create it, instead. if strings.Contains(err.Error(), "cannot determine project ID") { - return cmderr.AkitaErr{Err: fmt.Errorf("Could not find the project %q in the Akita cloud. Please create it from the Akita web console before proceeding.", projectFlag)} + return cmderr.AkitaErr{ + Err: fmt.Errorf( + "Could not find the project %q in the Akita cloud. Please create it from the Akita web console before proceeding.", + projectFlag, + ), + } } else { - return cmderr.AkitaErr{Err: errors.Wrapf(err, "Could not look up the project %q in the Akita cloud", projectFlag)} + return cmderr.AkitaErr{ + Err: errors.Wrapf( + err, + "Could not look up the project %q in the Akita cloud", + projectFlag, + ), + } } } From 6596d5e87dd4c624200a42f5bc4ef2a313b18fce Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 20 Mar 2023 09:58:27 -0500 Subject: [PATCH 13/22] Use the default namespace when none is provided --- cmd/internal/kube/secret.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 359ce058..7b043252 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -105,21 +105,13 @@ func createSecretFile(path string) (*os.File, error) { } func init() { - var err error - - secretTemplate, err = template.ParseFS(templateFS, "template/akita-secret.tmpl") - if err != nil { - log.Fatalf("unable to parse kube secret template: %v", err) - } - secretCmd.Flags().StringVarP( &namespace, "namespace", "n", - "", + "default", "The Kubernetes namespace the secret should be applied to", ) - _ = secretCmd.MarkFlagRequired("namespace") secretCmd.Flags().StringVarP(&output, "output", "o", "akita-secret.yml", "File to output the generated secret.") From 69857a46fa69b814319c8ebe9ca018b97445e366 Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 20 Mar 2023 10:03:52 -0500 Subject: [PATCH 14/22] Rename flag variables to fit standard conventions --- cmd/internal/kube/secret.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 7b043252..4091dc04 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -15,8 +15,8 @@ import ( ) var ( - output string - namespace string + outputFlag string + namespaceFlag string // Store a parsed representation of /template/akita-secret.tmpl secretTemplate *template.Template ) @@ -30,12 +30,12 @@ var secretCmd = &cobra.Command{ return err } - err = handleSecretGeneration(namespace, key, secret, output) + err = handleSecretGeneration(namespaceFlag, key, secret, outputFlag) if err != nil { return err } - printer.Infoln("Generated Kubernetes secret config to ", output) + printer.Infoln("Generated Kubernetes secret config to ", outputFlag) return nil }, } @@ -106,14 +106,14 @@ func createSecretFile(path string) (*os.File, error) { func init() { secretCmd.Flags().StringVarP( - &namespace, + &namespaceFlag, "namespace", "n", "default", "The Kubernetes namespace the secret should be applied to", ) - secretCmd.Flags().StringVarP(&output, "output", "o", "akita-secret.yml", "File to output the generated secret.") + secretCmd.Flags().StringVarP(&outputFlag, "output", "o", "akita-secret.yml", "File to output the generated secret.") Cmd.AddCommand(secretCmd) } From 5acfe0610228fedbab13c3fef2ea452108a8dd9a Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 20 Mar 2023 10:36:09 -0500 Subject: [PATCH 15/22] Print output on successful secret generation --- cmd/internal/kube/secret.go | 49 ++++++++++++++++++++++++++------ cmd/internal/kube/secret_test.go | 3 +- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 4091dc04..6dd2e196 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -1,15 +1,16 @@ package kube import ( + "bytes" "encoding/base64" - "log" "os" "path/filepath" "text/template" - "github.com/akitasoftware/akita-cli/printer" + "github.com/akitasoftware/akita-cli/telemetry" "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" + "github.com/akitasoftware/akita-cli/printer" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -30,14 +31,22 @@ var secretCmd = &cobra.Command{ return err } - err = handleSecretGeneration(namespaceFlag, key, secret, outputFlag) + output, err := handleSecretGeneration(namespaceFlag, key, secret, outputFlag) if err != nil { return err } - printer.Infoln("Generated Kubernetes secret config to ", outputFlag) + // Output the generated secret to the console + printer.RawOutput(output) + return nil }, + // Override the parent command's PersistentPreRun to prevent any logs from being printed. + // This is necessary because the secret command is intended to be used in a pipeline + PersistentPreRun: func(cmd *cobra.Command, args []string) { + // Initialize the telemetry client, but do not allow any logs to be printed + telemetry.Init(false) + }, } // Represents the input used by secretTemplate @@ -47,8 +56,23 @@ type secretTemplateInput struct { APISecret string } +func initSecretTemplate() error { + var err error + + secretTemplate, err = template.ParseFS(templateFS, "template/akita-secret.tmpl") + if err != nil { + return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to parse secret template")} + } + + return nil +} + // Generates a Kubernetes secret config file for Akita -func handleSecretGeneration(namespace, key, secret, output string) error { +// On success, the generated output is returned as a string. +func handleSecretGeneration(namespace, key, secret, output string) (string, error) { + if err := initSecretTemplate(); err != nil { + return "", err + } input := secretTemplateInput{ Namespace: namespace, @@ -58,17 +82,24 @@ func handleSecretGeneration(namespace, key, secret, output string) error { secretFile, err := createSecretFile(output) if err != nil { - return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} + return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} } defer secretFile.Close() - err = secretTemplate.Execute(secretFile, input) + buf := new(bytes.Buffer) + + err = secretTemplate.Execute(buf, input) if err != nil { - return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} + return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} } - return nil + _, err = secretFile.Write(buf.Bytes()) + if err != nil { + return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to read generated secret file")} + } + + return buf.String(), nil } // Creates a file at the give path to be used for storing of the generated Secret config diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go index b49a3216..08da6217 100644 --- a/cmd/internal/kube/secret_test.go +++ b/cmd/internal/kube/secret_test.go @@ -23,7 +23,7 @@ func Test_secretGeneration(t *testing.T) { actualOutput := filepath.Join(dir, "configurations", "akita-secret.yml") // WHEN - err := handleSecretGeneration(namespace, key, secret, actualOutput) + actualContent, err := handleSecretGeneration(namespace, key, secret, actualOutput) if err != nil { t.Errorf("Unexpected error: %s", err) } @@ -35,4 +35,5 @@ func Test_secretGeneration(t *testing.T) { } assert.Equal(t, string(testAkitaSecretYAML), string(actualFile)) + assert.Equal(t, string(testAkitaSecretYAML), actualContent) } From df81990a0f9a9b8a930d72c79d49962b055263e3 Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 20 Mar 2023 18:10:49 -0500 Subject: [PATCH 16/22] Add function to initialize telemetry This provides a workaround to remove all telemetry info logs during a command's initialization. This is needed by the kube secret command because only the raw YAML output should be printed to stdout. --- cmd/root.go | 2 ++ telemetry/telemetry.go | 46 +++++++++++++++++++++++++----------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 70127fc8..ddda260e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -74,6 +74,8 @@ var ( ) func preRun(cmd *cobra.Command, args []string) { + telemetry.Init(true) + switch logFormatFlag { case "json": printer.SwitchToJSON() diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index 99034c77..b92de012 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -50,7 +50,9 @@ func (_ nullClient) Close() error { return nil } -func init() { +// Initialize the telemetry client. +// This should be called once at startup either from the root command or from a subcommand that overrides the default PersistentPreRun. +func Init(isLoggingEnabled bool) { // Opt-out mechanism disableTelemetry := os.Getenv("AKITA_DISABLE_TELEMETRY") if disableTelemetry != "" { @@ -70,31 +72,37 @@ func init() { segmentKey = defaultSegmentKey } if segmentKey == "" { - printer.Infof("Telemetry unavailable; no Segment key configured.\n") - printer.Infof("This is caused by building from source rather than using an official build.\n") + if isLoggingEnabled { + printer.Infof("Telemetry unavailable; no Segment key configured.\n") + printer.Infof("This is caused by building from source rather than using an official build.\n") + } analyticsClient = nullClient{} return } var err error - analyticsClient, err = analytics.NewClient(analytics.Config{ - WriteKey: segmentKey, - SegmentEndpoint: segmentEndpoint, - App: analytics.AppInfo{ - Name: "akita-cli", - Version: version.ReleaseVersion().String(), - Build: version.GitVersion(), - Namespace: "", + analyticsClient, err = analytics.NewClient( + analytics.Config{ + WriteKey: segmentKey, + SegmentEndpoint: segmentEndpoint, + App: analytics.AppInfo{ + Name: "akita-cli", + Version: version.ReleaseVersion().String(), + Build: version.GitVersion(), + Namespace: "", + }, + // No output from the Segment library + IsLoggingEnabled: false, + // IsMixpanelEnabled: false, -- irrelevant for us, leaving at default value + BatchSize: 1, // disable batching }, - // No output from the Segment library - IsLoggingEnabled: false, - // IsMixpanelEnabled: false, -- irrelevant for us, leaving at default value - BatchSize: 1, // disable batching - }) + ) if err != nil { - printer.Infof("Telemetry unavailable; error setting up Segment client: %v\n", err) - printer.Infof("Akita support will not be able to see any errors you encounter.\n") - printer.Infof("Please send this log message to support@akitasoftware.com.\n") + if isLoggingEnabled { + printer.Infof("Telemetry unavailable; error setting up Segment client: %v\n", err) + printer.Infof("Akita support will not be able to see any errors you encounter.\n") + printer.Infof("Please send this log message to support@akitasoftware.com.\n") + } analyticsClient = nullClient{} } else { analyticsEnabled = true From 3dbe5261287d3ea0296e088a6e0bcb5353e7e756 Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 20 Mar 2023 20:49:47 -0500 Subject: [PATCH 17/22] Return an error if directory does not exist --- cmd/internal/kube/secret.go | 11 +++++------ cmd/internal/kube/secret_test.go | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 6dd2e196..62801268 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -114,18 +114,17 @@ func createSecretFile(path string) (*os.File, error) { return nil, errors.Wrapf(err, "failed to resolve the absolute path of the output directory") } + // Check that the output directory exists + if _, statErr := os.Stat(absOutputDir); os.IsNotExist(statErr) { + return nil, errors.Errorf("output directory %s does not exist", absOutputDir) + } + // Check if the output file already exists outputFilePath := filepath.Join(absOutputDir, outputName) if _, statErr := os.Stat(outputFilePath); statErr == nil { return nil, errors.Errorf("output file %s already exists", outputFilePath) } - // Create the output directory if it doesn't exist - err = os.MkdirAll(absOutputDir, 0755) - if err != nil { - return nil, errors.Wrapf(err, "failed to create the output directory") - } - // Create the output file in the output directory outputFile, err := os.Create(outputFilePath) if err != nil { diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go index 08da6217..b759b175 100644 --- a/cmd/internal/kube/secret_test.go +++ b/cmd/internal/kube/secret_test.go @@ -20,7 +20,7 @@ func Test_secretGeneration(t *testing.T) { ) dir := t.TempDir() - actualOutput := filepath.Join(dir, "configurations", "akita-secret.yml") + actualOutput := filepath.Join(dir, "akita-secret.yml") // WHEN actualContent, err := handleSecretGeneration(namespace, key, secret, actualOutput) From 935b4bbcb6c6bb93fa562329ad22bce93911b09d Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 09:42:52 -0500 Subject: [PATCH 18/22] Add aliases for kube command --- cmd/internal/kube/kube.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/internal/kube/kube.go b/cmd/internal/kube/kube.go index 75590d54..9b5a623d 100644 --- a/cmd/internal/kube/kube.go +++ b/cmd/internal/kube/kube.go @@ -9,6 +9,10 @@ import ( var Cmd = &cobra.Command{ Use: "kube", Short: "Install Akita in your Kubernetes cluster", + Aliases: []string{ + "k8s", + "kubernetes", + }, RunE: func(_ *cobra.Command, _ []string) error { return cmderr.AkitaErr{Err: errors.New("no subcommand specified")} }, From 562adb3346b28c7b736bcd50d670ec9498632e47 Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 09:46:03 -0500 Subject: [PATCH 19/22] Tweak test names --- cmd/internal/kube/secret_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go index b759b175..8c977468 100644 --- a/cmd/internal/kube/secret_test.go +++ b/cmd/internal/kube/secret_test.go @@ -23,17 +23,17 @@ func Test_secretGeneration(t *testing.T) { actualOutput := filepath.Join(dir, "akita-secret.yml") // WHEN - actualContent, err := handleSecretGeneration(namespace, key, secret, actualOutput) + output, err := handleSecretGeneration(namespace, key, secret, actualOutput) if err != nil { t.Errorf("Unexpected error: %s", err) } - // THEN - actualFile, err := os.ReadFile(actualOutput) + generatedFile, err := os.ReadFile(actualOutput) if err != nil { - t.Errorf("Failed to read generated file: %v", err) + t.Errorf("Failed to read generated generatedFile: %v", err) } - assert.Equal(t, string(testAkitaSecretYAML), string(actualFile)) - assert.Equal(t, string(testAkitaSecretYAML), actualContent) + // THEN + assert.Equal(t, string(testAkitaSecretYAML), string(generatedFile)) + assert.Equal(t, string(testAkitaSecretYAML), output) } From 24a8bc3a8c51e9ad0c6cfc82a9c78f1bd8c38642 Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 09:57:11 -0500 Subject: [PATCH 20/22] Fix test --- learn/parse_http_test.go | 2 ++ pcap/stream_test.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/learn/parse_http_test.go b/learn/parse_http_test.go index 046d945f..fea16ea3 100644 --- a/learn/parse_http_test.go +++ b/learn/parse_http_test.go @@ -3,6 +3,7 @@ package learn import ( "bytes" "compress/flate" + "github.com/akitasoftware/akita-cli/telemetry" "net/http" "strings" "testing" @@ -127,6 +128,7 @@ type parseTest struct { } func TestParseHTTPRequest(t *testing.T) { + telemetry.Init(false) standardMethodMeta := &as.MethodMeta{ Meta: &as.MethodMeta_Http{ Http: &as.HTTPMethodMeta{ diff --git a/pcap/stream_test.go b/pcap/stream_test.go index ca16ae19..7735db26 100644 --- a/pcap/stream_test.go +++ b/pcap/stream_test.go @@ -2,6 +2,7 @@ package pcap import ( "fmt" + "github.com/akitasoftware/akita-cli/telemetry" "net" "testing" "time" @@ -127,6 +128,7 @@ func runTCPFlowTestCase(c tcpFlowTestCase) error { } func TestTCPFlow(t *testing.T) { + telemetry.Init(false) testCases := []tcpFlowTestCase{ { name: "unparsable single byte", From edb42463601ad2b5ba7205569a5c7706c2daf704 Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 10:00:47 -0500 Subject: [PATCH 21/22] Update buffer initialization to use builtin constructor --- cmd/internal/kube/secret.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 62801268..d7d01ae0 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -84,10 +84,9 @@ func handleSecretGeneration(namespace, key, secret, output string) (string, erro if err != nil { return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} } - defer secretFile.Close() - buf := new(bytes.Buffer) + buf := bytes.NewBuffer([]byte{}) err = secretTemplate.Execute(buf, input) if err != nil { From 3d5e8966a7480a764e2cfe215244bb2b3e944d63 Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 00:42:17 -0500 Subject: [PATCH 22/22] Use k8 API to generate secret resource --- cmd/internal/kube/secret.go | 110 +++++++++++++++++++++---------- cmd/internal/kube/secret_test.go | 49 ++++++++++++-- go.mod | 31 ++++++--- go.sum | 74 ++++++++++++++++----- 4 files changed, 199 insertions(+), 65 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index d7d01ae0..a6193d67 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -2,15 +2,19 @@ package kube import ( "bytes" - "encoding/base64" + "encoding/json" + "github.com/akitasoftware/akita-cli/printer" + "github.com/akitasoftware/akita-cli/telemetry" + "github.com/ghodss/yaml" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + k8_json "k8s.io/apimachinery/pkg/runtime/serializer/json" "os" "path/filepath" - "text/template" - - "github.com/akitasoftware/akita-cli/telemetry" "github.com/akitasoftware/akita-cli/cmd/internal/cmderr" - "github.com/akitasoftware/akita-cli/printer" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -18,8 +22,6 @@ import ( var ( outputFlag string namespaceFlag string - // Store a parsed representation of /template/akita-secret.tmpl - secretTemplate *template.Template ) var secretCmd = &cobra.Command{ @@ -49,56 +51,92 @@ var secretCmd = &cobra.Command{ }, } -// Represents the input used by secretTemplate -type secretTemplateInput struct { - Namespace string - APIKey string - APISecret string -} +/* +XXX: Kuberenetes Go API package currently has issues with valid serialization. +The ObjectMeta field's CreationTimestamp field is improperly serialized as null when it should be omitted entirely if it is a zero value. +This shouldn't cause any issues applying the secret, but it does cause issues for any tools that depend on valid yaml objects (such as linting tools) +See: https://github.com/kubernetes/kubernetes/issues/109427 + +Here, I've manually filtered out the CreationTimestamp field from the serialized object to work around this issue. +*/ +func buildSecretConfiguration(namespace, apiKey, apiSecret string) ([]byte, error) { + secret := &v1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "akita-secrets", + Namespace: namespace, + }, + Type: v1.SecretTypeOpaque, + Data: map[string][]byte{ + "akita-api-key": []byte(apiKey), + "akita-api-secret": []byte(apiSecret), + }, + } -func initSecretTemplate() error { - var err error + unstructuredSecret, err := runtime.DefaultUnstructuredConverter.ToUnstructured(secret) + if err != nil { + return nil, err + } + + unstructuredObj := &unstructured.Unstructured{Object: unstructuredSecret} + serializer := k8_json.NewSerializerWithOptions( + k8_json.DefaultMetaFactory, + nil, + nil, + k8_json.SerializerOptions{Yaml: false, Pretty: false, Strict: true}, + ) - secretTemplate, err = template.ParseFS(templateFS, "template/akita-secret.tmpl") + buf := bytes.NewBuffer([]byte{}) + err = serializer.Encode(unstructuredObj, buf) if err != nil { - return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to parse secret template")} + return nil, err } - return nil + // HACK: Manually filter out the CreationTimestamp field from the serialized object + objMap := make(map[string]interface{}) + err = json.Unmarshal(buf.Bytes(), &objMap) + if err != nil { + return nil, err + } + + if _, ok := objMap["metadata"]; ok { + metadataMap := objMap["metadata"].(map[string]interface{}) + delete(metadataMap, "creationTimestamp") + } + + // Re-serialize the object + fixedJSON, err := json.Marshal(objMap) + if err != nil { + return nil, err + } + + return yaml.JSONToYAML(fixedJSON) } // Generates a Kubernetes secret config file for Akita -// On success, the generated output is returned as a string. -func handleSecretGeneration(namespace, key, secret, output string) (string, error) { - if err := initSecretTemplate(); err != nil { - return "", err - } +func handleSecretGeneration(namespace, apiKey, apiSecret, output string) (string, error) { - input := secretTemplateInput{ - Namespace: namespace, - APIKey: base64.StdEncoding.EncodeToString([]byte(key)), - APISecret: base64.StdEncoding.EncodeToString([]byte(secret)), + secret, err := buildSecretConfiguration(namespace, apiKey, apiSecret) + if err != nil { + return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate Kubernetes secret")} } + // Serialize the secret to YAML secretFile, err := createSecretFile(output) if err != nil { return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} } defer secretFile.Close() - buf := bytes.NewBuffer([]byte{}) - - err = secretTemplate.Execute(buf, input) + _, err = secretFile.Write(secret) if err != nil { return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} } - _, err = secretFile.Write(buf.Bytes()) - if err != nil { - return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to read generated secret file")} - } - - return buf.String(), nil + return string(secret), nil } // Creates a file at the give path to be used for storing of the generated Secret config diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go index 8c977468..571640f6 100644 --- a/cmd/internal/kube/secret_test.go +++ b/cmd/internal/kube/secret_test.go @@ -2,9 +2,13 @@ package kube import ( _ "embed" + "encoding/json" "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "os" "path/filepath" + "sigs.k8s.io/yaml" "testing" ) @@ -23,17 +27,50 @@ func Test_secretGeneration(t *testing.T) { actualOutput := filepath.Join(dir, "akita-secret.yml") // WHEN - output, err := handleSecretGeneration(namespace, key, secret, actualOutput) + result, err := handleSecretGeneration(namespace, key, secret, actualOutput) if err != nil { t.Errorf("Unexpected error: %s", err) } - generatedFile, err := os.ReadFile(actualOutput) + // THEN + data, err := os.ReadFile(actualOutput) if err != nil { - t.Errorf("Failed to read generated generatedFile: %v", err) + t.Errorf("Failed to read generated data: %v", err) } - // THEN - assert.Equal(t, string(testAkitaSecretYAML), string(generatedFile)) - assert.Equal(t, string(testAkitaSecretYAML), output) + convert := func(yamlBytes []byte) (v1.Secret, error) { + var result v1.Secret + + jsonData, err := yaml.YAMLToJSONStrict(yamlBytes) + if err != nil { + return result, err + } + + var parsedSecret v1.Secret + err = json.Unmarshal(jsonData, &parsedSecret) + + return parsedSecret, err + } + + file, err := convert(data) + output, err := convert([]byte(result)) + + expected := v1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "akita-secrets", + Namespace: namespace, + }, + Type: v1.SecretTypeOpaque, + Data: map[string][]byte{ + "akita-api-key": []byte(key), + "akita-api-secret": []byte(secret), + }, + } + + assert.Equal(t, expected, file) + assert.Equal(t, expected, output) } diff --git a/go.mod b/go.mod index 3e26993e..f87a60d2 100644 --- a/go.mod +++ b/go.mod @@ -19,10 +19,11 @@ require ( github.com/aws/smithy-go v1.13.4 github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 github.com/gdamore/tcell/v2 v2.1.0 + github.com/ghodss/yaml v1.0.0 github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f github.com/golang/mock v1.3.1 github.com/golang/protobuf v1.5.2 - github.com/google/go-cmp v0.5.8 + github.com/google/go-cmp v0.5.9 github.com/google/gopacket v1.1.19 github.com/google/martian/v3 v3.0.1 github.com/google/uuid v1.3.0 @@ -38,12 +39,15 @@ require ( github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.1 - github.com/stretchr/testify v1.7.1 + github.com/stretchr/testify v1.8.0 github.com/yudai/gojsondiff v1.0.0 golang.org/x/exp v0.0.0-20220428152302-39d4317da171 - golang.org/x/term v0.1.0 - golang.org/x/text v0.4.0 + golang.org/x/term v0.5.0 + golang.org/x/text v0.7.0 gopkg.in/yaml.v2 v2.4.0 + k8s.io/api v0.26.3 + k8s.io/apimachinery v0.26.3 + sigs.k8s.io/yaml v1.3.0 ) require ( @@ -61,13 +65,17 @@ require ( github.com/dukex/mixpanel v1.0.1 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/gdamore/encoding v1.0.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect + github.com/google/gofuzz v1.1.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/lucasb-eyer/go-colorful v1.0.3 // indirect github.com/magiconair/properties v1.8.1 // indirect @@ -76,6 +84,8 @@ require ( github.com/mattn/go-runewidth v0.0.10 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect @@ -87,11 +97,16 @@ require ( github.com/spf13/jwalterweatherman v1.0.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/sys v0.5.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.51.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) replace ( diff --git a/go.sum b/go.sum index af6b4bb5..9237e089 100644 --- a/go.sum +++ b/go.sum @@ -129,16 +129,22 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo github.com/gdamore/tcell/v2 v2.0.1-0.20201017141208-acf90d56d591/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA= github.com/gdamore/tcell/v2 v2.1.0 h1:UnSmozHgBkQi2PGsFr+rpdXuAPRRucMegpQp3Z3kDro= github.com/gdamore/tcell/v2 v2.1.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg= github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -172,8 +178,12 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -241,6 +251,8 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -249,6 +261,7 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -257,8 +270,8 @@ github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= @@ -296,11 +309,16 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/muesli/reflow v0.1.0/go.mod h1:I9bWAt7QTg/que/qmUCJBGlj7wEq8OAFBjPNjc6xK4I= github.com/muesli/termenv v0.6.0/go.mod h1:SohX91w6swWA4AYU+QmPx+aSgXhWO0juiyID9UZmbpA= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -313,8 +331,8 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -383,6 +401,7 @@ github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -390,8 +409,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -405,6 +425,7 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.0/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -443,6 +464,7 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -460,11 +482,12 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -475,6 +498,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -508,20 +532,20 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -544,7 +568,9 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -582,15 +608,18 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -604,10 +633,25 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.26.3 h1:emf74GIQMTik01Aum9dPP0gAypL8JTLl/lHa4V9RFSU= +k8s.io/api v0.26.3/go.mod h1:PXsqwPMXBSBcL1lJ9CYDKy7kIReUydukS5JiRlxC3qE= +k8s.io/apimachinery v0.26.3 h1:dQx6PNETJ7nODU3XPtrwkfuubs6w7sX0M8n61zHIV/k= +k8s.io/apimachinery v0.26.3/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=