Skip to content

Commit

Permalink
Allow multiple accounts to be saved in config
Browse files Browse the repository at this point in the history
  • Loading branch information
anagrius committed Nov 29, 2018
1 parent e5fe290 commit a97739f
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 35 deletions.
195 changes: 165 additions & 30 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ import (
"github.com/spf13/viper"
)

type Login struct {
address string
token string
username string
}

// usersCmd represents the users command
func newLoginCmd() *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -23,20 +29,67 @@ func newLoginCmd() *cobra.Command {
You can also specify a differant config file to initialize by setting the --config flag.
In the config file already exists, the settings will be merged into the existing.`,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
var addr, token string
var err error
accounts := viper.GetStringMap("accounts")

prompt.Output("")
owl := "[purple]" + prompt.Owl() + "[reset]"
fmt.Print((prompt.Colorize(owl)))
prompt.Output("")
prompt.Title("Welcome to Humio")
prompt.Output("")
prompt.Description("This will guide you through setting up the Humio CLI.")
prompt.Output("")
if len(accounts) > 0 {
prompt.Output("")
prompt.Title("Add another account")
} else {
prompt.Output("")
owl := "[purple]" + prompt.Owl() + "[reset]"
fmt.Print((prompt.Colorize(owl)))
prompt.Output("")
prompt.Title("Welcome to Humio")
prompt.Output("")
prompt.Description("This will guide you through setting up the Humio CLI.")
prompt.Output("")
}

if currentAddr := viper.GetString("address"); currentAddr != "" {
currentToken := viper.GetString("token")

prompt.Info("Which Humio instance should we talk to?") // INFO
if accounts != nil {
var currentName string
for name, data := range accounts {
login := mapToLogin(data)
if login.address == currentAddr && login.token == currentToken {
currentName = name
}
}

if currentName == "" {
prompt.Output("")
prompt.Output("You are currently logged in an unnamed account (address/token).")
prompt.Output("Would you like to name the account before logging in with another?")
prompt.Output("This way you can quickly switch between accounts and servers.")
prompt.Output("")

client := NewApiClient(cmd)
username, usernameErr := client.Viewer().Username()

prompt.Output("Server: " + currentAddr)

if usernameErr != nil {
prompt.Output(prompt.Colorize("Username: [red][Error] - Invalid token or bad network connection.[reset]"))
} else {
prompt.Output("Username: " + username)
}

prompt.Output("")
if prompt.Confirm("Do you want to save this account?") {
prompt.Output("")
addAccount(cmd, currentAddr, currentToken, username)
}
}
}
prompt.Output("")
}

prompt.Info("Which Humio instance should we talk to?")
prompt.Output("")
prompt.Description("If you are not using Humio Cloud enter the address of your Humio installation,")
prompt.Description("e.g. http://localhost:8080/ or https://humio.example.com/")
Expand Down Expand Up @@ -114,6 +167,7 @@ In the config file already exists, the settings will be merged into the existing
prompt.Description("")
}

var username string
for true {
token, err = prompt.AskSecret("API Token")

Expand All @@ -131,46 +185,127 @@ In the config file already exists, the settings will be merged into the existing
return fmt.Errorf("error initializing the http client: %s", clientErr)
}

username, apiErr := client.Viewer().Username()
var apiErr error
username, apiErr = client.Viewer().Username()

if apiErr != nil {
prompt.Error("authorization failed, try another token")
continue
prompt.Error("Authentication failed, invalid token")

if prompt.Confirm("Do you want to use another token?") {
continue
}
}

fmt.Println("")
fmt.Println("")
fmt.Println(prompt.Colorize(fmt.Sprintf("==> Logged in as: [purple]%s[reset]", username)))
fmt.Println("")
if username != "" {
cmd.Println()
cmd.Println()
cmd.Println(prompt.Colorize(fmt.Sprintf("==> Logged in as: [purple]%s[reset]", username)))
}

cmd.Println()
break
}

viper.Set("address", addr)
viper.Set("token", token)

configFile := viper.ConfigFileUsed()
if len(accounts) > 0 && prompt.Confirm("Would you like to give this account a name?") {
addAccount(cmd, addr, token, username)
}

fmt.Println(prompt.Colorize("==> Writing settings to: [purple]" + configFile + "[reset]"))
configFile := viper.ConfigFileUsed()
cmd.Println(prompt.Colorize("==> Writing settings to: [purple]" + configFile + "[reset]"))

if writeErr := viper.WriteConfig(); writeErr != nil {
if os.IsNotExist(writeErr) {
dirName := filepath.Dir(configFile)
if dirErr := os.MkdirAll(dirName, 0700); dirErr != nil {
return fmt.Errorf("error creating config directory %s: %s", dirName, dirErr)
}
if configFileErr := viper.WriteConfigAs(configFile); configFileErr != nil {
return fmt.Errorf("error writing config file: %s", configFileErr)
}
}
if saveErr := saveConfig(); saveErr != nil {
cmd.Println(fmt.Errorf("error saving config: %s", saveErr))
os.Exit(1)
}

fmt.Println("")
cmd.Println()
prompt.Output("Bye bye now! 🎉")
fmt.Println("")
cmd.Println("")

return nil
},
}

cmd.AddCommand(newLoginListCmd())
cmd.AddCommand(newLoginChooseCmd())

return cmd
}

func saveConfig() error {
configFile := viper.ConfigFileUsed()

if writeErr := viper.WriteConfig(); writeErr != nil {
if os.IsNotExist(writeErr) {
dirName := filepath.Dir(configFile)
if dirErr := os.MkdirAll(dirName, 0700); dirErr != nil {
return fmt.Errorf("error creating config directory %s: %s", dirName, dirErr)
}
if configFileErr := viper.WriteConfigAs(configFile); configFileErr != nil {
return fmt.Errorf("error writing config file: %s", configFileErr)
}
}
}

return nil
}

func addAccount(cmd *cobra.Command, address string, token string, username string) {
prompt.Description("Example names: dev, prod, cloud, root")

for true {
newName, chooseErr := prompt.Ask("Choose a name for the account")
if chooseErr != nil {
cmd.Println(fmt.Errorf("error reading input %s", chooseErr))
os.Exit(1)
}
newName = strings.TrimSpace(newName)
if newName == "" {
prompt.Error("Name cannot be blank.")
continue
} else if newName == "list" || newName == "add" || newName == "remove" {
prompt.Error("The names `list`, `add`, and `remove` are reserved. Choose another.")
continue
}

accounts := viper.GetStringMap("accounts")

accounts[newName] = map[string]string{
"address": address,
"token": token,
"username": username,
}

viper.Set("accounts", accounts)

prompt.Output("")
prompt.Info("Account Saved")
prompt.Output("")
break
}
}

func mapToLogin(data interface{}) *Login {
return &Login{
address: getMapKey(data, "address"),
username: getMapKey(data, "username"),
token: getMapKey(data, "token"),
}
}

func getMapKey(data interface{}, key string) string {
m, ok1 := data.(map[string]interface{})
if ok1 {
v := m[key]
vStr, ok2 := v.(string)

if ok2 {
return vStr
}
}

return ""
}
51 changes: 51 additions & 0 deletions cmd/login_choose.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package cmd

import (
"fmt"
"os"

"github.com/humio/cli/prompt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// usersCmd represents the users command
func newLoginChooseCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "choose <account-name>",
Short: "Choose one of your saved accounts to be the active one.",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
accounts := viper.GetStringMap("accounts")
accountName := args[0]

account := accounts[accountName]

if account == nil {
cmd.Println(fmt.Errorf("unknown account %s", accountName))
os.Exit(1)
}

address := getMapKey(account, "address")
token := getMapKey(account, "token")
username := getMapKey(account, "username")

viper.Set("address", address)
viper.Set("token", token)

if saveErr := saveConfig(); saveErr != nil {
fmt.Println(fmt.Errorf("error saving config: %s", saveErr))
os.Exit(1)
}
prompt.Info(fmt.Sprintf("Switched to account: '%s'", accountName))
cmd.Println()
prompt.Output("Address: " + address)
if username != "" {
prompt.Output("Username: " + username)
}
cmd.Println()
},
}

return cmd
}
42 changes: 42 additions & 0 deletions cmd/login_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cmd

import (
"fmt"

"github.com/humio/cli/prompt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// usersCmd represents the users command
func newLoginListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "list [flags]",
Short: "Lists saved accounts.",
Long: `Lists accounts shored in your ~/.humio/config.yaml file.`,
Run: func(cmd *cobra.Command, args []string) {
accounts := viper.GetStringMap("accounts")

for name, data := range accounts {
login := mapToLogin(data)
if isCurrentAccount(login.address, login.token) {
cmd.Println(prompt.Colorize(fmt.Sprintf("[purple]%s (%s) - %s[reset]", name, login.username, login.address)))
} else {
cmd.Println(fmt.Sprintf("%s (%s) - %s", name, login.username, login.address))
}
}

if len(accounts) == 0 {
cmd.Println("You have no saved accounts")
}

cmd.Println()
},
}

return cmd
}

func isCurrentAccount(addr string, token string) bool {
return viper.GetString("address") == addr && viper.GetString("token") == token
}
21 changes: 16 additions & 5 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ Common Management Commands:
}
}
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if cmd.Name() != "login" {
cmd.Println()
cmd.Println("Humio Address:", viper.GetString("address"))
cmd.Println()
}
},
}

cobra.OnInitialize(initConfig)
Expand Down Expand Up @@ -141,11 +148,7 @@ func initConfig() {
}

func NewApiClient(cmd *cobra.Command) *api.Client {
config := api.DefaultConfig()
config.Address = viper.GetString("address")
config.Token = viper.GetString("token")

client, err := api.NewClient(config)
client, err := NewApiClientE(cmd)

if err != nil {
fmt.Println(fmt.Errorf("Error creating HTTP client: %s", err))
Expand All @@ -154,3 +157,11 @@ func NewApiClient(cmd *cobra.Command) *api.Client {

return client
}

func NewApiClientE(cmd *cobra.Command) (*api.Client, error) {
config := api.DefaultConfig()
config.Address = viper.GetString("address")
config.Token = viper.GetString("token")

return api.NewClient(config)
}

0 comments on commit a97739f

Please sign in to comment.