From 746248e11c3d6193e933d16163fc41969514dcd8 Mon Sep 17 00:00:00 2001 From: versilis Date: Mon, 13 Mar 2023 14:47:55 -0500 Subject: [PATCH 01/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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 4490c527c5d631f3e89899755ec6bb4f5446ac1d Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 15:54:39 -0500 Subject: [PATCH 22/25] Only print when no file is specified --- cmd/internal/kube/secret.go | 71 ++++++++++++++++++++++---------- cmd/internal/kube/secret_test.go | 15 +------ 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index d7d01ae0..d70b4a9c 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -16,8 +16,8 @@ import ( ) var ( - outputFlag string - namespaceFlag string + secretFilePathFlag string + namespaceFlag string // Store a parsed representation of /template/akita-secret.tmpl secretTemplate *template.Template ) @@ -31,14 +31,24 @@ var secretCmd = &cobra.Command{ return err } - output, err := handleSecretGeneration(namespaceFlag, key, secret, outputFlag) + output, err := handleSecretGeneration(namespaceFlag, key, secret) if err != nil { return err } - // Output the generated secret to the console - printer.RawOutput(output) + // If the secret file path flag hasn't been set, print the generated secret to stdout + if secretFilePathFlag == "" { + printer.RawOutput(string(output)) + return nil + } + // Otherwise, write the generated secret to the given file path + err = writeSecretFile(output, secretFilePathFlag) + if err != nil { + return cmderr.AkitaErr{Err: errors.Wrapf(err, "Failed to write generated secret to %s", output)} + } + + printer.Infof("Generated Kubernetes secret file to %s", secretFilePathFlag) return nil }, // Override the parent command's PersistentPreRun to prevent any logs from being printed. @@ -69,9 +79,10 @@ func initSecretTemplate() error { // 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, key, secret string) ([]byte, error) { + err := initSecretTemplate() + if err != nil { + return nil, cmderr.AkitaErr{Err: errors.Wrap(err, "failed to initialize secret template")} } input := secretTemplateInput{ @@ -80,31 +91,43 @@ func handleSecretGeneration(namespace, key, secret, output string) (string, erro APISecret: base64.StdEncoding.EncodeToString([]byte(secret)), } - secretFile, err := createSecretFile(output) + buf := bytes.NewBuffer([]byte{}) + + err = secretTemplate.Execute(buf, input) if err != nil { - return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to create output file")} + return nil, cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} } - defer secretFile.Close() - buf := bytes.NewBuffer([]byte{}) + return buf.Bytes(), nil +} - err = secretTemplate.Execute(buf, input) +// Writes the generated secret to the given file path +func writeSecretFile(data []byte, filePath string) error { + secretFile, err := createSecretFile(filePath) if err != nil { - return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to generate template")} + return cmderr.AkitaErr{ + Err: cmderr.AkitaErr{ + Err: errors.Wrapf( + err, + "failed to create secret file %s", + filePath, + ), + }, + } } + defer secretFile.Close() - _, err = secretFile.Write(buf.Bytes()) + _, err = secretFile.Write(data) if err != nil { - return "", cmderr.AkitaErr{Err: errors.Wrap(err, "failed to read generated secret file")} + return cmderr.AkitaErr{Err: errors.Wrap(err, "failed to write generated secret file")} } - return buf.String(), nil + 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. +// Creates a file at the give path to be used for storing of the generated Secret configuration func createSecretFile(path string) (*os.File, error) { - // Split the outut flag value into directory and filename + // Split the output flag value into directory and filename outputDir, outputName := filepath.Split(path) // Get the absolute path of the output directory @@ -142,7 +165,13 @@ func init() { "The Kubernetes namespace the secret should be applied to", ) - secretCmd.Flags().StringVarP(&outputFlag, "output", "o", "akita-secret.yml", "File to output the generated secret.") + secretCmd.Flags().StringVarP( + &secretFilePathFlag, + "file", + "f", + "", + "File to output the generated secret. If not set, the secret will be printed to stdout.", + ) Cmd.AddCommand(secretCmd) } diff --git a/cmd/internal/kube/secret_test.go b/cmd/internal/kube/secret_test.go index 8c977468..710719eb 100644 --- a/cmd/internal/kube/secret_test.go +++ b/cmd/internal/kube/secret_test.go @@ -3,8 +3,6 @@ package kube import ( _ "embed" "github.com/stretchr/testify/assert" - "os" - "path/filepath" "testing" ) @@ -19,21 +17,12 @@ func Test_secretGeneration(t *testing.T) { secret = "api-secret" ) - dir := t.TempDir() - actualOutput := filepath.Join(dir, "akita-secret.yml") - // WHEN - output, err := handleSecretGeneration(namespace, key, secret, actualOutput) + output, err := handleSecretGeneration(namespace, key, secret) if err != nil { t.Errorf("Unexpected error: %s", err) } - generatedFile, err := os.ReadFile(actualOutput) - if err != nil { - t.Errorf("Failed to read generated generatedFile: %v", err) - } - // THEN - assert.Equal(t, string(testAkitaSecretYAML), string(generatedFile)) - assert.Equal(t, string(testAkitaSecretYAML), output) + assert.Equal(t, testAkitaSecretYAML, output) } From ce8ba09ca4c2d89d3c55ae5a0b7eba37dfd4cf8d Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 18:07:56 -0500 Subject: [PATCH 23/25] Fix doc comment --- cmd/internal/kube/secret.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index d70b4a9c..5a38e7f8 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -125,7 +125,8 @@ func writeSecretFile(data []byte, filePath string) error { return nil } -// Creates a file at the give path to be used for storing of the generated Secret configuration +// Creates a file at the given path to be used for storing of the generated Secret configuration +// If the directory provided does not exist, an error will be returned and the file will not be created func createSecretFile(path string) (*os.File, error) { // Split the output flag value into directory and filename outputDir, outputName := filepath.Split(path) From 058e72cc3610e5d4bf8c950b472b241adac4c988 Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 18:18:51 -0500 Subject: [PATCH 24/25] Use null analytics client by default --- pcap/stream_test.go | 2 -- telemetry/telemetry.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pcap/stream_test.go b/pcap/stream_test.go index 7735db26..ca16ae19 100644 --- a/pcap/stream_test.go +++ b/pcap/stream_test.go @@ -2,7 +2,6 @@ package pcap import ( "fmt" - "github.com/akitasoftware/akita-cli/telemetry" "net" "testing" "time" @@ -128,7 +127,6 @@ func runTCPFlowTestCase(c tcpFlowTestCase) error { } func TestTCPFlow(t *testing.T) { - telemetry.Init(false) testCases := []tcpFlowTestCase{ { name: "unparsable single byte", diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index b92de012..c9779691 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -18,7 +18,7 @@ import ( var ( // Shared client object - analyticsClient analytics.Client + analyticsClient analytics.Client = nullClient{} // Is analytics enabled? analyticsEnabled bool From 44ba56bcadb842a46efb3404cd271e3356ff7200 Mon Sep 17 00:00:00 2001 From: versilis Date: Tue, 21 Mar 2023 18:46:52 -0500 Subject: [PATCH 25/25] Add contextual information on successful file generation --- cmd/internal/kube/secret.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/internal/kube/secret.go b/cmd/internal/kube/secret.go index 5a38e7f8..5d0161db 100644 --- a/cmd/internal/kube/secret.go +++ b/cmd/internal/kube/secret.go @@ -48,7 +48,8 @@ var secretCmd = &cobra.Command{ return cmderr.AkitaErr{Err: errors.Wrapf(err, "Failed to write generated secret to %s", output)} } - printer.Infof("Generated Kubernetes secret file to %s", secretFilePathFlag) + printer.Infof("Successfully generated a Kubernetes Secret file for Akita at %s\n", secretFilePathFlag) + printer.Infof("To apply, run: kubectl apply -f %s\n", secretFilePathFlag) return nil }, // Override the parent command's PersistentPreRun to prevent any logs from being printed.