github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/user/logout.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package user
     5  
     6  import (
     7  	"github.com/juju/cmd"
     8  	"github.com/juju/errors"
     9  	"launchpad.net/gnuflag"
    10  
    11  	"github.com/juju/juju/cmd/modelcmd"
    12  	"github.com/juju/juju/jujuclient"
    13  )
    14  
    15  const logoutDoc = `
    16  Log out of the controller.
    17  
    18  This command will remove the user credentials for the current
    19  or specified controller from the client system. This command
    20  will fail if you have not previously logged in with a password;
    21  you can override this behavior by passing --force.
    22  
    23  If another client has logged in as the same user, they will
    24  remain logged in. This command only affects the local client.
    25  
    26  `
    27  
    28  // NewLogoutCommand returns a new cmd.Command to handle "juju logout".
    29  func NewLogoutCommand() cmd.Command {
    30  	return modelcmd.WrapController(&logoutCommand{})
    31  }
    32  
    33  // logoutCommand changes the password for a user.
    34  type logoutCommand struct {
    35  	modelcmd.ControllerCommandBase
    36  	Force bool
    37  }
    38  
    39  // Info implements Command.Info.
    40  func (c *logoutCommand) Info() *cmd.Info {
    41  	return &cmd.Info{
    42  		Name:    "logout",
    43  		Purpose: "logs out of the controller",
    44  		Doc:     logoutDoc,
    45  	}
    46  }
    47  
    48  // Init implements Command.Init.
    49  func (c *logoutCommand) Init(args []string) error {
    50  	return cmd.CheckEmpty(args)
    51  }
    52  
    53  // SetFlags implements Command.SetFlags.
    54  func (c *logoutCommand) SetFlags(f *gnuflag.FlagSet) {
    55  	c.ControllerCommandBase.SetFlags(f)
    56  	f.BoolVar(&c.Force, "force", false, "force logout when a locally recorded password is detected")
    57  }
    58  
    59  // Run implements Command.Run.
    60  func (c *logoutCommand) Run(ctx *cmd.Context) error {
    61  	controllerName := c.ControllerName()
    62  	store := c.ClientStore()
    63  	if err := c.logout(store, controllerName); err != nil {
    64  		return errors.Trace(err)
    65  	}
    66  
    67  	// Count the number of logged-into controllers to inform the user.
    68  	var loggedInCount int
    69  	controllers, err := store.AllControllers()
    70  	if err != nil {
    71  		return errors.Trace(err)
    72  	}
    73  	for name := range controllers {
    74  		if name == controllerName {
    75  			continue
    76  		}
    77  		_, err := store.CurrentAccount(name)
    78  		if errors.IsNotFound(err) {
    79  			continue
    80  		} else if err != nil {
    81  			return errors.Trace(err)
    82  		}
    83  		loggedInCount++
    84  	}
    85  	switch loggedInCount {
    86  	case 0:
    87  		ctx.Infof("Logged out. You are no longer logged into any controllers.")
    88  	case 1:
    89  		ctx.Infof("Logged out. You are still logged into 1 controller.")
    90  	default:
    91  		ctx.Infof("Logged out. You are still logged into %d controllers.", loggedInCount)
    92  	}
    93  	return nil
    94  }
    95  
    96  func (c *logoutCommand) logout(store jujuclient.ClientStore, controllerName string) error {
    97  	accountName, err := store.CurrentAccount(controllerName)
    98  	if errors.IsNotFound(err) {
    99  		// Not logged in; nothing else to do.
   100  		return nil
   101  	} else if err != nil {
   102  		return errors.Trace(err)
   103  	}
   104  
   105  	accountDetails, err := store.AccountByName(controllerName, accountName)
   106  	if errors.IsNotFound(err) {
   107  		// Not logged in; nothing else to do.
   108  		return nil
   109  	} else if err != nil {
   110  		return errors.Trace(err)
   111  	}
   112  
   113  	// We first ensure that the user has a macaroon, which implies
   114  	// they know their password. If they have just bootstrapped,
   115  	// they will have a randomly generated password which they will
   116  	// be unaware of.
   117  	if accountDetails.Macaroon == "" && accountDetails.Password != "" && !c.Force {
   118  		return errors.New(`preventing account loss
   119  
   120  It appears that you have not changed the password for
   121  your account. If this is the case, change the password
   122  first before logging out, so that you can log in again
   123  afterwards. To change your password, run the command
   124  "juju change-user-password".
   125  
   126  If you are sure you want to log out, and it is safe to
   127  clear the credentials from the client, then you can run
   128  this command again with the "--force" flag.
   129  `)
   130  	}
   131  
   132  	// Remove the account credentials.
   133  	if err := store.RemoveAccount(controllerName, accountName); err != nil {
   134  		return errors.Annotate(err, "failed to clear credentials")
   135  	}
   136  	return nil
   137  }