github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/user/remove.go (about) 1 // Copyright 2012-2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 package user 4 5 import ( 6 "bufio" 7 "fmt" 8 "io" 9 "strings" 10 11 "github.com/juju/cmd" 12 "github.com/juju/errors" 13 "github.com/juju/gnuflag" 14 15 "github.com/juju/juju/apiserver/params" 16 jujucmd "github.com/juju/juju/cmd" 17 "github.com/juju/juju/cmd/juju/block" 18 "github.com/juju/juju/cmd/modelcmd" 19 ) 20 21 var removeUsageSummary = ` 22 Deletes a Juju user from a controller.`[1:] 23 24 // TODO(redir): Get updated copy for add-user as that may need updates, too. 25 var removeUsageDetails = ` 26 This removes a user permanently. 27 28 By default, the controller is the current controller. 29 30 Examples: 31 juju remove-user bob 32 juju remove-user bob --yes 33 34 See also: 35 unregister 36 revoke 37 show-user 38 list-users 39 switch-user 40 disable-user 41 enable-user 42 change-user-password`[1:] 43 44 var removeUserMsg = ` 45 WARNING! This command will permanently archive the user %q on the %q 46 controller. 47 48 This action is irreversible. If you wish to temporarily disable the 49 user please use the`[1:] + " `juju disable-user` " + `command. See 50 ` + " `juju help disable-user` " + `for more details. 51 52 Continue (y/N)? ` 53 54 // RemoveUserAPI defines the usermanager API methods that the remove command 55 // uses. 56 type RemoveUserAPI interface { 57 RemoveUser(username string) error 58 Close() error 59 } 60 61 // NewRemoveCommand constructs a wrapped unexported removeCommand. 62 func NewRemoveCommand() cmd.Command { 63 return modelcmd.WrapController(&removeCommand{}) 64 } 65 66 // removeCommand deletes a user from a Juju controller. 67 type removeCommand struct { 68 modelcmd.ControllerCommandBase 69 api RemoveUserAPI 70 UserName string 71 ConfirmDelete bool 72 } 73 74 // SetFlags adds command specific flags and then returns the flagset. 75 func (c *removeCommand) SetFlags(f *gnuflag.FlagSet) { 76 c.ControllerCommandBase.SetFlags(f) 77 f.BoolVar(&c.ConfirmDelete, "y", false, "Confirm deletion of the user") 78 f.BoolVar(&c.ConfirmDelete, "yes", false, "") 79 } 80 81 // Info implements Command.Info. 82 func (c *removeCommand) Info() *cmd.Info { 83 return jujucmd.Info(&cmd.Info{ 84 Name: "remove-user", 85 Args: "<user name>", 86 Purpose: removeUsageSummary, 87 Doc: removeUsageDetails, 88 }) 89 } 90 91 // Init implements Command.Init. 92 func (c *removeCommand) Init(args []string) error { 93 if len(args) == 0 { 94 return errors.Errorf("no username supplied") 95 } 96 c.UserName = args[0] 97 return cmd.CheckEmpty(args[1:]) 98 } 99 100 // Run implements Command.Run. 101 func (c *removeCommand) Run(ctx *cmd.Context) error { 102 controllerName, err := c.ControllerName() 103 if err != nil { 104 return errors.Trace(err) 105 } 106 api := c.api // This is for testing. 107 108 if api == nil { // The real McCoy. 109 var err error 110 api, err = c.NewUserManagerAPIClient() 111 if err != nil { 112 return errors.Trace(err) 113 } 114 defer api.Close() 115 } 116 117 // Confirm deletion if the user didn't specify -y/--yes in the command. 118 if !c.ConfirmDelete { 119 if err := confirmDelete(ctx, controllerName, c.UserName); err != nil { 120 return errors.Trace(err) 121 } 122 } 123 124 if err := api.RemoveUser(c.UserName); err != nil { 125 // This is very awful, but it makes the user experience crisper. At 126 // least maybe more tenable until users and authn/z are overhauled. 127 if e, ok := err.(*params.Error); ok { 128 if e.Message == fmt.Sprintf("failed to delete user %q: user %q is permanently deleted", c.UserName, c.UserName) { 129 e.Message = fmt.Sprintf("failed to delete user %q: the user has already been permanently deleted", c.UserName) 130 err = e 131 } 132 } 133 return block.ProcessBlockedError(err, block.BlockChange) 134 } 135 136 fmt.Fprintf(ctx.Stdout, "User %q removed\n", c.UserName) 137 138 return nil 139 } 140 141 func confirmDelete(ctx *cmd.Context, controller, username string) error { 142 // Get confirmation from the user that they want to continue 143 fmt.Fprintf(ctx.Stdout, removeUserMsg, username, controller) 144 145 scanner := bufio.NewScanner(ctx.Stdin) 146 scanner.Scan() 147 err := scanner.Err() 148 if err != nil && err != io.EOF { 149 return errors.Annotate(err, "user deletion aborted") 150 } 151 answer := strings.ToLower(scanner.Text()) 152 if answer != "y" && answer != "yes" { 153 return errors.New("user deletion aborted") 154 } 155 return nil 156 }