func findAuthOpts(c *cli.Context, have map[string]commandoptions.Cred, want map[string]string) error { // use command-line options if available commandoptions.CLIopts(c, have, want) // are there any unset auth variables? if len(want) != 0 { // if so, look in config file err := commandoptions.ConfigFile(c, have, want) if err != nil { return err } // still unset auth variables? if len(want) != 0 { // if so, look in environment variables envvars(have, want) } } return nil }
// Credentials determines the appropriate authentication method for the user. // It returns a gophercloud.AuthOptions object and a region. // // It will use command-line authentication parameters if available, then it will // look for any unset parameters in the config file, and then finally in // environment variables. func Credentials(c *cli.Context, logger *logrus.Logger) (*CredentialsResult, error) { ao := &gophercloud.AuthOptions{ AllowReauth: true, } have := make(map[string]commandoptions.Cred) // let's looks for a region and identity endpoint want := map[string]string{ "auth-url": "", "region": "", } err := findAuthOpts(c, have, want) if err != nil { return nil, err } // if the user didn't provide an auth URL, default to the Rackspace US endpoint if _, ok := have["auth-url"]; !ok || have["auth-url"].Value == "" { have["auth-url"] = commandoptions.Cred{Value: rackspace.RackspaceUSIdentity, From: "default value"} delete(want, "auth-url") } ao.IdentityEndpoint = have["auth-url"].Value // upper-case the region region := strings.ToUpper(have["region"].Value) delete(want, "region") // now we check for token authentication (only allowed via the command-line) want["auth-tenant-id"] = "" want["auth-token"] = "" commandoptions.CLIopts(c, have, want) // if a tenant ID was provided on the command-line, we don't bother checking for a // username or api key if have["auth-tenant-id"].Value != "" || have["auth-token"].Value != "" { if tenantID, ok := have["auth-tenant-id"]; ok { ao.TenantID = tenantID.Value ao.TokenID = have["auth-token"].Value delete(want, "auth-token") } else { return nil, Err(have, want, tenantIDAuthErrSlice) } } else { // otherwise, let's look for a username and API key want = map[string]string{ "username": "", "api-key": "", } err = findAuthOpts(c, have, want) if err != nil { return nil, err } if have["username"].Value != "" || have["api-key"].Value != "" { if username, ok := have["username"]; ok { ao.Username = username.Value ao.APIKey = have["api-key"].Value delete(want, "api-key") } else { return nil, Err(have, want, usernameAuthErrSlice) } } else { return nil, Err(have, want, usernameAuthErrSlice) } } if logger != nil { haveString := "" for k, v := range have { haveString += fmt.Sprintf("%s: %s (from %s)\n", k, v.Value, v.From) } logger.Infof("Authentication Credentials:\n%s\n", haveString) } credsResult := &CredentialsResult{ AuthOpts: ao, Region: region, Have: have, Want: want, } return credsResult, nil }
func (ctx *Context) handleGlobalOptions() error { defaultSection, err := commandoptions.ProfileSection("") if err != nil { return err } defaultKeysHash := map[string]string{} if defaultSection != nil { defaultKeysHash = defaultSection.KeysHash() } have := make(map[string]commandoptions.Cred) want := map[string]string{ "output": "", "no-cache": "", "no-header": "", "log": "", "use-service-net": "", } // use command-line options if available commandoptions.CLIopts(ctx.CLIContext, have, want) // are there any unset auth variables? if len(want) != 0 { // if so, look in config file err := commandoptions.ConfigFile(ctx.CLIContext, have, want) if err != nil { return err } } var outputFormat string if ctx.CLIContext.IsSet("output") { outputFormat = ctx.CLIContext.String("output") } else if value, ok := defaultKeysHash["output"]; ok && value != "" { outputFormat = value } else { have["output"] = commandoptions.Cred{ Value: "table", From: "default value", } outputFormat = "table" } switch outputFormat { case "json", "csv", "table": ctx.GlobalOptions.output = outputFormat default: return fmt.Errorf("Invalid value for `output` flag: '%s'. Options are: json, csv, table.", outputFormat) } if ctx.CLIContext.IsSet("no-header") { ctx.GlobalOptions.noHeader = true } else if value, ok := defaultKeysHash["no-header"]; ok && value != "" { ctx.GlobalOptions.noHeader = true } if ctx.CLIContext.IsSet("no-cache") { ctx.GlobalOptions.noCache = true } else if value, ok := defaultKeysHash["no-cache"]; ok && value != "" { ctx.GlobalOptions.noCache = true } if ctx.CLIContext.IsSet("use-service-net") { ctx.GlobalOptions.useServiceNet = true } else if value, ok := defaultKeysHash["use-service-net"]; ok && value != "" { ctx.GlobalOptions.useServiceNet = true } var logLevel string if ctx.CLIContext.IsSet("log") { logLevel = ctx.CLIContext.String("log") } else if value, ok := defaultKeysHash["log"]; ok && value != "" { logLevel = value } var level logrus.Level if logLevel != "" { switch strings.ToLower(logLevel) { case "debug": level = logrus.DebugLevel case "info": level = logrus.InfoLevel default: return fmt.Errorf("Invalid value for `log` flag: %s. Valid options are: debug, info", logLevel) } } ctx.logger = &logrus.Logger{ Out: ctx.CLIContext.App.Writer, Formatter: &logrus.TextFormatter{}, Level: level, } haveString := "" for k, v := range have { haveString += fmt.Sprintf("%s: %s (from %s)\n", k, v.Value, v.From) } ctx.logger.Infof("Global Options:\n%s\n", haveString) return nil }