~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/modelcmd/credentials.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}