github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/logout.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	svchost "github.com/hashicorp/terraform-svchost"
     9  	"github.com/hashicorp/terraform/internal/command/cliconfig"
    10  	"github.com/hashicorp/terraform/internal/tfdiags"
    11  )
    12  
    13  // LogoutCommand is a Command implementation which removes stored credentials
    14  // for a remote service host.
    15  type LogoutCommand struct {
    16  	Meta
    17  }
    18  
    19  // Run implements cli.Command.
    20  func (c *LogoutCommand) Run(args []string) int {
    21  	args = c.Meta.process(args)
    22  	cmdFlags := c.Meta.defaultFlagSet("logout")
    23  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    24  	if err := cmdFlags.Parse(args); err != nil {
    25  		return 1
    26  	}
    27  
    28  	args = cmdFlags.Args()
    29  	if len(args) > 1 {
    30  		c.Ui.Error(
    31  			"The logout command expects at most one argument: the host to log out of.")
    32  		cmdFlags.Usage()
    33  		return 1
    34  	}
    35  
    36  	var diags tfdiags.Diagnostics
    37  
    38  	givenHostname := "app.terraform.io"
    39  	if len(args) != 0 {
    40  		givenHostname = args[0]
    41  	}
    42  
    43  	hostname, err := svchost.ForComparison(givenHostname)
    44  	if err != nil {
    45  		diags = diags.Append(tfdiags.Sourceless(
    46  			tfdiags.Error,
    47  			"Invalid hostname",
    48  			fmt.Sprintf("The given hostname %q is not valid: %s.", givenHostname, err.Error()),
    49  		))
    50  		c.showDiagnostics(diags)
    51  		return 1
    52  	}
    53  
    54  	// From now on, since we've validated the given hostname, we should use
    55  	// dispHostname in the UI to ensure we're presenting it in the canonical
    56  	// form, in case that helps users with debugging when things aren't
    57  	// working as expected. (Perhaps the normalization is part of the cause.)
    58  	dispHostname := hostname.ForDisplay()
    59  
    60  	creds := c.Services.CredentialsSource().(*cliconfig.CredentialsSource)
    61  	filename, _ := creds.CredentialsFilePath()
    62  	credsCtx := &loginCredentialsContext{
    63  		Location:      creds.HostCredentialsLocation(hostname),
    64  		LocalFilename: filename, // empty in the very unlikely event that we can't select a config directory for this user
    65  		HelperType:    creds.CredentialsHelperType(),
    66  	}
    67  
    68  	if credsCtx.Location == cliconfig.CredentialsInOtherFile {
    69  		diags = diags.Append(tfdiags.Sourceless(
    70  			tfdiags.Error,
    71  			fmt.Sprintf("Credentials for %s are manually configured", dispHostname),
    72  			"The \"terraform logout\" command cannot log out because credentials for this host are manually configured in a CLI configuration file.\n\nTo log out, revoke the existing credentials and remove that block from the CLI configuration.",
    73  		))
    74  	}
    75  
    76  	if diags.HasErrors() {
    77  		c.showDiagnostics(diags)
    78  		return 1
    79  	}
    80  
    81  	switch credsCtx.Location {
    82  	case cliconfig.CredentialsNotAvailable:
    83  		c.Ui.Output(fmt.Sprintf("No credentials for %s are stored.\n", dispHostname))
    84  		return 0
    85  	case cliconfig.CredentialsViaHelper:
    86  		c.Ui.Output(fmt.Sprintf("Removing the stored credentials for %s from the configured\n%q credentials helper.\n", dispHostname, credsCtx.HelperType))
    87  	case cliconfig.CredentialsInPrimaryFile:
    88  		c.Ui.Output(fmt.Sprintf("Removing the stored credentials for %s from the following file:\n    %s\n", dispHostname, credsCtx.LocalFilename))
    89  	}
    90  
    91  	err = creds.ForgetForHost(hostname)
    92  	if err != nil {
    93  		diags = diags.Append(tfdiags.Sourceless(
    94  			tfdiags.Error,
    95  			"Failed to remove API token",
    96  			fmt.Sprintf("Unable to remove stored API token: %s", err),
    97  		))
    98  	}
    99  
   100  	c.showDiagnostics(diags)
   101  	if diags.HasErrors() {
   102  		return 1
   103  	}
   104  
   105  	c.Ui.Output(
   106  		fmt.Sprintf(
   107  			c.Colorize().Color(strings.TrimSpace(`
   108  [green][bold]Success![reset] [bold]Terraform has removed the stored API token for %s.[reset]
   109  `)),
   110  			dispHostname,
   111  		) + "\n",
   112  	)
   113  
   114  	return 0
   115  }
   116  
   117  // Help implements cli.Command.
   118  func (c *LogoutCommand) Help() string {
   119  	defaultFile := c.defaultOutputFile()
   120  	if defaultFile == "" {
   121  		// Because this is just for the help message and it's very unlikely
   122  		// that a user wouldn't have a functioning home directory anyway,
   123  		// we'll just use a placeholder here. The real command has some
   124  		// more complex behavior for this case. This result is not correct
   125  		// on all platforms, but given how unlikely we are to hit this case
   126  		// that seems okay.
   127  		defaultFile = "~/.terraform/credentials.tfrc.json"
   128  	}
   129  
   130  	helpText := `
   131  Usage: terraform [global options] logout [hostname]
   132  
   133    Removes locally-stored credentials for specified hostname.
   134  
   135    Note: the API token is only removed from local storage, not destroyed on the
   136    remote server, so it will remain valid until manually revoked.
   137  
   138    If no hostname is provided, the default hostname is app.terraform.io.
   139        %s
   140  `
   141  	return strings.TrimSpace(helpText)
   142  }
   143  
   144  // Synopsis implements cli.Command.
   145  func (c *LogoutCommand) Synopsis() string {
   146  	return "Remove locally-stored credentials for a remote host"
   147  }
   148  
   149  func (c *LogoutCommand) defaultOutputFile() string {
   150  	if c.CLIConfigDir == "" {
   151  		return "" // no default available
   152  	}
   153  	return filepath.Join(c.CLIConfigDir, "credentials.tfrc.json")
   154  }