github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/modelcmd/credentials.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package modelcmd 5 6 import ( 7 "io/ioutil" 8 9 "github.com/juju/errors" 10 "github.com/juju/utils" 11 12 "github.com/juju/juju/cloud" 13 "github.com/juju/juju/environs" 14 "github.com/juju/juju/jujuclient" 15 ) 16 17 var ( 18 // ErrMultipleCredentials is the error returned by DetectCredential 19 // if more than one credential is detected. 20 ErrMultipleCredentials = errors.New("more than one credential detected") 21 ) 22 23 // GetCredentials returns a curated set of credential values for a given cloud. 24 // The credential key values are read from the credentials store and the provider 25 // finalises the values to resolve things like json files. 26 // If region is not specified, the default credential region is used. 27 func GetCredentials( 28 store jujuclient.CredentialGetter, region, credentialName, cloudName, cloudType string, 29 ) (_ *cloud.Credential, chosenCredentialName, regionName string, _ error) { 30 31 credential, credentialName, defaultRegion, err := credentialByName( 32 store, cloudName, credentialName, 33 ) 34 if err != nil { 35 return nil, "", "", errors.Trace(err) 36 } 37 38 regionName = region 39 if regionName == "" { 40 regionName = defaultRegion 41 } 42 43 readFile := func(f string) ([]byte, error) { 44 f, err := utils.NormalizePath(f) 45 if err != nil { 46 return nil, errors.Trace(err) 47 } 48 return ioutil.ReadFile(f) 49 } 50 51 // Finalize credential against schemas supported by the provider. 52 provider, err := environs.Provider(cloudType) 53 if err != nil { 54 return nil, "", "", errors.Trace(err) 55 } 56 57 credential, err = cloud.FinalizeCredential( 58 *credential, provider.CredentialSchemas(), readFile, 59 ) 60 if err != nil { 61 return nil, "", "", errors.Annotatef( 62 err, "validating %q credential for cloud %q", 63 credentialName, cloudName, 64 ) 65 } 66 return credential, credentialName, regionName, nil 67 } 68 69 // credentialByName returns the credential and default region to use for the 70 // specified cloud, optionally specifying a credential name. If no credential 71 // name is specified, then use the default credential for the cloud if one has 72 // been specified. The credential name is returned also, in case the default 73 // credential is used. If there is only one credential, it is implicitly the 74 // default. 75 // 76 // If there exists no matching credentials, an error satisfying 77 // errors.IsNotFound will be returned. 78 func credentialByName( 79 store jujuclient.CredentialGetter, cloudName, credentialName string, 80 ) (_ *cloud.Credential, credentialNameUsed string, defaultRegion string, _ error) { 81 82 cloudCredentials, err := store.CredentialForCloud(cloudName) 83 if err != nil { 84 return nil, "", "", errors.Annotate(err, "loading credentials") 85 } 86 if credentialName == "" { 87 // No credential specified, so use the default for the cloud. 88 credentialName = cloudCredentials.DefaultCredential 89 if credentialName == "" && len(cloudCredentials.AuthCredentials) == 1 { 90 for credentialName = range cloudCredentials.AuthCredentials { 91 } 92 } 93 } 94 credential, ok := cloudCredentials.AuthCredentials[credentialName] 95 if !ok { 96 return nil, "", "", errors.NotFoundf( 97 "%q credential for cloud %q", credentialName, cloudName, 98 ) 99 } 100 return &credential, credentialName, cloudCredentials.DefaultRegion, nil 101 } 102 103 // DetectCredential detects credentials for the specified cloud type, and, if 104 // exactly one is detected, returns it. 105 // 106 // If no credentials are detected, an error satisfying errors.IsNotFound will 107 // be returned. If more than one credential is detected, ErrMultipleCredentials 108 // will be returned. 109 func DetectCredential(cloudName, cloudType string) (*cloud.CloudCredential, error) { 110 provider, err := environs.Provider(cloudType) 111 if err != nil { 112 return nil, errors.Trace(err) 113 } 114 detected, err := provider.DetectCredentials() 115 if err != nil { 116 return nil, errors.Annotatef( 117 err, "detecting credentials for %q cloud provider", cloudName, 118 ) 119 } 120 logger.Tracef("provider detected credentials: %v", detected) 121 if len(detected.AuthCredentials) == 0 { 122 return nil, errors.NotFoundf("credentials for cloud %q", cloudName) 123 } 124 if len(detected.AuthCredentials) > 1 { 125 return nil, ErrMultipleCredentials 126 } 127 return detected, nil 128 }