github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 "strconv" 12 13 "github.com/juju/errors" 14 "github.com/juju/utils" 15 "gopkg.in/goose.v2/identity" 16 "gopkg.in/ini.v1" 17 18 "github.com/juju/juju/cloud" 19 "github.com/juju/juju/environs" 20 ) 21 22 const ( 23 CredAttrTenantName = "tenant-name" 24 CredAttrTenantID = "tenant-id" 25 CredAttrUserName = "username" 26 CredAttrPassword = "password" 27 CredAttrDomainName = "domain-name" 28 CredAttrProjectDomainName = "project-domain-name" 29 CredAttrUserDomainName = "user-domain-name" 30 CredAttrAccessKey = "access-key" 31 CredAttrSecretKey = "secret-key" 32 CredAttrVersion = "version" 33 ) 34 35 type OpenstackCredentials struct{} 36 37 // CredentialSchemas is part of the environs.ProviderCredentials interface. 38 func (OpenstackCredentials) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema { 39 return map[cloud.AuthType]cloud.CredentialSchema{ 40 cloud.UserPassAuthType: { 41 { 42 CredAttrUserName, cloud.CredentialAttr{Description: "The username to authenticate with."}, 43 }, { 44 CredAttrPassword, cloud.CredentialAttr{ 45 Description: "The password for the specified username.", 46 Hidden: true, 47 }, 48 }, { 49 CredAttrTenantName, cloud.CredentialAttr{ 50 Description: "The OpenStack tenant name.", 51 Optional: true, 52 }, 53 }, { 54 CredAttrTenantID, cloud.CredentialAttr{ 55 Description: "The Openstack tenant ID", 56 Optional: true, 57 }, 58 }, { 59 CredAttrVersion, cloud.CredentialAttr{ 60 Description: "The Openstack identity version", 61 Optional: true, 62 }, 63 }, { 64 CredAttrDomainName, cloud.CredentialAttr{ 65 Description: "The OpenStack domain name.", 66 Optional: true, 67 }, 68 }, { 69 CredAttrProjectDomainName, cloud.CredentialAttr{ 70 Description: "The OpenStack project domain name.", 71 Optional: true, 72 }, 73 }, { 74 CredAttrUserDomainName, cloud.CredentialAttr{ 75 Description: "The OpenStack user domain name.", 76 Optional: true, 77 }, 78 }, 79 }, 80 cloud.AccessKeyAuthType: { 81 { 82 CredAttrAccessKey, cloud.CredentialAttr{Description: "The access key to authenticate with."}, 83 }, { 84 CredAttrSecretKey, cloud.CredentialAttr{ 85 Description: "The secret key to authenticate with.", 86 Hidden: true, 87 }, 88 }, { 89 CredAttrTenantName, cloud.CredentialAttr{ 90 Description: "The OpenStack tenant name.", 91 Optional: true, 92 }, 93 }, { 94 CredAttrTenantID, cloud.CredentialAttr{ 95 Description: "The Openstack tenant ID", 96 Optional: true, 97 }, 98 }, { 99 CredAttrVersion, cloud.CredentialAttr{ 100 Description: "The Openstack identity version", 101 Optional: true, 102 }, 103 }, 104 }, 105 } 106 } 107 108 // DetectCredentials is part of the environs.ProviderCredentials interface. 109 func (c OpenstackCredentials) DetectCredentials() (*cloud.CloudCredential, error) { 110 result := cloud.CloudCredential{ 111 AuthCredentials: make(map[string]cloud.Credential), 112 } 113 114 // Try just using environment variables 115 creds, user, region, err := c.detectCredential() 116 if err == nil { 117 result.DefaultRegion = region 118 result.AuthCredentials[user] = *creds 119 } 120 121 // Now look for .novarc file in home dir. 122 novarc := filepath.Join(utils.Home(), ".novarc") 123 novaInfo, err := ini.LooseLoad(novarc) 124 if err != nil { 125 return nil, errors.Annotate(err, "loading novarc file") 126 } 127 stripExport := regexp.MustCompile(`(?i)^\s*export\s*`) 128 keyValues := novaInfo.Section(ini.DEFAULT_SECTION).KeysHash() 129 if len(keyValues) > 0 { 130 for k, v := range keyValues { 131 k = stripExport.ReplaceAllString(k, "") 132 os.Setenv(k, v) 133 } 134 creds, user, region, err := c.detectCredential() 135 if err == nil { 136 result.DefaultRegion = region 137 result.AuthCredentials[user] = *creds 138 } 139 } 140 if len(result.AuthCredentials) == 0 { 141 return nil, errors.NotFoundf("openstack credentials") 142 } 143 return &result, nil 144 } 145 146 func (c OpenstackCredentials) detectCredential() (*cloud.Credential, string, string, error) { 147 creds, err := identity.CredentialsFromEnv() 148 if err != nil { 149 return nil, "", "", errors.Errorf("failed to retrive cred from env : %v", err) 150 } 151 if creds.TenantName == "" { 152 logger.Debugf("neither OS_TENANT_NAME nor OS_PROJECT_NAME environment variable not set") 153 } 154 if creds.TenantID == "" { 155 logger.Debugf("neither OS_TENANT_ID nor OS_PROJECT_ID environment variable not set") 156 } 157 if creds.User == "" { 158 return nil, "", "", errors.NewNotFound(nil, "neither OS_USERNAME nor OS_ACCESS_KEY environment variable not set") 159 } 160 if creds.Secrets == "" { 161 return nil, "", "", errors.NewNotFound(nil, "neither OS_PASSWORD nor OS_SECRET_KEY environment variable not set") 162 } 163 164 user, err := utils.LocalUsername() 165 if err != nil { 166 return nil, "", "", errors.Trace(err) 167 } 168 169 var version string 170 if creds.Version != 0 { 171 version = strconv.Itoa(creds.Version) 172 } else { 173 version = "" 174 } 175 // If OS_USERNAME or NOVA_USERNAME is set, assume userpass. 176 var credential cloud.Credential 177 if os.Getenv("OS_USERNAME") != "" || os.Getenv("NOVA_USERNAME") != "" { 178 user = creds.User 179 credential = cloud.NewCredential( 180 cloud.UserPassAuthType, 181 map[string]string{ 182 CredAttrUserName: creds.User, 183 CredAttrPassword: creds.Secrets, 184 CredAttrTenantName: creds.TenantName, 185 CredAttrTenantID: creds.TenantID, 186 CredAttrUserDomainName: creds.UserDomain, 187 CredAttrProjectDomainName: creds.ProjectDomain, 188 CredAttrDomainName: creds.Domain, 189 CredAttrVersion: version, 190 }, 191 ) 192 } else { 193 credential = cloud.NewCredential( 194 cloud.AccessKeyAuthType, 195 map[string]string{ 196 CredAttrAccessKey: creds.User, 197 CredAttrSecretKey: creds.Secrets, 198 CredAttrTenantName: creds.TenantName, 199 CredAttrTenantID: creds.TenantID, 200 CredAttrVersion: version, 201 }, 202 ) 203 } 204 region := creds.Region 205 if region == "" { 206 region = "<unspecified>" 207 } 208 credential.Label = fmt.Sprintf("openstack region %q project %q user %q", region, creds.TenantName, user) 209 return &credential, user, creds.Region, nil 210 } 211 212 // FinalizeCredential is part of the environs.ProviderCredentials interface. 213 func (OpenstackCredentials) FinalizeCredential(_ environs.FinalizeCredentialContext, args environs.FinalizeCredentialParams) (*cloud.Credential, error) { 214 return &args.Credential, nil 215 }