github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/openstack/credentials.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package openstack 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "regexp" 11 12 "github.com/juju/errors" 13 "github.com/juju/utils" 14 "gopkg.in/goose.v1/identity" 15 "gopkg.in/ini.v1" 16 17 "github.com/juju/juju/cloud" 18 "github.com/juju/juju/environs" 19 ) 20 21 const ( 22 CredAttrTenantName = "tenant-name" 23 CredAttrUserName = "username" 24 CredAttrPassword = "password" 25 CredAttrDomainName = "domain-name" 26 CredAttrAccessKey = "access-key" 27 CredAttrSecretKey = "secret-key" 28 ) 29 30 type OpenstackCredentials struct{} 31 32 // CredentialSchemas is part of the environs.ProviderCredentials interface. 33 func (OpenstackCredentials) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema { 34 return map[cloud.AuthType]cloud.CredentialSchema{ 35 cloud.UserPassAuthType: { 36 { 37 CredAttrUserName, cloud.CredentialAttr{Description: "The username to authenticate with."}, 38 }, { 39 CredAttrPassword, cloud.CredentialAttr{ 40 Description: "The password for the specified username.", 41 Hidden: true, 42 }, 43 }, { 44 CredAttrTenantName, cloud.CredentialAttr{Description: "The OpenStack tenant name."}, 45 }, { 46 CredAttrDomainName, cloud.CredentialAttr{ 47 Description: "The OpenStack domain name.", 48 Optional: true, 49 }, 50 }, 51 }, 52 cloud.AccessKeyAuthType: { 53 { 54 CredAttrAccessKey, cloud.CredentialAttr{Description: "The access key to authenticate with."}, 55 }, { 56 CredAttrSecretKey, cloud.CredentialAttr{ 57 Description: "The secret key to authenticate with.", 58 Hidden: true, 59 }, 60 }, { 61 CredAttrTenantName, cloud.CredentialAttr{Description: "The OpenStack tenant name."}, 62 }, 63 }, 64 } 65 } 66 67 // DetectCredentials is part of the environs.ProviderCredentials interface. 68 func (c OpenstackCredentials) DetectCredentials() (*cloud.CloudCredential, error) { 69 result := cloud.CloudCredential{ 70 AuthCredentials: make(map[string]cloud.Credential), 71 } 72 73 // Try just using environment variables 74 creds, user, region, err := c.detectCredential() 75 if err == nil { 76 result.DefaultRegion = region 77 result.AuthCredentials[user] = *creds 78 } 79 80 // Now look for .novarc file in home dir. 81 novarc := filepath.Join(utils.Home(), ".novarc") 82 novaInfo, err := ini.LooseLoad(novarc) 83 if err != nil { 84 return nil, errors.Annotate(err, "loading novarc file") 85 } 86 stripExport := regexp.MustCompile(`(?i)^\s*export\s*`) 87 keyValues := novaInfo.Section(ini.DEFAULT_SECTION).KeysHash() 88 if len(keyValues) > 0 { 89 for k, v := range keyValues { 90 k = stripExport.ReplaceAllString(k, "") 91 os.Setenv(k, v) 92 } 93 creds, user, region, err := c.detectCredential() 94 if err == nil { 95 result.DefaultRegion = region 96 result.AuthCredentials[user] = *creds 97 } 98 } 99 if len(result.AuthCredentials) == 0 { 100 return nil, errors.NotFoundf("openstack credentials") 101 } 102 return &result, nil 103 } 104 105 func (c OpenstackCredentials) detectCredential() (*cloud.Credential, string, string, error) { 106 creds := identity.CredentialsFromEnv() 107 if creds.TenantName == "" { 108 return nil, "", "", errors.NewNotFound(nil, "OS_TENANT_NAME environment variable not set") 109 } 110 if creds.User == "" { 111 return nil, "", "", errors.NewNotFound(nil, "neither OS_USERNAME nor OS_ACCESS_KEY environment variable not set") 112 } 113 if creds.Secrets == "" { 114 return nil, "", "", errors.NewNotFound(nil, "neither OS_PASSWORD nor OS_SECRET_KEY environment variable not set") 115 } 116 117 user, err := utils.LocalUsername() 118 if err != nil { 119 return nil, "", "", errors.Trace(err) 120 } 121 122 // If OS_USERNAME or NOVA_USERNAME is set, assume userpass. 123 var credential cloud.Credential 124 if os.Getenv("OS_USERNAME") != "" || os.Getenv("NOVA_USERNAME") != "" { 125 user = creds.User 126 credential = cloud.NewCredential( 127 cloud.UserPassAuthType, 128 map[string]string{ 129 CredAttrUserName: creds.User, 130 CredAttrPassword: creds.Secrets, 131 CredAttrTenantName: creds.TenantName, 132 CredAttrDomainName: creds.DomainName, 133 }, 134 ) 135 } else { 136 credential = cloud.NewCredential( 137 cloud.AccessKeyAuthType, 138 map[string]string{ 139 CredAttrAccessKey: creds.User, 140 CredAttrSecretKey: creds.Secrets, 141 CredAttrTenantName: creds.TenantName, 142 }, 143 ) 144 } 145 region := creds.Region 146 if region == "" { 147 region = "<unspecified>" 148 } 149 credential.Label = fmt.Sprintf("openstack region %q project %q user %q", region, creds.TenantName, user) 150 return &credential, user, creds.Region, nil 151 } 152 153 // FinalizeCredential is part of the environs.ProviderCredentials interface. 154 func (OpenstackCredentials) FinalizeCredential(_ environs.FinalizeCredentialContext, args environs.FinalizeCredentialParams) (*cloud.Credential, error) { 155 return &args.Credential, nil 156 }