diff --git a/cmd/vclusterctl/cmd/connect.go b/cmd/vclusterctl/cmd/connect.go index d1d09fcee0..8ec770e0b6 100644 --- a/cmd/vclusterctl/cmd/connect.go +++ b/cmd/vclusterctl/cmd/connect.go @@ -7,8 +7,8 @@ import ( loftctlUtil "github.com/loft-sh/loftctl/v4/pkg/util" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/loft-sh/vcluster/pkg/upgrade" "github.com/spf13/cobra" ) @@ -92,13 +92,13 @@ func (cmd *ConnectCmd) Run(ctx context.Context, args []string) error { } // get manager - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } // is platform manager? - if manager == platform.ManagerPlatform { + if manager == config.ManagerPlatform { return cli.ConnectPlatform(ctx, &cmd.ConnectOptions, cmd.GlobalFlags, vClusterName, args[1:], cmd.Log) } diff --git a/cmd/vclusterctl/cmd/create.go b/cmd/vclusterctl/cmd/create.go index e349f6bf6c..88797c1fcc 100644 --- a/cmd/vclusterctl/cmd/create.go +++ b/cmd/vclusterctl/cmd/create.go @@ -8,9 +8,9 @@ import ( loftctlUtil "github.com/loft-sh/loftctl/v4/pkg/util" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/constants" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/loft-sh/vcluster/pkg/upgrade" "github.com/spf13/cobra" ) @@ -94,14 +94,14 @@ vcluster create test --namespace test // Run executes the functionality func (cmd *CreateCmd) Run(ctx context.Context, args []string) error { - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } // check if we should create a platform vCluster - platform.PrintManagerInfo("create", manager, cmd.log) - if manager == platform.ManagerPlatform { + config.PrintManagerInfo("create", manager, cmd.log) + if manager == config.ManagerPlatform { return cli.CreatePlatform(ctx, &cmd.CreateOptions, cmd.GlobalFlags, args[0], cmd.log) } diff --git a/cmd/vclusterctl/cmd/delete.go b/cmd/vclusterctl/cmd/delete.go index 4e62024e48..250d1dbdab 100644 --- a/cmd/vclusterctl/cmd/delete.go +++ b/cmd/vclusterctl/cmd/delete.go @@ -4,6 +4,7 @@ import ( loftctlUtil "github.com/loft-sh/loftctl/v4/pkg/util" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" @@ -62,14 +63,18 @@ vcluster delete test --namespace test // Run executes the functionality func (cmd *DeleteCmd) Run(cobraCmd *cobra.Command, args []string) error { - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } - // check if we should delete a platform vCluster - platform.PrintManagerInfo("delete", manager, cmd.log) - if manager == platform.ManagerPlatform { + // check if we should create a platform vCluster + // if there is a platform client we print an info message + _, err = platform.CreatePlatformClient() + if err == nil { + config.PrintManagerInfo("delete", manager, cmd.log) + } + if manager == config.ManagerPlatform { // deploy platform cluster return cli.DeletePlatform(cobraCmd.Context(), &cmd.DeleteOptions, args[0], cmd.log) } diff --git a/cmd/vclusterctl/cmd/info.go b/cmd/vclusterctl/cmd/info.go index 799f108948..191a069c1e 100644 --- a/cmd/vclusterctl/cmd/info.go +++ b/cmd/vclusterctl/cmd/info.go @@ -5,6 +5,7 @@ import ( "runtime" "github.com/loft-sh/log" + "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/platform" "github.com/loft-sh/vcluster/pkg/telemetry" "github.com/spf13/cobra" @@ -20,7 +21,7 @@ type cliInfo struct { } // NewInfoCmd creates a new info command -func NewInfoCmd() *cobra.Command { +func NewInfoCmd(globalFlags *flags.GlobalFlags) *cobra.Command { cobraCmd := &cobra.Command{ Use: "info", Short: "Displays informations about the cli and platform", @@ -41,7 +42,7 @@ vcluster info Version: cobraCmd.Root().Version, OS: runtime.GOOS, Arch: runtime.GOARCH, - MachineID: telemetry.GetMachineID(log.GetInstance()), + MachineID: telemetry.GetMachineID(globalFlags.Config, log.GetInstance()), } platformClient, err := platform.CreatePlatformClient() diff --git a/cmd/vclusterctl/cmd/list.go b/cmd/vclusterctl/cmd/list.go index 8749adc26c..5cfe2fdc0e 100644 --- a/cmd/vclusterctl/cmd/list.go +++ b/cmd/vclusterctl/cmd/list.go @@ -3,8 +3,8 @@ package cmd import ( "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -53,13 +53,13 @@ vcluster list --namespace test // Run executes the functionality func (cmd *ListCmd) Run(cobraCmd *cobra.Command, _ []string) error { - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } // check if we should create a platform vCluster - if manager == platform.ManagerPlatform { + if manager == config.ManagerPlatform { return cli.ListPlatform(cobraCmd.Context(), &cmd.ListOptions, cmd.GlobalFlags, cmd.log) } diff --git a/cmd/vclusterctl/cmd/login.go b/cmd/vclusterctl/cmd/login.go index d640d03b88..a02395331b 100644 --- a/cmd/vclusterctl/cmd/login.go +++ b/cmd/vclusterctl/cmd/login.go @@ -8,7 +8,6 @@ import ( "github.com/loft-sh/log" "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/use" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -21,7 +20,7 @@ type LoginOptions struct { } func NewLoginCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { - loftGlobalFlags, err := platform.GlobalFlags(globalFlags) + loftGlobalFlags, err := flags.LoftctlGlobalFlags(globalFlags) if err != nil { return nil, fmt.Errorf("failed to parse pro flags: %w", err) } @@ -61,7 +60,7 @@ vcluster login https://my-vcluster-platform.com --access-key myaccesskey // should switch manager if options.Manager != "" { - err = use.SwitchManager(options.Manager, log.GetInstance()) + err = use.SwitchManager(globalFlags.Config, options.Manager, log.GetInstance()) if err != nil { return fmt.Errorf("switch manager failed: %w", err) } diff --git a/cmd/vclusterctl/cmd/logout.go b/cmd/vclusterctl/cmd/logout.go index e4a42b9221..06a4ddb79d 100644 --- a/cmd/vclusterctl/cmd/logout.go +++ b/cmd/vclusterctl/cmd/logout.go @@ -6,13 +6,14 @@ import ( loftctl "github.com/loft-sh/loftctl/v4/cmd/loftctl/cmd" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/use" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) func NewLogoutCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { - loftctlGlobalFlags, err := platform.GlobalFlags(globalFlags) + loftctlGlobalFlags, err := flags.LoftctlGlobalFlags(globalFlags) if err != nil { return nil, fmt.Errorf("failed to parse pro flags: %w", err) } @@ -48,7 +49,7 @@ vcluster logout return err } - err = use.SwitchManager(string(platform.ManagerHelm), log.GetInstance()) + err = use.SwitchManager(globalFlags.Config, string(config.ManagerHelm), log.GetInstance()) if err != nil { return err } diff --git a/cmd/vclusterctl/cmd/pause.go b/cmd/vclusterctl/cmd/pause.go index 010db7224e..481b7322a0 100644 --- a/cmd/vclusterctl/cmd/pause.go +++ b/cmd/vclusterctl/cmd/pause.go @@ -7,8 +7,8 @@ import ( loftctlUtil "github.com/loft-sh/loftctl/v4/pkg/util" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -65,13 +65,13 @@ vcluster pause test --namespace test // Run executes the functionality func (cmd *PauseCmd) Run(ctx context.Context, args []string) error { - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } // check if we should create a platform vCluster - if manager == platform.ManagerPlatform { + if manager == config.ManagerPlatform { return cli.PausePlatform(ctx, &cmd.PauseOptions, args[0], cmd.Log) } diff --git a/cmd/vclusterctl/cmd/platform/import.go b/cmd/vclusterctl/cmd/platform/import.go index 1d2a6d4b89..e83c5b4121 100644 --- a/cmd/vclusterctl/cmd/platform/import.go +++ b/cmd/vclusterctl/cmd/platform/import.go @@ -6,8 +6,8 @@ import ( loftctlUtil "github.com/loft-sh/loftctl/v4/pkg/util" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -56,13 +56,13 @@ vcluster platform import my-vcluster --cluster connected-cluster \ // Run executes the functionality func (cmd *ImportCmd) Run(ctx context.Context, args []string) error { - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } // check if we should create a platform vCluster - if manager == platform.ManagerPlatform { + if manager == config.ManagerPlatform { return cli.ActivatePlatform(ctx, &cmd.ActivateOptions, cmd.GlobalFlags, args[0], cmd.Log) } diff --git a/cmd/vclusterctl/cmd/platform/platform.go b/cmd/vclusterctl/cmd/platform/platform.go index fad705bddf..e935476841 100644 --- a/cmd/vclusterctl/cmd/platform/platform.go +++ b/cmd/vclusterctl/cmd/platform/platform.go @@ -5,7 +5,6 @@ import ( "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/platform/connect" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -20,7 +19,7 @@ func NewPlatformCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { Args: cobra.NoArgs, } - loftctlGlobalFlags, err := platform.GlobalFlags(globalFlags) + loftctlGlobalFlags, err := flags.LoftctlGlobalFlags(globalFlags) if err != nil { return nil, fmt.Errorf("failed to parse pro flags: %w", err) } diff --git a/cmd/vclusterctl/cmd/platform/pro.go b/cmd/vclusterctl/cmd/platform/pro.go index c366f6535f..49493f914d 100644 --- a/cmd/vclusterctl/cmd/platform/pro.go +++ b/cmd/vclusterctl/cmd/platform/pro.go @@ -5,7 +5,6 @@ import ( "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/platform/connect" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -22,7 +21,7 @@ Deprecated, please use vcluster platform instead Args: cobra.NoArgs, } - loftctlGlobalFlags, err := platform.GlobalFlags(globalFlags) + loftctlGlobalFlags, err := flags.LoftctlGlobalFlags(globalFlags) if err != nil { return nil, fmt.Errorf("failed to parse pro flags: %w", err) } diff --git a/cmd/vclusterctl/cmd/resume.go b/cmd/vclusterctl/cmd/resume.go index 370d2d1959..4f3995462f 100644 --- a/cmd/vclusterctl/cmd/resume.go +++ b/cmd/vclusterctl/cmd/resume.go @@ -6,8 +6,8 @@ import ( loftctlUtil "github.com/loft-sh/loftctl/v4/pkg/util" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) @@ -60,13 +60,13 @@ vcluster resume test --namespace test // Run executes the functionality func (cmd *ResumeCmd) Run(ctx context.Context, args []string) error { - manager, err := platform.GetManager(cmd.Manager) + manager, err := config.GetManager(cmd.Config, cmd.Manager) if err != nil { return err } // check if we should resume a platform backed virtual cluster - if manager == platform.ManagerPlatform { + if manager == config.ManagerPlatform { return cli.ResumePlatform(ctx, &cmd.ResumeOptions, args[0], cmd.Log) } diff --git a/cmd/vclusterctl/cmd/root.go b/cmd/vclusterctl/cmd/root.go index b04dfecb8c..ac6dfac764 100644 --- a/cmd/vclusterctl/cmd/root.go +++ b/cmd/vclusterctl/cmd/root.go @@ -11,6 +11,7 @@ import ( cmdpro "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/platform" cmdtelemetry "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/telemetry" "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/use" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/platform" "github.com/loft-sh/vcluster/pkg/telemetry" @@ -27,6 +28,14 @@ func NewRootCmd(log log.Logger) *cobra.Command { SilenceErrors: true, Short: "Welcome to vcluster!", PersistentPreRun: func(_ *cobra.Command, _ []string) { + if globalFlags.Config == "" { + var err error + globalFlags.Config, err = config.DefaultConfigFilePath() + if err != nil { + log.Fatalf("failed to get vcluster configuration file path: %w", err) + } + } + if globalFlags.Silent { log.SetLevel(logrus.FatalLevel) } else if globalFlags.Debug { @@ -49,9 +58,6 @@ func Execute() { panic(err) } - // start telemetry - telemetry.StartCLI() - // start command log := log.GetInstance() rootCmd, err := BuildRoot(log) @@ -60,6 +66,9 @@ func Execute() { log.Fatalf("error building root: %+v\n", err) } + // start telemetry + telemetry.StartCLI(globalFlags.Config) + // Execute command err = rootCmd.ExecuteContext(context.Background()) recordAndFlush(err) @@ -76,7 +85,7 @@ func Execute() { func BuildRoot(log log.Logger) (*cobra.Command, error) { rootCmd := NewRootCmd(log) persistentFlags := rootCmd.PersistentFlags() - globalFlags = flags.SetGlobalFlags(persistentFlags) + globalFlags = flags.SetGlobalFlags(persistentFlags, log) // Set version for --version flag rootCmd.Version = upgrade.GetVersion() @@ -93,9 +102,9 @@ func BuildRoot(log log.Logger) (*cobra.Command, error) { rootCmd.AddCommand(get.NewGetCmd(globalFlags)) rootCmd.AddCommand(use.NewUseCmd(globalFlags)) rootCmd.AddCommand(convert.NewConvertCmd(globalFlags)) - rootCmd.AddCommand(cmdtelemetry.NewTelemetryCmd()) + rootCmd.AddCommand(cmdtelemetry.NewTelemetryCmd(globalFlags)) rootCmd.AddCommand(versionCmd) - rootCmd.AddCommand(NewInfoCmd()) + rootCmd.AddCommand(NewInfoCmd(globalFlags)) // add pro commands proCmd, err := cmdpro.NewProCmd(globalFlags) @@ -143,6 +152,6 @@ func BuildRoot(log log.Logger) (*cobra.Command, error) { } func recordAndFlush(err error) { - telemetry.CollectorCLI.RecordCLI(platform.Self, err) + telemetry.CollectorCLI.RecordCLI(globalFlags.Config, platform.Self, err) telemetry.CollectorCLI.Flush() } diff --git a/cmd/vclusterctl/cmd/telemetry/disable.go b/cmd/vclusterctl/cmd/telemetry/disable.go index 8bb79fdf38..1466775856 100644 --- a/cmd/vclusterctl/cmd/telemetry/disable.go +++ b/cmd/vclusterctl/cmd/telemetry/disable.go @@ -2,17 +2,20 @@ package telemetry import ( "github.com/loft-sh/log" - "github.com/loft-sh/vcluster/pkg/util/cliconfig" + "github.com/loft-sh/vcluster/pkg/cli/config" + "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/spf13/cobra" ) type DisableCmd struct { + *flags.GlobalFlags log log.Logger } -func disable() *cobra.Command { +func disable(globalFlags *flags.GlobalFlags) *cobra.Command { cmd := &DisableCmd{ - log: log.GetInstance(), + GlobalFlags: globalFlags, + log: log.GetInstance(), } cobraCmd := &cobra.Command{ @@ -37,7 +40,7 @@ docs: https://www.vcluster.com/docs/advanced-topics/telemetry } func (cmd *DisableCmd) Run(*cobra.Command) error { - c := cliconfig.GetConfig(cmd.log) + c := config.Read(cmd.Config, cmd.log) c.TelemetryDisabled = true - return cliconfig.WriteConfig(c) + return config.Write(cmd.Config, c) } diff --git a/cmd/vclusterctl/cmd/telemetry/enable.go b/cmd/vclusterctl/cmd/telemetry/enable.go index 316760d50a..4d64d5f14f 100644 --- a/cmd/vclusterctl/cmd/telemetry/enable.go +++ b/cmd/vclusterctl/cmd/telemetry/enable.go @@ -2,17 +2,20 @@ package telemetry import ( "github.com/loft-sh/log" - "github.com/loft-sh/vcluster/pkg/util/cliconfig" + "github.com/loft-sh/vcluster/pkg/cli/config" + "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/spf13/cobra" ) type EnableCmd struct { + *flags.GlobalFlags log log.Logger } -func enable() *cobra.Command { +func enable(globalFlags *flags.GlobalFlags) *cobra.Command { cmd := &EnableCmd{ - log: log.GetInstance(), + GlobalFlags: globalFlags, + log: log.GetInstance(), } cobraCmd := &cobra.Command{ @@ -37,7 +40,7 @@ docs: https://www.vcluster.com/docs/advanced-topics/telemetry } func (cmd *EnableCmd) Run(*cobra.Command) error { - c := cliconfig.GetConfig(cmd.log) + c := config.Read(cmd.Config, cmd.log) c.TelemetryDisabled = false - return cliconfig.WriteConfig(c) + return config.Write(cmd.Config, c) } diff --git a/cmd/vclusterctl/cmd/telemetry/telemetry.go b/cmd/vclusterctl/cmd/telemetry/telemetry.go index 98350cefde..ac32320130 100644 --- a/cmd/vclusterctl/cmd/telemetry/telemetry.go +++ b/cmd/vclusterctl/cmd/telemetry/telemetry.go @@ -1,10 +1,11 @@ package telemetry import ( + "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/spf13/cobra" ) -func NewTelemetryCmd() *cobra.Command { +func NewTelemetryCmd(globalFlags *flags.GlobalFlags) *cobra.Command { telemetryCmd := &cobra.Command{ Use: "telemetry", Short: "Sets your vcluster telemetry preferences", @@ -23,7 +24,7 @@ docs: https://www.vcluster.com/docs/advanced-topics/telemetry //TODO: hide global flags on this command and all sub-commands, same for the top-level upgrade command - telemetryCmd.AddCommand(disable()) - telemetryCmd.AddCommand(enable()) + telemetryCmd.AddCommand(disable(globalFlags)) + telemetryCmd.AddCommand(enable(globalFlags)) return telemetryCmd } diff --git a/cmd/vclusterctl/cmd/ui.go b/cmd/vclusterctl/cmd/ui.go index 939daa22dd..797217839e 100644 --- a/cmd/vclusterctl/cmd/ui.go +++ b/cmd/vclusterctl/cmd/ui.go @@ -7,12 +7,11 @@ import ( loftctl "github.com/loft-sh/loftctl/v4/cmd/loftctl/cmd" "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/cli/flags" - "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" ) func NewUICmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) { - loftctlGlobalFlags, err := platform.GlobalFlags(globalFlags) + loftctlGlobalFlags, err := flags.LoftctlGlobalFlags(globalFlags) if err != nil { return nil, fmt.Errorf("failed to parse pro flags: %w", err) } diff --git a/cmd/vclusterctl/cmd/use/manager.go b/cmd/vclusterctl/cmd/use/manager.go index 80bf72ed3a..c0b69d2b13 100644 --- a/cmd/vclusterctl/cmd/use/manager.go +++ b/cmd/vclusterctl/cmd/use/manager.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/loft-sh/log" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/platform" "github.com/spf13/cobra" @@ -35,7 +36,7 @@ Either use helm or vCluster platform as the deployment method for managing virtu Long: description, Args: cobra.ExactArgs(1), RunE: func(cobraCmd *cobra.Command, args []string) error { - if args[0] != string(platform.ManagerHelm) && args[0] != string(platform.ManagerPlatform) { + if args[0] != string(config.ManagerHelm) && args[0] != string(config.ManagerPlatform) { return fmt.Errorf("you can only use helm or platform to use") } @@ -47,24 +48,24 @@ Either use helm or vCluster platform as the deployment method for managing virtu } func (cmd *ManagerCmd) Run(_ context.Context, args []string) error { - return SwitchManager(args[0], cmd.Log) + return SwitchManager(cmd.Config, args[0], cmd.Log) } -func SwitchManager(manager string, log log.Logger) error { - if manager == string(platform.ManagerPlatform) { +func SwitchManager(configPath, manager string, log log.Logger) error { + if manager == string(config.ManagerPlatform) { _, err := platform.CreatePlatformClient() if err != nil { return fmt.Errorf("cannot switch to platform manager, because seems like you are not logged into a vCluster platform (%w)", err) } } - managerFile, err := platform.LoadManagerFile() + managerFile, err := config.LoadManagerFile(configPath) if err != nil { return err } - managerFile.Manager = platform.ManagerType(manager) - err = platform.SaveManagerFile(managerFile) + managerFile.Manager = config.ManagerType(manager) + err = config.SaveManagerFile(configPath, managerFile) if err != nil { return err } diff --git a/pkg/cli/config/config.go b/pkg/cli/config/config.go new file mode 100644 index 0000000000..00ec365179 --- /dev/null +++ b/pkg/cli/config/config.go @@ -0,0 +1,191 @@ +package config + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "sync" + + "github.com/loft-sh/log" + "github.com/loft-sh/vcluster/pkg/platform" + homedir "github.com/mitchellh/go-homedir" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + DirName = ".vcluster" + FileName = "config.json" + ManagerFileName = "manager.json" +) + +var ( + singleConfig *Config + singleConfigOnce sync.Once +) + +// New creates a new default config +func New() *Config { + return &Config{ + TelemetryDisabled: false, + Platform: &PlatformConfig{ + platform.Config{ + TypeMeta: metav1.TypeMeta{ + Kind: "Config", + APIVersion: "storage.loft.sh/v1", + }, + VirtualClusterAccessPointCertificates: make(map[string]platform.VirtualClusterCertificatesEntry), + }, + }, + } +} + +// Read returns the current config by trying to read it from the given config path. +// It returns a new default config if there have been any errors during the read. +func Read(path string, log log.Logger) *Config { + singleConfigOnce.Do(func() { + if singleConfig == nil { + cfg, err := readOrNew(path) + if err != nil { + log.Debugf("Failed to load local configuration file: %v", err) + } + singleConfig = cfg + } + }) + + return singleConfig +} + +func Write(path string, c *Config) error { + 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 +} + +func GetManager(path, manager string) (ManagerType, error) { + if manager != "" { + if manager != string(ManagerPlatform) && manager != string(ManagerHelm) { + return "", fmt.Errorf("unknown manager: %s, please choose either helm or platform", manager) + } + + return ManagerType(manager), nil + } + + managerFile, err := LoadManagerFile(path) + if err != nil { + return "", err + } else if managerFile.Manager == "" { + return ManagerHelm, nil + } + + return managerFile.Manager, nil +} + +func LoadManagerFile(path string) (*ManagerConfig, error) { + _, err := os.Stat(path) + if err != nil { + // couldn't find manager file, so just return an empty manager config + return &ManagerConfig{}, nil + } + + rawBytes, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error reading vCluster platform manager file: %w", err) + } + + managerConfig := &ManagerConfig{} + err = json.Unmarshal(rawBytes, managerConfig) + if err != nil { + return nil, fmt.Errorf("error parsing vCluster platform manager file: %w", err) + } + + return managerConfig, nil +} + +func SaveManagerFile(path string, managerConfig *ManagerConfig) error { + rawBytes, err := json.Marshal(managerConfig) + if err != nil { + return fmt.Errorf("marshal manager config: %w", err) + } + + err = os.MkdirAll(filepath.Dir(path), 0755) + if err != nil { + return fmt.Errorf("create manager dir: %w", err) + } + + err = os.WriteFile(path, rawBytes, 0644) + if err != nil { + return fmt.Errorf("error saving manager config: %w", err) + } + + return nil +} + +func PrintManagerInfo(verb string, manager ManagerType, log log.Logger) { + // only print this to stderr + log = log.ErrorStreamOnly() + + if manager == ManagerHelm { + log.Infof("Using vCluster manager 'helm' to %s your virtual clusters, which means the vCluster CLI is running helm commands directly", verb) + log.Info("If you prefer to use the vCluster platform API instead, use the flag '--manager platform' or run 'vcluster use manager platform' to change the default") + } else { + log.Infof("Using vCluster manager 'platform' to %s your virtual clusters, which means the CLI is using the vCluster platform API instead of helm", verb) + log.Info("If you prefer to use helm instead, use the flag '--manager helm' or run 'vcluster use manager helm' to change the default") + } +} + +func DefaultConfigFilePath() (string, error) { + home, err := homedir.Dir() + if err != nil { + return "", err + } + return filepath.Join(home, DirName, FileName), nil +} + +func readOrNew(path string) (*Config, error) { + // check if the file exists + fi, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return New(), fmt.Errorf("failed to load vcluster configuration file from %s, falling back to default configuration, following error occurred: %w", path, err) + } + return New(), 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 New(), 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 New(), 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, err := io.ReadAll(file) + if err != nil { + return New(), err + } + + c := &Config{} + err = json.Unmarshal(bytes, &c) + if err != nil { + return New(), fmt.Errorf("failed to unmarshall vcluster configuration from %s file, falling back to default configuration, following error occurred: %w", path, err) + } + + return c, nil +} diff --git a/pkg/cli/config/types.go b/pkg/cli/config/types.go new file mode 100644 index 0000000000..f500861e88 --- /dev/null +++ b/pkg/cli/config/types.go @@ -0,0 +1,27 @@ +package config + +import ( + "github.com/loft-sh/vcluster/pkg/platform" +) + +const ( + ManagerHelm ManagerType = "helm" + ManagerPlatform ManagerType = "platform" +) + +type Config struct { + TelemetryDisabled bool `json:"telemetryDisabled,omitempty"` + Platform *PlatformConfig `json:"platform,omitempty"` +} + +// PlatformConfig defines the platform client config structure +type PlatformConfig struct { + platform.Config +} + +type ManagerType string + +type ManagerConfig struct { + // Manager is the current manager that is used, either helm or platform + Manager ManagerType `json:"manager,omitempty"` +} diff --git a/pkg/cli/create_helm.go b/pkg/cli/create_helm.go index a6bd3ca671..4184e416cb 100644 --- a/pkg/cli/create_helm.go +++ b/pkg/cli/create_helm.go @@ -18,6 +18,7 @@ import ( "github.com/loft-sh/log/terminal" "github.com/loft-sh/vcluster/config" "github.com/loft-sh/vcluster/config/legacyconfig" + cliconfig "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/find" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/cli/localkubernetes" @@ -28,7 +29,6 @@ import ( "github.com/loft-sh/vcluster/pkg/telemetry" "github.com/loft-sh/vcluster/pkg/upgrade" "github.com/loft-sh/vcluster/pkg/util" - "github.com/loft-sh/vcluster/pkg/util/cliconfig" "github.com/loft-sh/vcluster/pkg/util/clihelper" "github.com/loft-sh/vcluster/pkg/util/helmdownloader" "golang.org/x/mod/semver" @@ -492,9 +492,9 @@ func (cmd *createHelm) ToChartOptions(kubernetesVersion *version.Info, log log.L Major: kubernetesVersion.Major, Minor: kubernetesVersion.Minor, }, - DisableTelemetry: cliconfig.GetConfig(log).TelemetryDisabled, + DisableTelemetry: cliconfig.Read(cmd.Config, log).TelemetryDisabled, InstanceCreatorType: "vclusterctl", - MachineID: telemetry.GetMachineID(log), + MachineID: telemetry.GetMachineID(cmd.Config, log), }, nil } diff --git a/pkg/cli/create_platform.go b/pkg/cli/create_platform.go index 5b484083ac..2caf237a97 100644 --- a/pkg/cli/create_platform.go +++ b/pkg/cli/create_platform.go @@ -20,6 +20,7 @@ import ( "github.com/loft-sh/loftctl/v4/pkg/vcluster" "github.com/loft-sh/log" vclusterconfig "github.com/loft-sh/vcluster/config" + cliconfig "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/cli/flags" "github.com/loft-sh/vcluster/pkg/constants" "github.com/loft-sh/vcluster/pkg/platform" @@ -27,7 +28,6 @@ import ( "github.com/loft-sh/vcluster/pkg/telemetry" "github.com/loft-sh/vcluster/pkg/upgrade" "github.com/loft-sh/vcluster/pkg/util" - "github.com/loft-sh/vcluster/pkg/util/cliconfig" "golang.org/x/mod/semver" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -112,13 +112,13 @@ func CreatePlatform(ctx context.Context, options *CreateOptions, globalFlags *fl } else { if virtualClusterInstance == nil { // create without template - virtualClusterInstance, err = createWithoutTemplate(ctx, platformClient, options, virtualClusterName, globalFlags.Namespace, log) + virtualClusterInstance, err = createWithoutTemplate(ctx, globalFlags.Config, platformClient, options, virtualClusterName, globalFlags.Namespace, log) if err != nil { return err } } else { // upgrade via template - virtualClusterInstance, err = upgradeWithoutTemplate(ctx, platformClient, options, virtualClusterInstance, log) + virtualClusterInstance, err = upgradeWithoutTemplate(ctx, globalFlags.Config, platformClient, options, virtualClusterInstance, log) if err != nil { return err } @@ -146,14 +146,14 @@ func CreatePlatform(ctx context.Context, options *CreateOptions, globalFlags *fl return nil } -func createWithoutTemplate(ctx context.Context, platformClient platform.Client, options *CreateOptions, virtualClusterName, targetNamespace string, log log.Logger) (*managementv1.VirtualClusterInstance, error) { +func createWithoutTemplate(ctx context.Context, configPath string, platformClient platform.Client, options *CreateOptions, virtualClusterName, targetNamespace string, log log.Logger) (*managementv1.VirtualClusterInstance, error) { err := validateNoTemplateOptions(options) if err != nil { return nil, err } // merge values - helmValues, err := mergeValues(platformClient, options, log) + helmValues, err := mergeValues(configPath, platformClient, options, log) if err != nil { return nil, err } @@ -227,14 +227,14 @@ func createWithoutTemplate(ctx context.Context, platformClient platform.Client, return virtualClusterInstance, nil } -func upgradeWithoutTemplate(ctx context.Context, platformClient platform.Client, options *CreateOptions, virtualClusterInstance *managementv1.VirtualClusterInstance, log log.Logger) (*managementv1.VirtualClusterInstance, error) { +func upgradeWithoutTemplate(ctx context.Context, configPath string, platformClient platform.Client, options *CreateOptions, virtualClusterInstance *managementv1.VirtualClusterInstance, log log.Logger) (*managementv1.VirtualClusterInstance, error) { err := validateNoTemplateOptions(options) if err != nil { return nil, err } // merge values - helmValues, err := mergeValues(platformClient, options, log) + helmValues, err := mergeValues(configPath, platformClient, options, log) if err != nil { return nil, err } @@ -526,9 +526,9 @@ func validateTemplateOptions(options *CreateOptions) error { return nil } -func mergeValues(platformClient platform.Client, options *CreateOptions, log log.Logger) (string, error) { +func mergeValues(configPath string, platformClient platform.Client, options *CreateOptions, log log.Logger) (string, error) { // merge values - chartOptions, err := toChartOptions(platformClient, options, log) + chartOptions, err := toChartOptions(configPath, platformClient, options, log) if err != nil { return "", err } @@ -589,7 +589,7 @@ func parseString(str string) (map[string]interface{}, error) { return out, nil } -func toChartOptions(platformClient platform.Client, options *CreateOptions, log log.Logger) (*vclusterconfig.ExtraValuesOptions, error) { +func toChartOptions(configPath string, platformClient platform.Client, options *CreateOptions, log log.Logger) (*vclusterconfig.ExtraValuesOptions, error) { if !util.Contains(options.Distro, AllowedDistros) { return nil, fmt.Errorf("unsupported distro %s, please select one of: %s", options.Distro, strings.Join(AllowedDistros, ", ")) } @@ -627,10 +627,10 @@ func toChartOptions(platformClient platform.Client, options *CreateOptions, log Distro: options.Distro, Expose: options.Expose, KubernetesVersion: kubernetesVersion, - DisableTelemetry: cliconfig.GetConfig(log).TelemetryDisabled, + DisableTelemetry: cliconfig.Read(configPath, log).TelemetryDisabled, InstanceCreatorType: "vclusterctl", - PlatformInstanceID: telemetry.GetPlatformInstanceID(platformClient.Self()), - PlatformUserID: telemetry.GetPlatformUserID(platformClient.Self()), - MachineID: telemetry.GetMachineID(log), + PlatformInstanceID: telemetry.GetPlatformInstanceID(configPath, platformClient.Self()), + PlatformUserID: telemetry.GetPlatformUserID(configPath, platformClient.Self()), + MachineID: telemetry.GetMachineID(configPath, log), }, nil } diff --git a/pkg/cli/flags/flags.go b/pkg/cli/flags/flags.go index 0c218f8d66..8adde6ff39 100644 --- a/pkg/cli/flags/flags.go +++ b/pkg/cli/flags/flags.go @@ -1,6 +1,12 @@ package flags import ( + "fmt" + + loftctlflags "github.com/loft-sh/loftctl/v4/cmd/loftctl/flags" + "github.com/loft-sh/log" + "github.com/loft-sh/vcluster/pkg/cli/config" + flag "github.com/spf13/pflag" ) @@ -15,10 +21,16 @@ type GlobalFlags struct { } // SetGlobalFlags applies the global flags -func SetGlobalFlags(flags *flag.FlagSet) *GlobalFlags { +func SetGlobalFlags(flags *flag.FlagSet, log log.Logger) *GlobalFlags { globalFlags := &GlobalFlags{} + defaultConfigPath, err := config.DefaultConfigFilePath() + if err != nil { + log.Fatalf("failed to get vcluster configuration file path: %w", err) + } + flags.BoolVar(&globalFlags.Debug, "debug", false, "Prints the stack trace if an error occurs") + flags.StringVar(&globalFlags.Config, "config", defaultConfigPath, "The vcluster CLI config to use (will be created if it does not exist)") flags.StringVar(&globalFlags.Context, "context", "", "The kubernetes config context to use") flags.StringVarP(&globalFlags.Namespace, "namespace", "n", "", "The kubernetes namespace to use") flags.BoolVarP(&globalFlags.Silent, "silent", "s", false, "Run in silent mode and prevents any vcluster log output except panics & fatals") @@ -26,3 +38,24 @@ func SetGlobalFlags(flags *flag.FlagSet) *GlobalFlags { return globalFlags } + +// LoftctlGlobalFlags converts vcluster global flags to vcluster pro global flags +func LoftctlGlobalFlags(globalFlags *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 = config.DefaultConfigFilePath() + if err != nil { + return nil, fmt.Errorf("failed to get vcluster pro configuration file path: %w", err) + } + } + + return loftctlGlobalFlags, nil +} diff --git a/pkg/platform/config.go b/pkg/platform/config.go index 27a665fb0d..3e59b1a480 100644 --- a/pkg/platform/config.go +++ b/pkg/platform/config.go @@ -6,7 +6,6 @@ import ( "os" "path/filepath" - "github.com/loft-sh/log" "github.com/loft-sh/vcluster/pkg/constants" homedir "github.com/mitchellh/go-homedir" ) @@ -22,7 +21,7 @@ func ConfigFilePath() (string, error) { return "", fmt.Errorf("failed to open vCluster platform configuration file, unable to detect $HOME directory, falling back to default configuration, following error occurred: %w", err) } - return filepath.Join(home, constants.VClusterFolder, VClusterProFolder, constants.ConfigFileName), nil + return filepath.Join(home, constants.VClusterFolder, constants.ConfigFileName), nil } func managerFilePath() (string, error) { @@ -31,24 +30,7 @@ func managerFilePath() (string, error) { return "", fmt.Errorf("failed to open vCluster platform manager file, unable to detect $HOME directory, falling back to default configuration, following error occurred: %w", err) } - return filepath.Join(home, constants.VClusterFolder, VClusterProFolder, constants.ManagerFileName), nil -} - -func PrintManagerInfo(verb string, manager ManagerType, log log.Logger) { - // only print this to stderr - log = log.ErrorStreamOnly() - - // check if there is a platform client or we skip the info message - _, err := CreatePlatformClient() - if err == nil { - if manager == ManagerHelm { - log.Infof("Using vCluster manager 'helm' to %s your virtual clusters, which means the vCluster CLI is running helm commands directly", verb) - log.Info("If you prefer to use the vCluster platform API instead, use the flag '--manager platform' or run 'vcluster use manager platform' to change the default") - } else { - log.Infof("Using vCluster manager 'platform' to %s your virtual clusters, which means the CLI is using the vCluster platform API instead of helm", verb) - log.Info("If you prefer to use helm instead, use the flag '--manager helm' or run 'vcluster use manager helm' to change the default") - } - } + return filepath.Join(home, constants.VClusterFolder, constants.ManagerFileName), nil } func GetManager(manager string) (ManagerType, error) { diff --git a/pkg/platform/flags.go b/pkg/platform/flags.go deleted file mode 100644 index 1fd5b990f2..0000000000 --- a/pkg/platform/flags.go +++ /dev/null @@ -1,29 +0,0 @@ -package platform - -import ( - "fmt" - - loftctlflags "github.com/loft-sh/loftctl/v4/cmd/loftctl/flags" - "github.com/loft-sh/vcluster/pkg/cli/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/platform/types.go b/pkg/platform/types.go index 1996cf768c..d7865b6628 100644 --- a/pkg/platform/types.go +++ b/pkg/platform/types.go @@ -1,12 +1,74 @@ package platform -type ManagerType string +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) const ( ManagerHelm ManagerType = "helm" ManagerPlatform ManagerType = "platform" ) +// Config defines the client config structure +type Config struct { + metav1.TypeMeta `json:",inline"` + + // host is the http endpoint of how to access loft + // +optional + Host string `json:"host,omitempty"` + + // LastInstallContext is the last install context + // +optional + LastInstallContext string `json:"lastInstallContext,omitempty"` + + // insecure specifies if the loft instance is insecure + // +optional + Insecure bool `json:"insecure,omitempty"` + + // access key is the access key for the given loft host + // +optional + AccessKey string `json:"accesskey,omitempty"` + + // virtual cluster access key is the access key for the given loft host to create virtual clusters + // +optional + VirtualClusterAccessKey string `json:"virtualClusterAccessKey,omitempty"` + + // DEPRECATED: do not use anymore + // the direct cluster endpoint token + // +optional + DirectClusterEndpointToken string `json:"directClusterEndpointToken,omitempty"` + + // DEPRECATED: do not use anymore + // last time the direct cluster endpoint token was requested + // +optional + DirectClusterEndpointTokenRequested *metav1.Time `json:"directClusterEndpointTokenRequested,omitempty"` + + // map of cached certificates for "access point" mode virtual clusters + // +optional + VirtualClusterAccessPointCertificates map[string]VirtualClusterCertificatesEntry +} + +type VirtualClusterCertificatesEntry struct { + CertificateData string + KeyData string + LastRequested metav1.Time + ExpirationTime time.Time +} + +// NewConfig creates a new config +func NewConfig() *Config { + return &Config{ + TypeMeta: metav1.TypeMeta{ + Kind: "Config", + APIVersion: "storage.loft.sh/v1", + }, + } +} + +type ManagerType string + type ManagerConfig struct { // Manager is the current manager that is used, either helm or platform Manager ManagerType `json:"manager,omitempty"` diff --git a/pkg/telemetry/collect_cli.go b/pkg/telemetry/collect_cli.go index 42840d4f90..4ce208446b 100644 --- a/pkg/telemetry/collect_cli.go +++ b/pkg/telemetry/collect_cli.go @@ -9,8 +9,8 @@ import ( "github.com/loft-sh/analytics-client/client" managementv1 "github.com/loft-sh/api/v4/pkg/apis/management/v1" "github.com/loft-sh/log" + "github.com/loft-sh/vcluster/pkg/cli/config" "github.com/loft-sh/vcluster/pkg/upgrade" - "github.com/loft-sh/vcluster/pkg/util/cliconfig" "github.com/loft-sh/vcluster/pkg/util/loghelper" ) @@ -26,15 +26,15 @@ const ( var CollectorCLI CLICollector = &noopCollector{} type CLICollector interface { - RecordCLI(self *managementv1.Self, err error) + RecordCLI(configPath string, self *managementv1.Self, err error) // Flush makes sure all events are sent to the backend Flush() } // StartCLI starts collecting events and sending them to the backend from the CLI -func StartCLI() { - cliConfig := cliconfig.GetConfig(log.Discard) +func StartCLI(configPath string) { + cliConfig := config.Read(configPath, log.Discard) // if disabled, we return noop collector if cliConfig.TelemetryDisabled || upgrade.GetVersion() == upgrade.DevelopmentVersion { @@ -70,7 +70,7 @@ func (d *cliCollector) Flush() { d.analyticsClient.Flush() } -func (d *cliCollector) RecordCLI(self *managementv1.Self, err error) { +func (d *cliCollector) RecordCLI(configPath string, self *managementv1.Self, err error) { timezone, _ := time.Now().Zone() eventProperties := map[string]interface{}{ "command": os.Args, @@ -91,16 +91,16 @@ func (d *cliCollector) RecordCLI(self *managementv1.Self, err error) { d.analyticsClient.RecordEvent(client.Event{ "event": { "type": "vcluster_cli", - "platform_user_id": GetPlatformUserID(self), - "platform_instance_id": GetPlatformInstanceID(self), - "machine_id": GetMachineID(log.Discard), + "platform_user_id": GetPlatformUserID(configPath, self), + "platform_instance_id": GetPlatformInstanceID(configPath, self), + "machine_id": GetMachineID(configPath, log.Discard), "properties": string(eventPropertiesRaw), "timestamp": time.Now().Unix(), }, "user": { - "platform_user_id": GetPlatformUserID(self), - "platform_instance_id": GetPlatformInstanceID(self), - "machine_id": GetMachineID(log.Discard), + "platform_user_id": GetPlatformUserID(configPath, self), + "platform_instance_id": GetPlatformInstanceID(configPath, self), + "machine_id": GetMachineID(configPath, log.Discard), "properties": string(userPropertiesRaw), "timestamp": time.Now().Unix(), }, diff --git a/pkg/telemetry/helpers.go b/pkg/telemetry/helpers.go index d082648556..fa67e021ab 100644 --- a/pkg/telemetry/helpers.go +++ b/pkg/telemetry/helpers.go @@ -9,7 +9,7 @@ import ( "github.com/denisbrodbeck/machineid" managementv1 "github.com/loft-sh/api/v4/pkg/apis/management/v1" "github.com/loft-sh/log" - "github.com/loft-sh/vcluster/pkg/util/cliconfig" + "github.com/loft-sh/vcluster/pkg/cli/config" homedir "github.com/mitchellh/go-homedir" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/version" @@ -75,8 +75,8 @@ func toKubernetesVersion(vi *version.Info) *KubernetesVersion { } // GetPlatformUserID returns the loft instance id -func GetPlatformUserID(self *managementv1.Self) string { - if cliconfig.GetConfig(log.Discard).TelemetryDisabled || self == nil { +func GetPlatformUserID(configPath string, self *managementv1.Self) string { + if config.Read(configPath, log.Discard).TelemetryDisabled || self == nil { return "" } platformID := self.Status.Subject @@ -87,8 +87,8 @@ func GetPlatformUserID(self *managementv1.Self) string { } // GetPlatformInstanceID returns the loft instance id -func GetPlatformInstanceID(self *managementv1.Self) string { - if cliconfig.GetConfig(log.Discard).TelemetryDisabled || self == nil { +func GetPlatformInstanceID(configPath string, self *managementv1.Self) string { + if config.Read(configPath, log.Discard).TelemetryDisabled || self == nil { return "" } @@ -97,8 +97,8 @@ func GetPlatformInstanceID(self *managementv1.Self) string { // GetMachineID retrieves machine ID and encodes it together with users $HOME path and // extra key to protect privacy. Returns a hex-encoded string. -func GetMachineID(log log.Logger) string { - if cliconfig.GetConfig(log).TelemetryDisabled { +func GetMachineID(configPath string, log log.Logger) string { + if config.Read(configPath, log).TelemetryDisabled { return "" } diff --git a/pkg/telemetry/noop.go b/pkg/telemetry/noop.go index 207108345e..d99335e70a 100644 --- a/pkg/telemetry/noop.go +++ b/pkg/telemetry/noop.go @@ -19,4 +19,4 @@ func (n *noopCollector) Flush() {} func (n *noopCollector) SetVirtualClient(_ kubernetes.Interface) {} -func (n *noopCollector) RecordCLI(_ *managementv1.Self, _ error) {} +func (n *noopCollector) RecordCLI(_ string, _ *managementv1.Self, _ error) {} diff --git a/pkg/util/cliconfig/config.go b/pkg/util/cliconfig/config.go deleted file mode 100644 index 9e83c6fbd2..0000000000 --- a/pkg/util/cliconfig/config.go +++ /dev/null @@ -1,107 +0,0 @@ -package cliconfig - -import ( - "encoding/json" - "fmt" - "io" - "os" - "path/filepath" - "sync" - - "github.com/loft-sh/log" - "github.com/loft-sh/vcluster/pkg/constants" - homedir "github.com/mitchellh/go-homedir" -) - -var ( - singleConfig *CLIConfig - singleConfigOnce sync.Once -) - -type CLIConfig struct { - TelemetryDisabled bool `json:"telemetryDisabled,omitempty"` -} - -func getDefaultCLIConfig() *CLIConfig { - return &CLIConfig{ - TelemetryDisabled: false, - } -} - -func getConfigFilePath(home string) string { - return filepath.Join(home, constants.VClusterFolder, constants.ConfigFileName) -} - -func GetConfig(log log.Logger) *CLIConfig { - singleConfigOnce.Do(func() { - var err error - singleConfig, err = getConfig() - if err != nil && log != nil { - log.Debugf("Failed to load local configuration file: %v", err.Error()) - } - - // set default if nil - if singleConfig == nil { - singleConfig = getDefaultCLIConfig() - } - }) - - return singleConfig -} - -func getConfig() (*CLIConfig, error) { - home, err := homedir.Dir() - if err != nil { - return getDefaultCLIConfig(), fmt.Errorf("failed to open vcluster configuration file from, unable to detect $HOME directory, falling back to default configuration, following error occurred: %w", err) - } - - path := getConfigFilePath(home) - // check if the file exists - fi, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - return getDefaultCLIConfig(), nil - } - return getDefaultCLIConfig(), 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 getDefaultCLIConfig(), 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 getDefaultCLIConfig(), 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 getDefaultCLIConfig(), fmt.Errorf("failed to unmarshall vcluster configuration from %s file, falling back to default configuration, following error occurred: %w", path, err) - } - return c, nil -} - -func WriteConfig(c *CLIConfig) error { - home, err := homedir.Dir() - if err != nil { - return fmt.Errorf("failed to write vcluster configuration file from, unable to detect $HOME directory, falling back to default configuration, following error occurred: %w", err) - } - path := getConfigFilePath(home) - - 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 -}