Skip to content

Commit

Permalink
[UX] moved login from root level to platform subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
facchettos committed Aug 7, 2024
1 parent c523d8b commit 39137d2
Show file tree
Hide file tree
Showing 5 changed files with 391 additions and 277 deletions.
235 changes: 3 additions & 232 deletions cmd/vclusterctl/cmd/login.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
package cmd

import (
"bytes"
"context"
"fmt"
"os"
"strings"

dockerconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
managementv1 "github.com/loft-sh/api/v4/pkg/apis/management/v1"
storagev1 "github.com/loft-sh/api/v4/pkg/apis/storage/v1"
"github.com/loft-sh/api/v4/pkg/product"
"github.com/loft-sh/log"
"github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/use"
"github.com/loft-sh/vcluster/pkg/cli/config"
platformcli "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/platform"
"github.com/loft-sh/vcluster/pkg/cli/flags"
"github.com/loft-sh/vcluster/pkg/docker"
"github.com/loft-sh/vcluster/pkg/platform"
"github.com/loft-sh/vcluster/pkg/platform/clihelper"
"github.com/loft-sh/vcluster/pkg/platform/kube"
"github.com/loft-sh/vcluster/pkg/upgrade"
"github.com/mgutz/ansi"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const PlatformURL = "VCLUSTER_PLATFORM_URL"
Expand All @@ -42,10 +23,7 @@ type LoginCmd struct {
}

func NewLoginCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) {
cmd := LoginCmd{
GlobalFlags: globalFlags,
Log: log.GetInstance(),
}
cmd := platformcli.NewLoginCmd(globalFlags)

description := `########################################################
#################### vcluster login ####################
Expand All @@ -64,6 +42,7 @@ vcluster login https://my-vcluster-platform.com --access-key myaccesskey
Long: description,
Args: cobra.MaximumNArgs(1),
RunE: func(cobraCmd *cobra.Command, args []string) error {
log.GetInstance().Warnf("\"vcluster login\" is deprecated, please use \"vcluster platform login\" instead")
// Check for newer version
upgrade.PrintNewerVersionWarning()

Expand All @@ -78,211 +57,3 @@ vcluster login https://my-vcluster-platform.com --access-key myaccesskey

return loginCmd, nil
}

func (cmd *LoginCmd) Run(ctx context.Context, args []string) error {
cfg := cmd.LoadedConfig(cmd.Log)

var url string
// Print login information
if len(args) == 0 {
url = os.Getenv(PlatformURL)
if url == "" {
insecureFlag := ""
if cfg.Platform.Insecure {
insecureFlag = "--insecure"
}

err := cmd.printLoginDetails(ctx)
if err != nil {
cmd.Log.Fatalf("%s\n\nYou may need to log in again via: %s login %s %s\n", err.Error(), os.Args[0], cfg.Platform.Host, insecureFlag)
}

domain := cfg.Platform.Host
if domain == "" {
domain = "my-vcluster-platform.com"
}

cmd.Log.WriteString(logrus.InfoLevel, fmt.Sprintf("\nTo log in as a different user, run: %s login %s %s\n\n", os.Args[0], domain, insecureFlag))

return nil
}
} else {
url = args[0]
}

if !strings.HasPrefix(url, "http") {
url = "https://" + url
}

// log into platform
loginClient := platform.NewLoginClientFromConfig(cfg)
url = strings.TrimSuffix(url, "/")
var err error
if cmd.AccessKey != "" {
err = loginClient.LoginWithAccessKey(url, cmd.AccessKey, cmd.Insecure)
} else {
err = loginClient.Login(url, cmd.Insecure, cmd.Log)
}
if err != nil {
return err
}
cmd.Log.Donef(product.Replace("Successfully logged into Loft instance %s"), ansi.Color(url, "white+b"))

// skip log into docker registries?
if !cmd.DockerLogin {
return nil
}

err = dockerLogin(ctx, cmd.LoadedConfig(cmd.Log), cmd.Log)
if err != nil {
return err
}

// should switch driver
if cmd.Driver != "" {
err := use.SwitchDriver(ctx, cfg, cmd.Driver, log.GetInstance())
if err != nil {
return fmt.Errorf("driver switch failed: %w", err)
}
}

return nil
}

func (cmd *LoginCmd) printLoginDetails(ctx context.Context) error {
cfg := cmd.LoadedConfig(cmd.Log)
platformClient := platform.NewClientFromConfig(cfg)

managementClient, err := platformClient.Management()
if err != nil {
return err
}

userName, teamName, err := platform.GetCurrentUser(ctx, managementClient)
if err != nil {
return err
}

if userName != nil {
cmd.Log.Infof("Logged into %s as user: %s", platformClient.Config().Platform.Host, clihelper.DisplayName(&userName.EntityInfo))
} else {
cmd.Log.Infof("Logged into %s as team: %s", platformClient.Config().Platform.Host, clihelper.DisplayName(teamName))
}
return nil
}

func dockerLogin(ctx context.Context, config *config.CLI, log log.Logger) error {
platformClient := platform.NewClientFromConfig(config)

managementClient, err := platformClient.Management()
if err != nil {
return err
}

// get user name
userName, teamName, err := platform.GetCurrentUser(ctx, managementClient)
if err != nil {
return err
}

// collect image pull secrets from team or user
dockerConfigs := []*configfile.ConfigFile{}
if userName != nil {
// get image pull secrets from user
user, err := managementClient.Loft().ManagementV1().Users().Get(ctx, userName.Name, metav1.GetOptions{})
if err != nil {
return err
}
dockerConfigs = append(dockerConfigs, collectImagePullSecrets(ctx, managementClient, user.Spec.ImagePullSecrets, log)...)

// get image pull secrets from teams
for _, teamName := range user.Status.Teams {
team, err := managementClient.Loft().ManagementV1().Teams().Get(ctx, teamName, metav1.GetOptions{})
if err != nil {
return err
}

dockerConfigs = append(dockerConfigs, collectImagePullSecrets(ctx, managementClient, team.Spec.ImagePullSecrets, log)...)
}
} else if teamName != nil {
// get image pull secrets from team
team, err := managementClient.Loft().ManagementV1().Teams().Get(ctx, teamName.Name, metav1.GetOptions{})
if err != nil {
return err
}
dockerConfigs = append(dockerConfigs, collectImagePullSecrets(ctx, managementClient, team.Spec.ImagePullSecrets, log)...)
}

// store docker configs
if len(dockerConfigs) > 0 {
dockerConfig, err := docker.NewDockerConfig()
if err != nil {
return err
}

// log into registries locally
for _, config := range dockerConfigs {
for registry, authConfig := range config.AuthConfigs {
err = dockerConfig.Store(registry, authConfig)
if err != nil {
return err
}

if registry == "https://index.docker.io/v1/" {
registry = "docker hub"
}

log.Donef("Successfully logged into docker registry '%s'", registry)
}
}

err = dockerConfig.Save()
if err != nil {
return errors.Wrap(err, "save docker config")
}
}

return nil
}

func collectImagePullSecrets(ctx context.Context, managementClient kube.Interface, imagePullSecrets []*storagev1.KindSecretRef, log log.Logger) []*configfile.ConfigFile {
retConfigFiles := []*configfile.ConfigFile{}
for _, imagePullSecret := range imagePullSecrets {
// unknown image pull secret type?
if imagePullSecret.Kind != "SharedSecret" || (imagePullSecret.APIGroup != storagev1.SchemeGroupVersion.Group && imagePullSecret.APIGroup != managementv1.SchemeGroupVersion.Group) {
continue
} else if imagePullSecret.SecretName == "" || imagePullSecret.SecretNamespace == "" {
continue
}

sharedSecret, err := managementClient.Loft().ManagementV1().SharedSecrets(imagePullSecret.SecretNamespace).Get(ctx, imagePullSecret.SecretName, metav1.GetOptions{})
if err != nil {
log.Warnf("Unable to retrieve image pull secret %s/%s: %v", imagePullSecret.SecretNamespace, imagePullSecret.SecretName, err)
continue
} else if len(sharedSecret.Spec.Data) == 0 {
log.Warnf("Unable to retrieve image pull secret %s/%s: secret is empty", imagePullSecret.SecretNamespace, imagePullSecret.SecretName)
continue
} else if imagePullSecret.Key == "" && len(sharedSecret.Spec.Data) > 1 {
log.Warnf("Unable to retrieve image pull secret %s/%s: secret has multiple keys, but none is specified for image pull secret", imagePullSecret.SecretNamespace, imagePullSecret.SecretName)
continue
}

// determine shared secret key
key := imagePullSecret.Key
if key == "" {
for k := range sharedSecret.Spec.Data {
key = k
}
}

configFile, err := dockerconfig.LoadFromReader(bytes.NewReader(sharedSecret.Spec.Data[key]))
if err != nil {
log.Warnf("Parsing image pull secret %s/%s.%s: %v", imagePullSecret.SecretNamespace, imagePullSecret.SecretName, key, err)
continue
}

retConfigFiles = append(retConfigFiles, configFile)
}

return retConfigFiles
}
48 changes: 3 additions & 45 deletions cmd/vclusterctl/cmd/logout.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
package cmd

import (
"context"
"fmt"

"github.com/loft-sh/api/v4/pkg/product"
"github.com/loft-sh/log"
"github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/use"
"github.com/loft-sh/vcluster/pkg/cli/config"
platformcli "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/platform"
"github.com/loft-sh/vcluster/pkg/cli/flags"
"github.com/loft-sh/vcluster/pkg/platform"
"github.com/mgutz/ansi"
"github.com/spf13/cobra"
)

type LogoutCmd struct {
*flags.GlobalFlags

Log log.Logger
}

func NewLogoutCmd(globalFlags *flags.GlobalFlags) (*cobra.Command, error) {
cmd := &LogoutCmd{
GlobalFlags: globalFlags,
Log: log.GetInstance(),
}

cmd := platformcli.NewLogoutCmd(globalFlags)
description := `########################################################
################### vcluster logout ####################
########################################################
Expand All @@ -42,35 +25,10 @@ vcluster logout
Long: description,
Args: cobra.NoArgs,
RunE: func(cobraCmd *cobra.Command, _ []string) error {
log.GetInstance().Warnf("\"vcluster logout\" is deprecated, please use \"vcluster platform logout\" instead")
return cmd.Run(cobraCmd.Context())
},
}

return logoutCmd, nil
}

func (cmd *LogoutCmd) Run(ctx context.Context) error {
platformClient := platform.NewClientFromConfig(cmd.LoadedConfig(cmd.Log))

// delete old access key if were logged in before
cfg := platformClient.Config()
if cfg.Platform.AccessKey != "" {
if err := platformClient.Logout(ctx); err != nil {
cmd.Log.Errorf("failed to send logout request: %v", err)
}

configHost := cfg.Platform.Host
cfg.Platform.Host = ""
cfg.Platform.AccessKey = ""
cfg.Platform.LastInstallContext = ""
cfg.Platform.Insecure = false

if err := platformClient.Save(); err != nil {
return fmt.Errorf("save config: %w", err)
}

cmd.Log.Donef(product.Replace("Successfully logged out of loft instance %s"), ansi.Color(configHost, "white+b"))
}

return use.SwitchDriver(ctx, cfg, string(config.HelmDriver), cmd.Log)
}
Loading

0 comments on commit 39137d2

Please sign in to comment.