Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: validate cloud context on root cmd #4033

Merged
merged 9 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/kubectl-testkube/commands/abort.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/validator"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/tests"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsuites"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -20,6 +21,10 @@ func NewAbortCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

validator.PersistentPreRunVersionCheck(cmd, common.Version)
}}

Expand Down
2 changes: 0 additions & 2 deletions cmd/kubectl-testkube/commands/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ func NewAgentCmd() *cobra.Command {
ui.Info("Build date", common.Date)

},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
},
}

cmd.AddCommand(agent.NewAgentDebugCmd())
Expand Down
4 changes: 2 additions & 2 deletions cmd/kubectl-testkube/commands/cloud/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func NewLoginCmd() *cobra.Command {
ui.ExitOnError("loading config file", err)

cfg.ContextType = config.ContextTypeCloud
cfg.CloudContext.Organization = orgID
cfg.CloudContext.Environment = envID
cfg.CloudContext.OrganizationId = orgID
cfg.CloudContext.EnvironmentId = envID

uris := opts.CloudUris
cfg.CloudContext.ApiUri = uris.Api
Expand Down
6 changes: 3 additions & 3 deletions cmd/kubectl-testkube/commands/common/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ func GetClient(cmd *cobra.Command) (client.Client, string, error) {
}
case config.ContextTypeCloud:
clientType = string(client.ClientCloud)
options.CloudApiPathPrefix = fmt.Sprintf("/organizations/%s/environments/%s/agent", cfg.CloudContext.Organization, cfg.CloudContext.Environment)
options.CloudApiPathPrefix = fmt.Sprintf("/organizations/%s/environments/%s/agent", cfg.CloudContext.OrganizationId, cfg.CloudContext.EnvironmentId)
options.CloudApiKey = cfg.CloudContext.ApiKey
options.CloudEnvironment = cfg.CloudContext.Environment
options.CloudOrganization = cfg.CloudContext.Organization
options.CloudEnvironment = cfg.CloudContext.EnvironmentId
options.CloudOrganization = cfg.CloudContext.OrganizationId
options.ApiUri = cfg.CloudContext.ApiUri
}

Expand Down
60 changes: 58 additions & 2 deletions cmd/kubectl-testkube/commands/common/cloudcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package common

import (
"fmt"
"regexp"
"strings"

"github.com/spf13/cobra"

"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
Expand All @@ -14,8 +18,8 @@ func UiPrintContext(cfg config.Data) {

if cfg.ContextType == config.ContextTypeCloud {
contextData := map[string]string{
"Organization ID": cfg.CloudContext.Organization,
"Environment ID ": cfg.CloudContext.Environment,
"Organization": cfg.CloudContext.OrganizationName + ui.DarkGray(" ("+cfg.CloudContext.OrganizationId+")"),
"Environment": cfg.CloudContext.EnvironmentName + ui.DarkGray(" ("+cfg.CloudContext.EnvironmentId+")"),
"API Key ": text.Obfuscate(cfg.CloudContext.ApiKey),
"API URI ": cfg.CloudContext.ApiUri,
"Namespace ": cfg.Namespace,
Expand All @@ -35,3 +39,55 @@ func UiPrintContext(cfg config.Data) {
})
}
}

func UiCloudContextValidationError(err error) {
ui.NL()
ui.Errf("Validating cloud context failed: %s", err.Error())
ui.NL()
ui.Info("Please set valid cloud context using `testkube set context` with valid values")
ui.NL()
ui.ShellCommand(" testkube set context -c cloud -e tkcenv_XXX -o tkcorg_XXX -k tkcapi_XXX")
ui.NL()
}

func UiContextHeader(cmd *cobra.Command, cfg config.Data) {
// only show header when output is pretty
if cmd.Flag("output") != nil && cmd.Flag("output").Value.String() != "pretty" {
return
}

header := "\n"
separator := " "

orgName := cfg.CloudContext.OrganizationName
if orgName == "" {
orgName = cfg.CloudContext.OrganizationId
}
envName := cfg.CloudContext.EnvironmentName
if envName == "" {
envName = cfg.CloudContext.EnvironmentId
}

if cfg.ContextType == config.ContextTypeCloud {
header += ui.DarkGray("Context: ") + ui.White(cfg.ContextType) + ui.DarkGray(" ("+Version+")") + separator
header += ui.DarkGray("Namespace: ") + ui.White(cfg.Namespace) + separator
header += ui.DarkGray("Org: ") + ui.White(orgName) + separator
header += ui.DarkGray("Env: ") + ui.White(envName)
} else {
header += ui.DarkGray("Context: ") + ui.White(cfg.ContextType) + ui.DarkGray(" ("+Version+")") + separator
header += ui.DarkGray("Namespace: ") + ui.White(cfg.Namespace)
}

fmt.Println(header)
fmt.Println(strings.Repeat("─", calculateStringSize(header)))
}

// calculateStringSize calculates the length of a string, excluding shell color codes.
func calculateStringSize(s string) int {
// Regular expression to match ANSI escape codes.
re := regexp.MustCompile(`\x1b[^m]*m`)
// Remove the escape codes from the string.
s = re.ReplaceAllString(s, "")
// Return the length of the string.
return len(s) - 1
}
4 changes: 2 additions & 2 deletions cmd/kubectl-testkube/commands/common/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ func PopulateLoginDataToContext(orgID, envID, token string, options HelmOptions,
cfg.CloudContext.ApiUri = options.CloudUris.Api
}
cfg.ContextType = config.ContextTypeCloud
cfg.CloudContext.Organization = orgID
cfg.CloudContext.Environment = envID
cfg.CloudContext.OrganizationId = orgID
cfg.CloudContext.EnvironmentId = envID
cfg.CloudContext.ApiKey = token

return config.Save(cfg)
Expand Down
31 changes: 31 additions & 0 deletions cmd/kubectl-testkube/commands/common/validator/cloudcontext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package validator

import (
"errors"

"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
)

func ValidateCloudContext(cfg config.Data) error {
if cfg.ContextType != config.ContextTypeCloud {
return nil
}

if cfg.CloudContext.ApiUri == "" {
return errors.New("please provide Testkube Cloud URI")
}

if cfg.CloudContext.ApiKey == "" {
return errors.New("please provide Testkube Cloud API token")
}

if cfg.CloudContext.EnvironmentId == "" {
return errors.New("please provide Environment")
}

if cfg.CloudContext.OrganizationId == "" {
return errors.New("please provide Organization")
}

return nil
}
25 changes: 22 additions & 3 deletions cmd/kubectl-testkube/commands/context/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"github.com/spf13/cobra"

"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/validator"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
cloudclient "github.com/kubeshop/testkube/pkg/cloud/client"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand Down Expand Up @@ -38,14 +40,14 @@ func NewSetContextCmd() *cobra.Command {
}

if org != "" {
cfg.CloudContext.Organization = org
cfg.CloudContext.OrganizationId = org
// reset env when the org is changed
if env == "" {
cfg.CloudContext.Environment = ""
cfg.CloudContext.EnvironmentId = ""
}
}
if env != "" {
cfg.CloudContext.Environment = env
cfg.CloudContext.EnvironmentId = env
}
if apiKey != "" {
cfg.CloudContext.ApiKey = apiKey
Expand All @@ -57,6 +59,18 @@ func NewSetContextCmd() *cobra.Command {
cfg.CloudContext.UiUri = uris.Ui
cfg.CloudContext.AgentUri = uris.Agent

orgClient := cloudclient.NewOrganizationsClient(rootDomain, cfg.CloudContext.ApiKey)
ui.ExitOnError("getting client", err)
org, err := orgClient.Get(cfg.CloudContext.OrganizationId)
ui.ExitOnError("getting organization", err)

envsClient := cloudclient.NewEnvironmentsClient(rootDomain, cfg.CloudContext.ApiKey, cfg.CloudContext.OrganizationId)
env, err := envsClient.Get(cfg.CloudContext.EnvironmentId)
ui.ExitOnError("getting environment", err)

cfg.CloudContext.OrganizationName = org.Name
cfg.CloudContext.EnvironmentName = env.Name

case config.ContextTypeKubeconfig:
// kubeconfig special use cases

Expand All @@ -71,9 +85,14 @@ func NewSetContextCmd() *cobra.Command {
err = config.Save(cfg)
ui.ExitOnError("saving config file", err)

if err = validator.ValidateCloudContext(cfg); err != nil {
common.UiCloudContextValidationError(err)
}

ui.Success("Your config was updated with new values")
ui.NL()
common.UiPrintContext(cfg)

},
}

Expand Down
5 changes: 5 additions & 0 deletions cmd/kubectl-testkube/commands/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsources"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsuites"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/webhooks"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -26,6 +27,10 @@ func NewCreateCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

if !crdOnly {
validator.PersistentPreRunVersionCheck(cmd, common.Version)
}
Expand Down
5 changes: 5 additions & 0 deletions cmd/kubectl-testkube/commands/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/validator"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/debug"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -19,6 +20,10 @@ func NewDebugCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

validator.PersistentPreRunVersionCheck(cmd, common.Version)
}}

Expand Down
5 changes: 5 additions & 0 deletions cmd/kubectl-testkube/commands/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsources"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsuites"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/webhooks"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -24,6 +25,10 @@ func NewDeleteCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

validator.PersistentPreRunVersionCheck(cmd, common.Version)
}}

Expand Down
5 changes: 5 additions & 0 deletions cmd/kubectl-testkube/commands/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/validator"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/tests"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -32,6 +33,10 @@ func NewDownloadCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

validator.PersistentPreRunVersionCheck(cmd, common.Version)
}}

Expand Down
6 changes: 6 additions & 0 deletions cmd/kubectl-testkube/commands/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsources"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsuites"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/webhooks"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -27,7 +28,12 @@ func NewGetCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

validator.PersistentPreRunVersionCheck(cmd, common.Version)

}}

cmd.AddCommand(tests.NewGetTestsCmd())
Expand Down
16 changes: 16 additions & 0 deletions cmd/kubectl-testkube/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/cloud"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/validator"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/telemetry"
"github.com/kubeshop/testkube/pkg/ui"
Expand Down Expand Up @@ -62,6 +63,20 @@ var RootCmd = &cobra.Command{
Short: "Testkube entrypoint for kubectl plugin",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
ui.SetVerbose(verbose)

cfg, err := config.Load()
ui.ExitOnError("loading config", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will it run without kubernetes cluster and ability to load/store testkube config?


common.UiContextHeader(cmd, cfg)

// don't validate context before set
if cmd.Name() == "context" {
return
}

if err = validator.ValidateCloudContext(cfg); err != nil {
common.UiCloudContextValidationError(err)
exu marked this conversation as resolved.
Show resolved Hide resolved
}
},

PersistentPostRun: func(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -148,6 +163,7 @@ func Execute() {
RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "", false, "show additional debug messages")
RootCmd.PersistentFlags().StringVarP(&apiURI, "api-uri", "a", apiURI, "api uri, default value read from config if set")
RootCmd.PersistentFlags().BoolVarP(&oauthEnabled, "oauth-enabled", "", cfg.OAuth2Data.Enabled, "enable oauth")

if err := RootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
Expand Down
5 changes: 5 additions & 0 deletions cmd/kubectl-testkube/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common/validator"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/tests"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsuites"
"github.com/kubeshop/testkube/cmd/kubectl-testkube/config"
"github.com/kubeshop/testkube/pkg/ui"
)

Expand All @@ -21,6 +22,10 @@ func NewRunCmd() *cobra.Command {
ui.PrintOnError("Displaying help", err)
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cfg, err := config.Load()
ui.ExitOnError("loading config", err)
common.UiContextHeader(cmd, cfg)

validator.PersistentPreRunVersionCheck(cmd, common.Version)
}}

Expand Down
Loading