diff --git a/cmd/vclusterctl/cmd/login.go b/cmd/vclusterctl/cmd/login.go index a20d009cf..9199bc36d 100644 --- a/cmd/vclusterctl/cmd/login.go +++ b/cmd/vclusterctl/cmd/login.go @@ -3,34 +3,28 @@ package cmd import ( "fmt" + "github.com/loft-sh/api/v3/pkg/product" loftctl "github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd" - loftctlflags "github.com/loft-sh/loftctl/v3/cmd/loftctl/flags" + "github.com/loft-sh/log" "github.com/loft-sh/vcluster/cmd/vclusterctl/flags" "github.com/loft-sh/vcluster/pkg/pro" "github.com/spf13/cobra" ) func NewLoginCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { - loftctlGlobalFlags := &loftctlflags.GlobalFlags{ - Silent: globalFlags.Silent, - Debug: globalFlags.Debug, - LogOutput: globalFlags.LogOutput, + loftctlGlobalFlags, err := pro.GlobalFlags(globalFlags) + if err != nil { + return nil, fmt.Errorf("failed to parse pro flags: %w", err) } - if globalFlags.Config != "" { - loftctlGlobalFlags.Config = globalFlags.Config - } else { - var err error - loftctlGlobalFlags.Config, err = pro.LoftctlConfigFilePath() - if err != nil { - return nil, fmt.Errorf("failed to get vcluster pro configuration file path: %w", err) - } + cmd := &loftctl.LoginCmd{ + GlobalFlags: loftctlGlobalFlags, + Log: log.GetInstance(), } - loginCmd := loftctl.NewLoginCmd(loftctlGlobalFlags) - - loginCmd.Use = "login [VCLUSTER_PRO_HOST]" - loginCmd.Long = `######################################################## + description := `######################################################## +#################### vcluster login #################### +######################################################## Login into vCluster.Pro Example: @@ -39,5 +33,19 @@ vcluster login https://my-vcluster-pro.com --access-key myaccesskey ######################################################## ` + loginCmd := &cobra.Command{ + Use: "login [VCLUSTER_PRO_HOST]", + Short: "Login to a vCluster.Pro instance", + Long: description, + Args: cobra.MaximumNArgs(1), + RunE: func(cobraCmd *cobra.Command, args []string) error { + return cmd.RunLogin(cobraCmd.Context(), args) + }, + } + + loginCmd.Flags().StringVar(&cmd.AccessKey, "access-key", "", "The access key to use") + loginCmd.Flags().BoolVar(&cmd.Insecure, "insecure", false, product.Replace("Allow login into an insecure Loft instance")) + loginCmd.Flags().BoolVar(&cmd.DockerLogin, "docker-login", true, "If true, will log into the docker image registries the user has image pull secrets for") + return loginCmd, nil } diff --git a/cmd/vclusterctl/cmd/logout.go b/cmd/vclusterctl/cmd/logout.go index 95dc7b5fb..d5d8a8fcf 100644 --- a/cmd/vclusterctl/cmd/logout.go +++ b/cmd/vclusterctl/cmd/logout.go @@ -4,33 +4,26 @@ import ( "fmt" loftctl "github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd" - loftctlflags "github.com/loft-sh/loftctl/v3/cmd/loftctl/flags" + "github.com/loft-sh/log" "github.com/loft-sh/vcluster/cmd/vclusterctl/flags" "github.com/loft-sh/vcluster/pkg/pro" "github.com/spf13/cobra" ) func NewLogoutCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { - loftctlGlobalFlags := &loftctlflags.GlobalFlags{ - Silent: globalFlags.Silent, - Debug: globalFlags.Debug, - LogOutput: globalFlags.LogOutput, + loftctlGlobalFlags, err := pro.GlobalFlags(globalFlags) + if err != nil { + return nil, fmt.Errorf("failed to parse pro flags: %w", err) } - if globalFlags.Config != "" { - loftctlGlobalFlags.Config = globalFlags.Config - } else { - var err error - loftctlGlobalFlags.Config, err = pro.LoftctlConfigFilePath() - if err != nil { - return nil, fmt.Errorf("failed to get vcluster pro configuration file path: %w", err) - } + cmd := &loftctl.LogoutCmd{ + GlobalFlags: loftctlGlobalFlags, + Log: log.GetInstance(), } - logoutCmd := loftctl.NewLogoutCmd(loftctlGlobalFlags) - - logoutCmd.Use = "logout" - logoutCmd.Long = `######################################################## + description := `######################################################## +################### vcluster logout #################### +######################################################## Log out of vCluster.Pro Example: @@ -38,5 +31,16 @@ vcluster logout ######################################################## ` + logoutCmd := &cobra.Command{ + Use: "logout", + Short: "Log out of a vCluster.Pro instance", + Long: description, + Args: cobra.NoArgs, + RunE: func(cobraCmd *cobra.Command, args []string) error { + return cmd.RunLogout(cobraCmd.Context(), args) + }, + } + return logoutCmd, nil + } diff --git a/cmd/vclusterctl/cmd/pro/pro.go b/cmd/vclusterctl/cmd/pro/pro.go index 1967a834f..611ad4ec7 100644 --- a/cmd/vclusterctl/cmd/pro/pro.go +++ b/cmd/vclusterctl/cmd/pro/pro.go @@ -3,10 +3,6 @@ package pro import ( "fmt" - loftctl "github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd" - loftctlreset "github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/reset" - loftctlflags "github.com/loft-sh/loftctl/v3/cmd/loftctl/flags" - "github.com/loft-sh/log" "github.com/loft-sh/vcluster/cmd/vclusterctl/flags" "github.com/loft-sh/vcluster/pkg/pro" "github.com/spf13/cobra" @@ -23,20 +19,9 @@ func NewProCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { Args: cobra.NoArgs, } - loftctlGlobalFlags := &loftctlflags.GlobalFlags{ - Silent: globalFlags.Silent, - Debug: globalFlags.Debug, - LogOutput: globalFlags.LogOutput, - } - - if globalFlags.Config != "" { - loftctlGlobalFlags.Config = globalFlags.Config - } else { - var err error - loftctlGlobalFlags.Config, err = pro.LoftctlConfigFilePath() - if err != nil { - return nil, fmt.Errorf("failed to get vcluster pro configuration file path: %w", err) - } + loftctlGlobalFlags, err := pro.GlobalFlags(globalFlags) + if err != nil { + return nil, fmt.Errorf("failed to parse pro flags: %w", err) } startCmd, err := NewStartCmd(loftctlGlobalFlags) @@ -45,41 +30,7 @@ func NewProCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { } proCmd.AddCommand(startCmd) - proCmd.AddCommand(loftctlreset.NewResetCmd(loftctlGlobalFlags)) + proCmd.AddCommand(NewResetCmd(loftctlGlobalFlags)) return proCmd, nil } - -func NewStartCmd(loftctlGlobalFlags *loftctlflags.GlobalFlags) (*cobra.Command, error) { - starCmd := loftctl.NewStartCmd(loftctlGlobalFlags) - - err := starCmd.Flags().Set("product", "vcluster-pro") - if err != nil { - return nil, fmt.Errorf("failed to set product flag: %w", err) - } - - err = starCmd.Flags().Set("chart-name", "vcluster-control-plane") - if err != nil { - return nil, fmt.Errorf("failed to set chart-name flag: %w", err) - } - - starCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { - version := pro.MinimumVersionTag - - latestVersion, err := pro.LatestCompatibleVersion(cmd.Context()) - if err != nil { - log.GetInstance().Warnf("failed to get latest compatible version: %v", err) - } else { - version = latestVersion - } - - err = starCmd.Flags().Set("version", version) - if err != nil { - return fmt.Errorf("failed to set version flag: %w", err) - } - - return nil - } - - return starCmd, nil -} diff --git a/cmd/vclusterctl/cmd/pro/reset.go b/cmd/vclusterctl/cmd/pro/reset.go new file mode 100644 index 000000000..eaf2db3c1 --- /dev/null +++ b/cmd/vclusterctl/cmd/pro/reset.go @@ -0,0 +1,60 @@ +package pro + +import ( + "github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/reset" + loftctlflags "github.com/loft-sh/loftctl/v3/cmd/loftctl/flags" + "github.com/loft-sh/log" + "github.com/spf13/cobra" +) + +func NewResetCmd(loftctlGlobalFlags *loftctlflags.GlobalFlags) *cobra.Command { + description := `######################################################## +################## vcluster pro reset ################## +######################################################## + ` + cmd := &cobra.Command{ + Use: "reset", + Short: "Reset configuration", + Long: description, + Args: cobra.NoArgs, + } + + cmd.AddCommand(NewPasswordCmd(loftctlGlobalFlags)) + + return cmd +} + +func NewPasswordCmd(globalFlags *loftctlflags.GlobalFlags) *cobra.Command { + cmd := &reset.PasswordCmd{ + GlobalFlags: globalFlags, + Log: log.GetInstance(), + } + + description := `######################################################## +############## vcluster pro reset password ############# +######################################################## +Resets the password of a user. + +Example: +vcluster pro reset password +vcluster pro reset password --user admin +####################################################### + ` + + c := &cobra.Command{ + Use: "password", + Short: "Resets the password of a user", + Long: description, + Args: cobra.NoArgs, + RunE: func(cobraCmd *cobra.Command, args []string) error { + return cmd.Run() + }, + } + + c.Flags().StringVar(&cmd.User, "user", "admin", "The name of the user to reset the password") + c.Flags().StringVar(&cmd.Password, "password", "", "The new password to use") + c.Flags().BoolVar(&cmd.Create, "create", false, "Creates the user if it does not exist") + c.Flags().BoolVar(&cmd.Force, "force", false, "If user had no password will create one") + + return c +} diff --git a/cmd/vclusterctl/cmd/pro/start.go b/cmd/vclusterctl/cmd/pro/start.go new file mode 100644 index 000000000..fc6ff87da --- /dev/null +++ b/cmd/vclusterctl/cmd/pro/start.go @@ -0,0 +1,75 @@ +package pro + +import ( + "context" + + loftctl "github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd" + loftctlflags "github.com/loft-sh/loftctl/v3/cmd/loftctl/flags" + "github.com/loft-sh/loftctl/v3/pkg/start" + "github.com/loft-sh/log" + "github.com/loft-sh/vcluster/pkg/pro" + "github.com/spf13/cobra" +) + +func NewStartCmd(loftctlGlobalFlags *loftctlflags.GlobalFlags) (*cobra.Command, error) { + cmd := &loftctl.StartCmd{ + Options: start.Options{ + GlobalFlags: loftctlGlobalFlags, + Log: log.GetInstance(), + Product: "vcluster-pro", + }, + } + + version := pro.MinimumVersionTag + + latestVersion, err := pro.LatestCompatibleVersion(context.TODO()) + if err == nil { + version = latestVersion + } + + startCmd := &cobra.Command{ + Use: "start", + Short: "Start a vCluster.Pro instance and connect via port-forwarding", + Long: `######################################################## +################## vcluster pro start ################## +######################################################## + +Starts a vCluster.Pro instance in your Kubernetes cluster +and then establishes a port-forwarding connection. + +Please make sure you meet the following requirements +before running this command: + +1. Current kube-context has admin access to the cluster +2. Helm v3 must be installed +3. kubectl must be installed + +######################################################## + `, + Args: cobra.NoArgs, + RunE: func(cobraCmd *cobra.Command, args []string) error { + return start.NewLoftStarter(cmd.Options).Start(cobraCmd.Context()) + }, + } + + startCmd.Flags().StringVar(&cmd.Context, "context", "", "The kube context to use for installation") + startCmd.Flags().StringVar(&cmd.Namespace, "namespace", "vcluster-pro", "The namespace to install vCluster.Pro into") + startCmd.Flags().StringVar(&cmd.LocalPort, "local-port", "", "The local port to bind to if using port-forwarding") + startCmd.Flags().StringVar(&cmd.Host, "host", "", "Provide a hostname to enable ingress and configure its hostname") + startCmd.Flags().StringVar(&cmd.Password, "password", "", "The password to use for the admin account. (If empty this will be the namespace UID)") + startCmd.Flags().StringVar(&cmd.Version, "version", version, "The vCluster.Pro version to install") + startCmd.Flags().StringVar(&cmd.Values, "values", "", "Path to a file for extra vCluster.Pro helm chart values") + startCmd.Flags().BoolVar(&cmd.ReuseValues, "reuse-values", true, "Reuse previous vCluster.Pro helm values on upgrade") + startCmd.Flags().BoolVar(&cmd.Upgrade, "upgrade", false, "If true, vCluster.Pro will try to upgrade the release") + startCmd.Flags().StringVar(&cmd.Email, "email", "", "The email to use for the installation") + startCmd.Flags().BoolVar(&cmd.Reset, "reset", false, "If true, an existing loft instance will be deleted before installing vCluster.Pro") + startCmd.Flags().BoolVar(&cmd.NoWait, "no-wait", false, "If true, vCluster.Pro will not wait after installing it") + startCmd.Flags().BoolVar(&cmd.NoPortForwarding, "no-port-forwarding", false, "If true, vCluster.Pro will not do port forwarding after installing it") + startCmd.Flags().BoolVar(&cmd.NoTunnel, "no-tunnel", false, "If true, vCluster.Pro will not create a loft.host tunnel for this installation") + startCmd.Flags().BoolVar(&cmd.NoLogin, "no-login", false, "If true, vCluster.Pro will not login to a vCluster.Pro instance on start") + startCmd.Flags().StringVar(&cmd.ChartPath, "chart-path", "", "The vCluster.Pro chart path to deploy vCluster.Pro") + startCmd.Flags().StringVar(&cmd.ChartRepo, "chart-repo", "https://charts.loft.sh/", "The chart repo to deploy vCluster.Pro") + startCmd.Flags().StringVar(&cmd.ChartName, "chart-name", "vcluster-control-plane", "The chart name to deploy vCluster.Pro") + + return startCmd, nil +} diff --git a/cmd/vclusterctl/cmd/root.go b/cmd/vclusterctl/cmd/root.go index 97f773948..11ff5a5fa 100644 --- a/cmd/vclusterctl/cmd/root.go +++ b/cmd/vclusterctl/cmd/root.go @@ -89,25 +89,19 @@ func BuildRoot(log log.Logger) (*cobra.Command, error) { if err != nil { return nil, fmt.Errorf("failed to create pro command: %w", err) } - if proCmd != nil { - rootCmd.AddCommand(proCmd) - } + rootCmd.AddCommand(proCmd) loginCmd, err := NewLoginCmd(globalFlags) if err != nil { return nil, fmt.Errorf("failed to create login command: %w", err) } - if loginCmd != nil { - rootCmd.AddCommand(loginCmd) - } + rootCmd.AddCommand(loginCmd) logoutCmd, err := NewLogoutCmd(globalFlags) if err != nil { return nil, fmt.Errorf("failed to create logout command: %w", err) } - if logoutCmd != nil { - rootCmd.AddCommand(logoutCmd) - } + rootCmd.AddCommand(logoutCmd) // add completion command err = rootCmd.RegisterFlagCompletionFunc("namespace", newNamespaceCompletionFunc(rootCmd.Context())) diff --git a/go.mod b/go.mod index c0dcbb63e..ddaacad0f 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru/v2 v2.0.2 github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 - github.com/loft-sh/api/v3 v3.0.0-20230921143328-114580f85fdd - github.com/loft-sh/loftctl/v3 v3.0.0-20230921143437-669b265e3ecf + github.com/loft-sh/api/v3 v3.0.0-20230922094800-6d0c1cbf0fa6 + github.com/loft-sh/loftctl/v3 v3.0.0-20230922094952-2a6aef29f31e github.com/loft-sh/utils v0.0.25 github.com/mitchellh/go-homedir v1.1.0 github.com/moby/term v0.5.0 diff --git a/go.sum b/go.sum index 5ebbf454c..c31876880 100644 --- a/go.sum +++ b/go.sum @@ -552,6 +552,8 @@ github.com/loft-sh/agentapi/v3 v3.3.0-ci.1.0.20230921083523-e1d74f6f8fd1 h1:XE+J github.com/loft-sh/agentapi/v3 v3.3.0-ci.1.0.20230921083523-e1d74f6f8fd1/go.mod h1:8jmVWFBcLjwh6Tv2KPVxkIjUJpVxUMROcbYYVYxR1pI= github.com/loft-sh/api/v3 v3.0.0-20230921143328-114580f85fdd h1:8UQwV6TK1QAHlsdrL8we59IKrPH1z8nSO6+mI2lziXs= github.com/loft-sh/api/v3 v3.0.0-20230921143328-114580f85fdd/go.mod h1:eIbt+Ze6F2fW651JE3VTlFsool+S/hX603aFG5s/AZg= +github.com/loft-sh/api/v3 v3.0.0-20230922094800-6d0c1cbf0fa6 h1:AGmtKdjldgxN4nj6WRSpGe0PKswASDqxnMy1r2ScmVc= +github.com/loft-sh/api/v3 v3.0.0-20230922094800-6d0c1cbf0fa6/go.mod h1:eIbt+Ze6F2fW651JE3VTlFsool+S/hX603aFG5s/AZg= github.com/loft-sh/apiserver v0.0.0-20230628051307-f26967fbb40f h1:eeLBYlrGOvzJK3h7JYdBGpRvdjzD/sTCVPL2lIQsXlg= github.com/loft-sh/apiserver v0.0.0-20230628051307-f26967fbb40f/go.mod h1:Mlbl/QTA48cbKpQcmYMA56TQ+Z6Nna7t7ocbCoCmf5w= github.com/loft-sh/external-types v0.0.2-0.20230301201552-ec939da949b4 h1:eSuBR+6j7MWmab6AU8WGd4EYQiRCZKupxThUxqf38C8= @@ -560,6 +562,8 @@ github.com/loft-sh/jspolicy v0.1.0 h1:FNAWR6tRX5NRWxAf9RI/86NRH83NXYbobLHSZyMND7 github.com/loft-sh/jspolicy v0.1.0/go.mod h1:4Zi38iEB0JvhnkrNHPpoueSUWQ1OlHMNB9JHTGEsPO0= github.com/loft-sh/loftctl/v3 v3.0.0-20230921143437-669b265e3ecf h1:SwIal5P1coM01bw3OYz0PLokpu4iTaYOMlPH1WfWBjk= github.com/loft-sh/loftctl/v3 v3.0.0-20230921143437-669b265e3ecf/go.mod h1:I+dMG4zKZWOn+CcteN0cyPGOclHlqqmXBC6THcUwj60= +github.com/loft-sh/loftctl/v3 v3.0.0-20230922094952-2a6aef29f31e h1:OhQRp9uH7U14lYg8yOrnOiVhhxxC9tFdwWSyxoSUJ/I= +github.com/loft-sh/loftctl/v3 v3.0.0-20230922094952-2a6aef29f31e/go.mod h1:g2HZHmpkqtiQGqM8QVRuaCgNDI6IMW6DZQP0cOUgxp8= github.com/loft-sh/log v0.0.0-20230824104949-bd516c25712a h1:/gqqjKpcHEdFXIX41lx1Y/FBqT/72gbPpf7sa20tyM8= github.com/loft-sh/log v0.0.0-20230824104949-bd516c25712a/go.mod h1:YImeRjXH34Yf5E79T7UHBQpDZl9fIaaFRgyZ/bkY+UQ= github.com/loft-sh/utils v0.0.25 h1:JbbRJfXO1Rd34fQcaoDSmwyPBEzsrLwBSR21C90hHuk= diff --git a/pkg/pro/client.go b/pkg/pro/client.go index 08bc54096..08d98d9fc 100644 --- a/pkg/pro/client.go +++ b/pkg/pro/client.go @@ -22,7 +22,7 @@ type VirtualClusterInstanceProject struct { var ErrConfigNotFound = errors.New("couldn't find vCluster.Pro config") func CreateProClient() (client.Client, error) { - configPath, err := LoftctlConfigFilePath() + configPath, err := ConfigFilePath() if err != nil { return nil, err } diff --git a/pkg/pro/config.go b/pkg/pro/config.go index 8dda0a67a..a6332cb27 100644 --- a/pkg/pro/config.go +++ b/pkg/pro/config.go @@ -1,51 +1,19 @@ package pro import ( - "encoding/json" - "errors" "fmt" - "io" - "os" "path/filepath" - "time" "github.com/loft-sh/vcluster/pkg/util/cliconfig" homedir "github.com/mitchellh/go-homedir" ) const ( - VclusterProFolder = "pro" - LoftctlConfigFileName = "creds.json" + VclusterProFolder = "pro" ) -var ( - // ErrNoLastVersion is returned if no last version was found in the config - ErrNoLastVersion = errors.New("no vcluster pro version found, please run 'vcluster pro login' first") -) - -// CLIConfig is the config of the CLI -type CLIConfig struct { - LatestVersion string `json:"latestVersion,omitempty"` - LatestCheckAt time.Time `json:"latestCheck,omitempty"` -} - -// defaultCLIConfig returns the default config -func defaultCLIConfig() *CLIConfig { - return &CLIConfig{} -} - -// LoftctlConfigFilePath returns the path to the loft config file -func LoftctlConfigFilePath() (string, error) { - home, err := homedir.Dir() - if err != nil { - return "", fmt.Errorf("failed to open vcluster pro configuration file from, unable to detect $HOME directory, falling back to default configuration, following error occurred: %w", err) - } - - return filepath.Join(home, cliconfig.VclusterFolder, VclusterProFolder, LoftctlConfigFileName), nil -} - -// configFilePath returns the path to the config file -func configFilePath() (string, error) { +// ConfigFilePath returns the path to the loft config file +func ConfigFilePath() (string, error) { home, err := homedir.Dir() if err != nil { return "", fmt.Errorf("failed to open vcluster pro configuration file from, unable to detect $HOME directory, falling back to default configuration, following error occurred: %w", err) @@ -53,60 +21,3 @@ func configFilePath() (string, error) { return filepath.Join(home, cliconfig.VclusterFolder, VclusterProFolder, cliconfig.ConfigFileName), nil } - -// GetConfig returns the config from the config file -func GetConfig() (*CLIConfig, error) { - path, err := configFilePath() - if err != nil { - return defaultCLIConfig(), fmt.Errorf("failed to get vcluster pro configuration file path: %w", err) - } - - // check if the file exists - fi, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - return defaultCLIConfig(), nil - } - return defaultCLIConfig(), fmt.Errorf("failed to load vcluster configuration file from %s, falling back to default configuration, following error occurred: %w", path, err) - } - if fi.IsDir() { - return defaultCLIConfig(), fmt.Errorf("failed to load vcluster configuration file %s, falling back to default configuration, this path is a directory", path) - } - file, err := os.Open(path) - if err != nil { - return defaultCLIConfig(), fmt.Errorf("failed to open vcluster configuration file from %s, falling back to default configuration, following error occurred: %w", path, err) - } - defer file.Close() - bytes, _ := io.ReadAll(file) - c := &CLIConfig{} - err = json.Unmarshal(bytes, &c) - if err != nil { - return defaultCLIConfig(), fmt.Errorf("failed to unmarshall vcluster configuration from %s file, falling back to default configuration, following error occurred: %w", path, err) - } - return c, nil -} - -// WriteConfig writes the given config to the config file -func WriteConfig(c *CLIConfig) error { - path, err := configFilePath() - if err != nil { - return fmt.Errorf("failed to get vcluster configuration file path: %w", err) - } - - err = os.MkdirAll(filepath.Dir(path), 0755) - if err != nil { - return fmt.Errorf("failed to create directory for configuration file, following error occurred: %w", err) - } - - data, err := json.Marshal(c) - if err != nil { - return fmt.Errorf("failed to transform config into JSON format, following error occurred: %w", err) - } - - err = os.WriteFile(path, data, 0644) - if err != nil { - return fmt.Errorf("failed to write configuration file, following error occurred: %w", err) - } - - return nil -} diff --git a/pkg/pro/flags.go b/pkg/pro/flags.go new file mode 100644 index 000000000..8175e027c --- /dev/null +++ b/pkg/pro/flags.go @@ -0,0 +1,29 @@ +package pro + +import ( + "fmt" + + loftctlflags "github.com/loft-sh/loftctl/v3/cmd/loftctl/flags" + "github.com/loft-sh/vcluster/cmd/vclusterctl/flags" +) + +// GlobalFlags converts vcluster global flags to vcluster pro global flags +func GlobalFlags(globalFlags *flags.GlobalFlags) (*loftctlflags.GlobalFlags, error) { + loftctlGlobalFlags := &loftctlflags.GlobalFlags{ + Silent: globalFlags.Silent, + Debug: globalFlags.Debug, + LogOutput: globalFlags.LogOutput, + } + + if globalFlags.Config != "" { + loftctlGlobalFlags.Config = globalFlags.Config + } else { + var err error + loftctlGlobalFlags.Config, err = ConfigFilePath() + if err != nil { + return nil, fmt.Errorf("failed to get vcluster pro configuration file path: %w", err) + } + } + + return loftctlGlobalFlags, nil +} diff --git a/pkg/pro/version.go b/pkg/pro/version.go index 70fc01507..c8c8c1cd2 100644 --- a/pkg/pro/version.go +++ b/pkg/pro/version.go @@ -2,11 +2,8 @@ package pro import ( "context" - "errors" "fmt" - "os" "strings" - "time" "github.com/blang/semver/v4" "github.com/google/go-github/v53/github" @@ -20,42 +17,27 @@ var ( // LatestCompatibleVersion returns the latest compatible version of vCluster.Pro func LatestCompatibleVersion(ctx context.Context) (string, error) { - proConfig, err := GetConfig() + client := github.NewClient(nil) + + release, _, err := client.Repositories.GetLatestRelease(ctx, "loft-sh", "loft") if err != nil { - return "", fmt.Errorf("failed to get pro config: %w", err) + return "", fmt.Errorf("failed to get latest release: %w", err) } - if time.Since(proConfig.LatestCheckAt).Hours() > 24 || os.Getenv("PRO_FORCE_UPDATE") == "true" || errors.Is(err, os.ErrNotExist) { - client := github.NewClient(nil) - - release, _, err := client.Repositories.GetLatestRelease(ctx, "loft-sh", "loft") - if err != nil { - return "", fmt.Errorf("failed to get latest release: %w", err) - } - - tagName := release.GetTagName() - - if tagName == "" { - return "", fmt.Errorf("failed to get latest release tag name") - } + tagName := release.GetTagName() - version := MinimumVersionTag - - ghVersion, err := semver.Parse(strings.TrimPrefix(tagName, "v")) - if err != nil { - log.GetInstance().Warnf("failed to parse latest release tag name, falling back to %s: %v", MinimumVersionTag, err) - } else if ghVersion.GTE(MinimumVersion) { - version = tagName - } + if tagName == "" { + return "", fmt.Errorf("failed to get latest release tag name") + } - proConfig.LatestVersion = version - proConfig.LatestCheckAt = time.Now() + version := MinimumVersionTag - err = WriteConfig(proConfig) - if err != nil { - return "", fmt.Errorf("failed to write pro config: %w", err) - } + ghVersion, err := semver.Parse(strings.TrimPrefix(tagName, "v")) + if err != nil { + log.GetInstance().Warnf("failed to parse latest release tag name, falling back to %s: %v", MinimumVersionTag, err) + } else if ghVersion.GTE(MinimumVersion) { + version = tagName } - return proConfig.LatestVersion, nil + return version, nil } diff --git a/vendor/github.com/loft-sh/api/v3/pkg/product/strings.go b/vendor/github.com/loft-sh/api/v3/pkg/product/strings.go index 795e50bad..a89427917 100644 --- a/vendor/github.com/loft-sh/api/v3/pkg/product/strings.go +++ b/vendor/github.com/loft-sh/api/v3/pkg/product/strings.go @@ -24,9 +24,9 @@ func ResetPassword() string { case Loft: return "loft reset password" case DevPodPro: - return "devpod reset password" + return "devpod pro reset password" case VClusterPro: - return "vcluster reset password" + return "vcluster pro reset password" } return resetPassword diff --git a/vendor/github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/reset/password.go b/vendor/github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/reset/password.go index 13ad1ba1b..4d6d0c1ad 100644 --- a/vendor/github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/reset/password.go +++ b/vendor/github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/reset/password.go @@ -31,14 +31,14 @@ type PasswordCmd struct { Create bool Force bool - log log.Logger + Log log.Logger } // NewPasswordCmd creates a new command func NewPasswordCmd(globalFlags *flags.GlobalFlags) *cobra.Command { cmd := &PasswordCmd{ GlobalFlags: globalFlags, - log: log.GetInstance(), + Log: log.GetInstance(), } description := product.ReplaceWithHeader("reset password", ` Resets the password of a user. @@ -91,7 +91,7 @@ func (cmd *PasswordCmd) Run() error { } // get user - cmd.log.Infof("Resetting password of user %s", cmd.User) + cmd.Log.Infof("Resetting password of user %s", cmd.User) user, err := managementClient.Loft().StorageV1().Users().Get(context.Background(), cmd.User, metav1.GetOptions{}) if err != nil && !kerrors.IsNotFound(err) { return errors.Wrap(err, "get user") @@ -144,7 +144,7 @@ func (cmd *PasswordCmd) Run() error { password := cmd.Password if password == "" { for { - password, err = cmd.log.Question(&survey.QuestionOptions{ + password, err = cmd.Log.Question(&survey.QuestionOptions{ Question: "Please enter a new password", IsPassword: true, }) @@ -152,7 +152,7 @@ func (cmd *PasswordCmd) Run() error { if err != nil { return err } else if password == "" { - cmd.log.Error("Please enter a password") + cmd.Log.Error("Please enter a password") continue } @@ -189,6 +189,6 @@ func (cmd *PasswordCmd) Run() error { } } - cmd.log.Donef("Successfully reset password of user %s", cmd.User) + cmd.Log.Donef("Successfully reset password of user %s", cmd.User) return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 96398ea54..d03b8f4d1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -313,7 +313,7 @@ github.com/loft-sh/agentapi/v3/pkg/client/loft/clientset_generated/clientset github.com/loft-sh/agentapi/v3/pkg/client/loft/clientset_generated/clientset/scheme github.com/loft-sh/agentapi/v3/pkg/client/loft/clientset_generated/clientset/typed/cluster/v1 github.com/loft-sh/agentapi/v3/pkg/client/loft/clientset_generated/clientset/typed/storage/v1 -# github.com/loft-sh/api/v3 v3.0.0-20230921143328-114580f85fdd +# github.com/loft-sh/api/v3 v3.0.0-20230922094800-6d0c1cbf0fa6 ## explicit; go 1.21.1 github.com/loft-sh/api/v3/pkg/apis/audit/v1 github.com/loft-sh/api/v3/pkg/apis/management @@ -340,7 +340,7 @@ github.com/loft-sh/external-types/loft-sh/admin-services/pkg/server # github.com/loft-sh/jspolicy v0.1.0 ## explicit; go 1.16 github.com/loft-sh/jspolicy/pkg/apis/policy/v1beta1 -# github.com/loft-sh/loftctl/v3 v3.0.0-20230921143437-669b265e3ecf +# github.com/loft-sh/loftctl/v3 v3.0.0-20230922094952-2a6aef29f31e ## explicit; go 1.21.1 github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd github.com/loft-sh/loftctl/v3/cmd/loftctl/cmd/connect