diff --git a/cmd/kubectl-testkube/commands/cloud.go b/cmd/kubectl-testkube/commands/cloud.go index e9902c9aa2d..3565134aac0 100644 --- a/cmd/kubectl-testkube/commands/cloud.go +++ b/cmd/kubectl-testkube/commands/cloud.go @@ -3,7 +3,7 @@ package commands import ( "github.com/spf13/cobra" - "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/cloud" + "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/pro" "github.com/kubeshop/testkube/pkg/ui" ) @@ -15,15 +15,15 @@ func NewCloudCmd() *cobra.Command { Hidden: true, Short: "[Deprecated] Testkube Cloud commands", Aliases: []string{"cl"}, - Run: func(cmd *cobra.Command, args []string) { - ui.Warn("You are using a deprecated command, please switch to `testkube pro`.") + PersistentPreRun: func(cmd *cobra.Command, args []string) { + ui.Errf("You are using a deprecated command, please switch to `testkube pro` prefix.\n\n") }, } - cmd.AddCommand(cloud.NewConnectCmd()) - cmd.AddCommand(cloud.NewDisconnectCmd()) - cmd.AddCommand(cloud.NewInitCmd()) - cmd.AddCommand(cloud.NewLoginCmd()) + cmd.AddCommand(pro.NewConnectCmd()) + cmd.AddCommand(pro.NewDisconnectCmd()) + cmd.AddCommand(pro.NewInitCmd()) + cmd.AddCommand(pro.NewLoginCmd()) return cmd } diff --git a/cmd/kubectl-testkube/commands/cloud/connect.go b/cmd/kubectl-testkube/commands/cloud/connect.go deleted file mode 100644 index 1ffb4b58d99..00000000000 --- a/cmd/kubectl-testkube/commands/cloud/connect.go +++ /dev/null @@ -1,215 +0,0 @@ -package cloud - -import ( - "fmt" - "os" - "strings" - - "github.com/pterm/pterm" - "github.com/spf13/cobra" - - "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" - "github.com/kubeshop/testkube/cmd/kubectl-testkube/config" - cloudclient "github.com/kubeshop/testkube/pkg/cloud/client" - "github.com/kubeshop/testkube/pkg/ui" -) - -const ( - listenAddr = "127.0.0.1:8090" - docsUrl = "https://docs.testkube.io/testkube-pro/intro" - tokenQueryParam = "token" -) - -func NewConnectCmd() *cobra.Command { - var opts = common.HelmOptions{} - - cmd := &cobra.Command{ - Use: "connect", - Deprecated: "Use `testkube pro connect` instead", - Hidden: true, - Aliases: []string{"c"}, - Short: "[Deprecated] Testkube Cloud connect ", - Run: func(cmd *cobra.Command, args []string) { - ui.Warn("You are using a deprecated command, please switch to `testkube pro connect`.") - - os.Exit(1) - - client, _, err := common.GetClient(cmd) - ui.ExitOnError("getting client", err) - - info, err := client.GetServerInfo() - firstInstall := err != nil && strings.Contains(err.Error(), "not found") - if err != nil && !firstInstall { - ui.Failf("Can't get testkube cluster information: %s", err.Error()) - } - - var apiContext string - if actx, ok := contextDescription[info.Context]; ok { - apiContext = actx - } - - ui.H1("Connect your cloud environment:") - ui.Paragraph("You can learn more about connecting your Testkube instance to the Cloud here:\n" + docsUrl) - ui.H2("You can safely switch between connecting Cloud and disconnecting without losing your data.") - - cfg, err := config.Load() - ui.ExitOnError("loading config", err) - - common.ProcessMasterFlags(cmd, &opts, &cfg) - - var clusterContext string - if cfg.ContextType == config.ContextTypeKubeconfig { - clusterContext, err = common.GetCurrentKubernetesContext() - ui.ExitOnError("getting current kubernetes context", err) - } - - // TODO: implement context info - ui.H1("Current status of your Testkube instance") - ui.Properties([][]string{ - {"Context", apiContext}, - {"Kubectl context", clusterContext}, - {"Namespace", cfg.Namespace}, - }) - - newStatus := [][]string{ - {"Testkube mode"}, - {"Context", contextDescription["cloud"]}, - {"Kubectl context", clusterContext}, - {"Namespace", cfg.Namespace}, - {ui.Separator, ""}, - } - - var ( - token string - refreshToken string - ) - // if no agent is passed create new environment and get its token - if opts.Master.AgentToken == "" && opts.Master.OrgId == "" && opts.Master.EnvId == "" { - token, refreshToken, err = common.LoginUser(opts.Master.URIs.Auth) - ui.ExitOnError("login", err) - - orgId, orgName, err := common.UiGetOrganizationId(opts.Master.URIs.Api, token) - ui.ExitOnError("getting organization", err) - - envName, err := uiGetEnvName() - ui.ExitOnError("getting environment name", err) - - envClient := cloudclient.NewEnvironmentsClient(opts.Master.URIs.Api, token, orgId) - env, err := envClient.Create(cloudclient.Environment{Name: envName, Owner: orgId}) - ui.ExitOnError("creating environment", err) - - opts.Master.OrgId = orgId - opts.Master.EnvId = env.Id - opts.Master.AgentToken = env.AgentToken - - newStatus = append( - newStatus, - [][]string{ - {"Testkube will be connected to cloud org/env"}, - {"Organization Id", opts.Master.OrgId}, - {"Organization name", orgName}, - {"Environment Id", opts.Master.EnvId}, - {"Environment name", env.Name}, - {ui.Separator, ""}, - }...) - } - - // validate if user created env - or was passed from flags - if opts.Master.EnvId == "" { - ui.Failf("You need pass valid environment id to connect to cloud") - } - if opts.Master.OrgId == "" { - ui.Failf("You need pass valid organization id to connect to cloud") - } - - // update summary - newStatus = append(newStatus, []string{"Testkube support services not needed anymore"}) - newStatus = append(newStatus, []string{"MinIO ", "Stopped and scaled down, (not deleted)"}) - newStatus = append(newStatus, []string{"MongoDB ", "Stopped and scaled down, (not deleted)"}) - newStatus = append(newStatus, []string{"Dashboard", "Stopped and scaled down, (not deleted)"}) - - ui.NL(2) - - ui.H1("Summary of your setup after connecting to Testkube Cloud") - ui.Properties(newStatus) - - ui.NL() - ui.Warn("Remember: All your historical data and artifacts will be safe in case you want to rollback. OSS and cloud executions will be separated.") - ui.NL() - - if ok := ui.Confirm("Proceed with connecting Testkube Cloud?"); !ok { - return - } - - spinner := ui.NewSpinner("Connecting Testkube Cloud") - err = common.HelmUpgradeOrInstallTestkubeCloud(opts, cfg, true) - ui.ExitOnError("Installing Testkube Cloud", err) - spinner.Success() - - ui.NL() - - // let's scale down deployment of mongo - if opts.MongoReplicas == 0 { - spinner = ui.NewSpinner("Scaling down MongoDB") - common.KubectlScaleDeployment(opts.Namespace, "testkube-mongodb", opts.MongoReplicas) - spinner.Success() - } - if opts.MinioReplicas == 0 { - spinner = ui.NewSpinner("Scaling down MinIO") - common.KubectlScaleDeployment(opts.Namespace, "testkube-minio-testkube", opts.MinioReplicas) - spinner.Success() - } - if opts.DashboardReplicas == 0 { - spinner = ui.NewSpinner("Scaling down Dashbaord") - common.KubectlScaleDeployment(opts.Namespace, "testkube-dashboard", opts.DashboardReplicas) - spinner.Success() - } - - ui.H2("Testkube Cloud is connected to your Testkube instance, saving local configuration") - - ui.H2("Saving testkube cli cloud context") - if token == "" && !common.IsUserLoggedIn(cfg, opts) { - token, refreshToken, err = common.LoginUser(opts.Master.URIs.Auth) - ui.ExitOnError("user login", err) - } - err = common.PopulateLoginDataToContext(opts.Master.OrgId, opts.Master.EnvId, token, refreshToken, opts, cfg) - - ui.ExitOnError("Setting cloud environment context", err) - - ui.NL(2) - - ui.ShellCommand("In case you want to roll back you can simply run the following command in your CLI:", "testkube cloud disconnect") - - ui.Success("You can now login to Testkube Cloud and validate your connection:") - ui.NL() - ui.Link(opts.Master.URIs.Ui + "/organization/" + opts.Master.OrgId + "/environment/" + opts.Master.EnvId + "/dashboard/tests") - - ui.NL(2) - }, - } - - common.PopulateHelmFlags(cmd, &opts) - common.PopulateMasterFlags(cmd, &opts) - - cmd.Flags().IntVar(&opts.MinioReplicas, "minio-replicas", 0, "MinIO replicas") - cmd.Flags().IntVar(&opts.MongoReplicas, "mongo-replicas", 0, "MongoDB replicas") - cmd.Flags().IntVar(&opts.DashboardReplicas, "dashboard-replicas", 0, "Dashboard replicas") - return cmd -} - -var contextDescription = map[string]string{ - "": "Unknown context, try updating your testkube cluster installation", - "oss": "Open Source Testkube", - "cloud": "Testkube in Cloud mode", -} - -func uiGetEnvName() (string, error) { - for i := 0; i < 3; i++ { - if envName := ui.TextInput("Tell us the name of your environment"); envName != "" { - return envName, nil - } - pterm.Error.Println("Environment name cannot be empty") - } - - return "", fmt.Errorf("environment name cannot be empty") -} diff --git a/cmd/kubectl-testkube/commands/cloud/disconnect.go b/cmd/kubectl-testkube/commands/cloud/disconnect.go deleted file mode 100644 index ad5de8a30db..00000000000 --- a/cmd/kubectl-testkube/commands/cloud/disconnect.go +++ /dev/null @@ -1,120 +0,0 @@ -package cloud - -import ( - "strings" - - "github.com/pterm/pterm" - - "github.com/spf13/cobra" - - "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" - "github.com/kubeshop/testkube/cmd/kubectl-testkube/config" - "github.com/kubeshop/testkube/pkg/ui" -) - -func NewDisconnectCmd() *cobra.Command { - - var opts common.HelmOptions - - cmd := &cobra.Command{ - Use: "disconnect", - Deprecated: "Use `testkube pro disconnect` instead", - Hidden: true, - Aliases: []string{"d"}, - Short: "[Deprecated] Switch back to Testkube OSS mode, based on active .kube/config file", - Run: func(cmd *cobra.Command, args []string) { - ui.Warn("You are using a deprecated command, please switch to `testkube pro disconnect`.") - - ui.H1("Disconnecting your cloud environment:") - ui.Paragraph("Rolling back to your clusters testkube OSS installation") - ui.Paragraph("If you need more details click into following link: " + docsUrl) - ui.H2("You can safely switch between connecting Cloud and disconnecting without losing your data.") - - cfg, err := config.Load() - if err != nil { - pterm.Error.Printfln("Failed to load config file: %s", err.Error()) - return - } - - client, _, err := common.GetClient(cmd) - ui.ExitOnError("getting client", err) - - info, err := client.GetServerInfo() - firstInstall := err != nil && strings.Contains(err.Error(), "not found") - if err != nil && !firstInstall { - ui.Failf("Can't get testkube cluster information: %s", err.Error()) - } - var apiContext string - if actx, ok := contextDescription[info.Context]; ok { - apiContext = actx - } - var clusterContext string - if cfg.ContextType == config.ContextTypeKubeconfig { - clusterContext, err = common.GetCurrentKubernetesContext() - if err != nil { - pterm.Error.Printfln("Failed to get current kubernetes context: %s", err.Error()) - return - } - } - - // TODO: implement context info - ui.H1("Current status of your Testkube instance") - - summary := [][]string{ - {"Testkube mode"}, - {"Context", apiContext}, - {"Kubectl context", clusterContext}, - {"Namespace", cfg.Namespace}, - {ui.Separator, ""}, - - {"Testkube is connected to cloud organizations environment"}, - {"Organization Id", info.OrgId}, - {"Environment Id", info.EnvId}, - } - - ui.Properties(summary) - - if ok := ui.Confirm("Shall we disconnect your cloud environment now?"); !ok { - return - } - - ui.NL(2) - - spinner := ui.NewSpinner("Disonnecting from Testkube Cloud") - - err = common.HelmUpgradeOrInstalTestkube(opts) - ui.ExitOnError("Installing Testkube Cloud", err) - spinner.Success() - - // let's scale down deployment of mongo - if opts.MongoReplicas > 0 { - spinner = ui.NewSpinner("Scaling up MongoDB") - common.KubectlScaleDeployment(opts.Namespace, "testkube-mongodb", opts.MongoReplicas) - spinner.Success() - } - if opts.MinioReplicas > 0 { - spinner = ui.NewSpinner("Scaling up MinIO") - common.KubectlScaleDeployment(opts.Namespace, "testkube-minio-testkube", opts.MinioReplicas) - spinner.Success() - } - if opts.DashboardReplicas > 0 { - spinner = ui.NewSpinner("Scaling up Dashbaord") - common.KubectlScaleDeployment(opts.Namespace, "testkube-dashboard", opts.DashboardReplicas) - spinner.Success() - } - - ui.NL() - ui.Success("Disconnect finished successfully") - ui.NL() - ui.ShellCommand("You can now open your local Dashboard and validate the successfull disconnect", "testkube dashboard") - }, - } - - // populate options - common.PopulateHelmFlags(cmd, &opts) - cmd.Flags().IntVar(&opts.MinioReplicas, "minio-replicas", 1, "MinIO replicas") - cmd.Flags().IntVar(&opts.MongoReplicas, "mongo-replicas", 1, "MongoDB replicas") - cmd.Flags().IntVar(&opts.DashboardReplicas, "dashboard-replicas", 1, "Dashboard replicas") - - return cmd -} diff --git a/cmd/kubectl-testkube/commands/cloud/init.go b/cmd/kubectl-testkube/commands/cloud/init.go deleted file mode 100644 index c976585c25c..00000000000 --- a/cmd/kubectl-testkube/commands/cloud/init.go +++ /dev/null @@ -1,119 +0,0 @@ -package cloud - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" - "github.com/kubeshop/testkube/cmd/kubectl-testkube/config" - "github.com/kubeshop/testkube/pkg/telemetry" - "github.com/kubeshop/testkube/pkg/ui" -) - -func NewInitCmd() *cobra.Command { - options := common.HelmOptions{ - NoMinio: true, - NoMongo: true, - NoDashboard: true, - } - - cmd := &cobra.Command{ - Use: "init", - Deprecated: "Use `testkube pro init` instead", - Hidden: true, - Short: "[Deprecated] Install Testkube Cloud Agent and connect to Testkube Cloud environment", - Aliases: []string{"install"}, - Run: func(cmd *cobra.Command, args []string) { - ui.Warn("You are using a deprecated command, please switch to `testkube pro init`.") - - ui.Info("WELCOME TO") - ui.Logo() - - cfg, err := config.Load() - ui.ExitOnError("loading config file", err) - ui.NL() - - common.ProcessMasterFlags(cmd, &options, &cfg) - - sendAttemptTelemetry(cmd, cfg) - - // create new cloud uris - if !options.NoConfirm { - ui.Warn("This will install Testkube to the latest version. This may take a few minutes.") - ui.Warn("Please be sure you're on valid kubectl context before continuing!") - ui.NL() - - currentContext, err := common.GetCurrentKubernetesContext() - if err != nil { - sendErrTelemetry(cmd, cfg, "k8s_context", err) - ui.ExitOnError("getting current context", err) - } - ui.Alert("Current kubectl context:", currentContext) - ui.NL() - - ok := ui.Confirm("Do you want to continue?") - if !ok { - ui.Errf("Testkube installation cancelled") - sendErrTelemetry(cmd, cfg, "user_cancel", err) - return - } - } - - spinner := ui.NewSpinner("Installing Testkube") - err = common.HelmUpgradeOrInstallTestkubeCloud(options, cfg, false) - if err != nil { - sendErrTelemetry(cmd, cfg, "helm_install", err) - ui.ExitOnError("Installing Testkube", err) - } - spinner.Success() - - ui.NL() - - ui.H2("Saving testkube cli cloud context") - var token, refreshToken string - if !common.IsUserLoggedIn(cfg, options) { - token, refreshToken, err = common.LoginUser(options.Master.URIs.Auth) - sendErrTelemetry(cmd, cfg, "login", err) - ui.ExitOnError("user login", err) - } - err = common.PopulateLoginDataToContext(options.Master.OrgId, options.Master.EnvId, token, refreshToken, options, cfg) - sendErrTelemetry(cmd, cfg, "setting_context", err) - ui.ExitOnError("Setting cloud environment context", err) - - ui.Info(" Happy Testing! 🚀") - ui.NL() - }, - } - - common.PopulateHelmFlags(cmd, &options) - common.PopulateMasterFlags(cmd, &options) - - cmd.Flags().BoolVar(&options.MultiNamespace, "multi-namespace", false, "multi namespace mode") - cmd.Flags().BoolVar(&options.NoOperator, "no-operator", false, "should operator be installed (for more instances in multi namespace mode it should be set to true)") - return cmd -} - -func sendErrTelemetry(cmd *cobra.Command, clientCfg config.Data, errType string, errorLogs error) { - var errorStackTrace string - errorStackTrace = fmt.Sprintf("%+v", errorLogs) - if clientCfg.TelemetryEnabled { - ui.Debug("collecting anonymous telemetry data, you can disable it by calling `kubectl testkube disable telemetry`") - out, err := telemetry.SendCmdErrorEvent(cmd, common.Version, errType, errorStackTrace) - if ui.Verbose && err != nil { - ui.Err(err) - } - ui.Debug("telemetry send event response", out) - } -} - -func sendAttemptTelemetry(cmd *cobra.Command, clientCfg config.Data) { - if clientCfg.TelemetryEnabled { - ui.Debug("collecting anonymous telemetry data, you can disable it by calling `kubectl testkube disable telemetry`") - out, err := telemetry.SendCmdAttemptEvent(cmd, common.Version) - if ui.Verbose && err != nil { - ui.Err(err) - } - ui.Debug("telemetry send event response", out) - } -} diff --git a/cmd/kubectl-testkube/commands/cloud/login.go b/cmd/kubectl-testkube/commands/cloud/login.go deleted file mode 100644 index 44970cd7c20..00000000000 --- a/cmd/kubectl-testkube/commands/cloud/login.go +++ /dev/null @@ -1,52 +0,0 @@ -package cloud - -import ( - "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" - "github.com/kubeshop/testkube/cmd/kubectl-testkube/config" - "github.com/kubeshop/testkube/pkg/ui" - - "github.com/spf13/cobra" -) - -func NewLoginCmd() *cobra.Command { - var opts common.HelmOptions - - cmd := &cobra.Command{ - Use: "login", - Deprecated: "Use `testkube pro login` instead", - Hidden: true, - Aliases: []string{"l"}, - Short: "[Deprecated] Login to Testkube Pro", - Run: func(cmd *cobra.Command, args []string) { - token, refreshToken, err := common.LoginUser(opts.Master.URIs.Auth) - ui.ExitOnError("getting token", err) - - orgID := opts.Master.OrgId - envID := opts.Master.EnvId - - if orgID == "" { - orgID, _, err = common.UiGetOrganizationId(opts.Master.URIs.Api, token) - ui.ExitOnError("getting organization", err) - } - if envID == "" { - envID, _, err = common.UiGetEnvironmentID(opts.Master.URIs.Api, token, orgID) - ui.ExitOnError("getting environment", err) - } - cfg, err := config.Load() - ui.ExitOnError("loading config file", err) - - common.ProcessMasterFlags(cmd, &opts, &cfg) - - err = common.PopulateLoginDataToContext(orgID, envID, token, refreshToken, opts, cfg) - ui.ExitOnError("saving config file", err) - - ui.Success("Your config was updated with new values") - ui.NL() - common.UiPrintContext(cfg) - }, - } - - common.PopulateMasterFlags(cmd, &opts) - - return cmd -}