github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/context.go (about)

     1  package commands
     2  
     3  import (
     4  	stderrors "errors"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"strings"
     9  	"text/tabwriter"
    10  
    11  	log "github.com/sirupsen/logrus"
    12  	"github.com/spf13/cobra"
    13  
    14  	argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
    15  	"github.com/argoproj/argo-cd/v3/util/errors"
    16  	"github.com/argoproj/argo-cd/v3/util/localconfig"
    17  )
    18  
    19  // NewContextCommand returns a new instance of an `argocd ctx` command
    20  func NewContextCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
    21  	var deletion bool
    22  	command := &cobra.Command{
    23  		Use:     "context [CONTEXT]",
    24  		Aliases: []string{"ctx"},
    25  		Short:   "Switch between contexts",
    26  		Example: `# List Argo CD Contexts
    27  argocd context
    28  
    29  # Switch Argo CD context
    30  argocd context cd.argoproj.io
    31  
    32  # Delete Argo CD context
    33  argocd context cd.argoproj.io --delete`,
    34  		Run: func(c *cobra.Command, args []string) {
    35  			localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
    36  			errors.CheckError(err)
    37  
    38  			if deletion {
    39  				if len(args) == 0 {
    40  					c.HelpFunc()(c, args)
    41  					os.Exit(1)
    42  				}
    43  				err := deleteContext(args[0], clientOpts.ConfigPath)
    44  				errors.CheckError(err)
    45  				return
    46  			}
    47  
    48  			if len(args) == 0 {
    49  				printArgoCDContexts(clientOpts.ConfigPath)
    50  				return
    51  			}
    52  
    53  			ctxName := args[0]
    54  
    55  			argoCDDir, err := localconfig.DefaultConfigDir()
    56  			errors.CheckError(err)
    57  			prevCtxFile := path.Join(argoCDDir, ".prev-ctx")
    58  
    59  			if ctxName == "-" {
    60  				prevCtxBytes, err := os.ReadFile(prevCtxFile)
    61  				errors.CheckError(err)
    62  				ctxName = string(prevCtxBytes)
    63  			}
    64  			if localCfg.CurrentContext == ctxName {
    65  				fmt.Printf("Already at context '%s'\n", localCfg.CurrentContext)
    66  				return
    67  			}
    68  			if _, err = localCfg.ResolveContext(ctxName); err != nil {
    69  				log.Fatal(err)
    70  			}
    71  			prevCtx := localCfg.CurrentContext
    72  			localCfg.CurrentContext = ctxName
    73  
    74  			err = localconfig.WriteLocalConfig(*localCfg, clientOpts.ConfigPath)
    75  			errors.CheckError(err)
    76  			err = os.WriteFile(prevCtxFile, []byte(prevCtx), 0o644)
    77  			errors.CheckError(err)
    78  			fmt.Printf("Switched to context '%s'\n", localCfg.CurrentContext)
    79  		},
    80  	}
    81  	command.Flags().BoolVar(&deletion, "delete", false, "Delete the context instead of switching to it")
    82  	return command
    83  }
    84  
    85  func deleteContext(context, configPath string) error {
    86  	localCfg, err := localconfig.ReadLocalConfig(configPath)
    87  	errors.CheckError(err)
    88  	if localCfg == nil {
    89  		return stderrors.New("nothing to logout from")
    90  	}
    91  
    92  	serverName, ok := localCfg.RemoveContext(context)
    93  	if !ok {
    94  		return fmt.Errorf("context %s does not exist", context)
    95  	}
    96  	_ = localCfg.RemoveUser(context)
    97  	_ = localCfg.RemoveServer(serverName)
    98  
    99  	if localCfg.IsEmpty() {
   100  		err = localconfig.DeleteLocalConfig(configPath)
   101  		errors.CheckError(err)
   102  	} else {
   103  		if localCfg.CurrentContext == context {
   104  			localCfg.CurrentContext = ""
   105  		}
   106  		err = localconfig.ValidateLocalConfig(*localCfg)
   107  		if err != nil {
   108  			return stderrors.New("error in logging out")
   109  		}
   110  		err = localconfig.WriteLocalConfig(*localCfg, configPath)
   111  		errors.CheckError(err)
   112  	}
   113  	fmt.Printf("Context '%s' deleted\n", context)
   114  	return nil
   115  }
   116  
   117  func printArgoCDContexts(configPath string) {
   118  	localCfg, err := localconfig.ReadLocalConfig(configPath)
   119  	errors.CheckError(err)
   120  	if localCfg == nil {
   121  		log.Fatalf("No contexts defined in %s", configPath)
   122  	}
   123  	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
   124  	defer func() { _ = w.Flush() }()
   125  	columnNames := []string{"CURRENT", "NAME", "SERVER"}
   126  	_, err = fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t"))
   127  	errors.CheckError(err)
   128  
   129  	for _, contextRef := range localCfg.Contexts {
   130  		context, err := localCfg.ResolveContext(contextRef.Name)
   131  		if err != nil {
   132  			log.Warnf("Context '%s' had error: %v", contextRef.Name, err)
   133  		}
   134  		prefix := " "
   135  		if localCfg.CurrentContext == context.Name {
   136  			prefix = "*"
   137  		}
   138  		_, err = fmt.Fprintf(w, "%s\t%s\t%s\n", prefix, context.Name, context.Server.Server)
   139  		errors.CheckError(err)
   140  	}
   141  }