github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/cloud/detectcredentials_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloud_test 5 6 import ( 7 "fmt" 8 "io" 9 "regexp" 10 "strings" 11 12 "github.com/juju/cmd" 13 "github.com/juju/cmd/cmdtesting" 14 "github.com/juju/errors" 15 jc "github.com/juju/testing/checkers" 16 gc "gopkg.in/check.v1" 17 18 jujucloud "github.com/juju/juju/cloud" 19 "github.com/juju/juju/cmd/juju/cloud" 20 "github.com/juju/juju/environs" 21 "github.com/juju/juju/jujuclient" 22 "github.com/juju/juju/testing" 23 ) 24 25 type detectCredentialsSuite struct { 26 testing.BaseSuite 27 28 store *jujuclient.MemStore 29 aCredential jujucloud.CloudCredential 30 } 31 32 var _ = gc.Suite(&detectCredentialsSuite{}) 33 34 type mockProvider struct { 35 environs.CloudEnvironProvider 36 detectedCreds *jujucloud.CloudCredential 37 credSchemas *map[jujucloud.AuthType]jujucloud.CredentialSchema 38 } 39 40 func (p *mockProvider) DetectCredentials() (*jujucloud.CloudCredential, error) { 41 if len(p.detectedCreds.AuthCredentials) == 0 { 42 return nil, errors.NotFoundf("credentials") 43 } 44 return p.detectedCreds, nil 45 } 46 47 func (p *mockProvider) CredentialSchemas() map[jujucloud.AuthType]jujucloud.CredentialSchema { 48 if p.credSchemas == nil { 49 return map[jujucloud.AuthType]jujucloud.CredentialSchema{ 50 jujucloud.AccessKeyAuthType: { 51 { 52 "access-key", jujucloud.CredentialAttr{}, 53 }, { 54 "secret-key", jujucloud.CredentialAttr{Hidden: true}, 55 }, 56 }, 57 jujucloud.UserPassAuthType: { 58 { 59 "username", jujucloud.CredentialAttr{}, 60 }, { 61 "password", jujucloud.CredentialAttr{Hidden: true}, 62 }, { 63 "application-password", jujucloud.CredentialAttr{Hidden: true}, 64 }, 65 }, 66 jujucloud.OAuth2AuthType: { 67 { 68 "client-id", jujucloud.CredentialAttr{}, 69 }, { 70 "client-email", jujucloud.CredentialAttr{}, 71 }, { 72 "private-key", jujucloud.CredentialAttr{Hidden: true}, 73 }, { 74 "project-id", jujucloud.CredentialAttr{}, 75 }, 76 }, 77 } 78 } 79 return *p.credSchemas 80 } 81 82 func (p *mockProvider) FinalizeCredential( 83 ctx environs.FinalizeCredentialContext, 84 args environs.FinalizeCredentialParams, 85 ) (*jujucloud.Credential, error) { 86 if args.Credential.AuthType() == "interactive" { 87 fmt.Fprintln(ctx.GetStderr(), "generating userpass credential") 88 out := jujucloud.NewCredential(jujucloud.UserPassAuthType, map[string]string{ 89 "username": args.Credential.Attributes()["username"], 90 "password": args.CloudEndpoint, 91 "application-password": args.CloudIdentityEndpoint, 92 }) 93 return &out, nil 94 } 95 return &args.Credential, nil 96 } 97 98 func (s *detectCredentialsSuite) SetUpSuite(c *gc.C) { 99 s.BaseSuite.SetUpSuite(c) 100 unreg := environs.RegisterProvider("mock-provider", &mockProvider{detectedCreds: &s.aCredential}) 101 s.AddCleanup(func(_ *gc.C) { 102 unreg() 103 }) 104 } 105 106 func (s *detectCredentialsSuite) SetUpTest(c *gc.C) { 107 s.BaseSuite.SetUpTest(c) 108 s.store = jujuclient.NewMemStore() 109 s.aCredential = jujucloud.CloudCredential{} 110 } 111 112 func (s *detectCredentialsSuite) run(c *gc.C, stdin io.Reader, clouds map[string]jujucloud.Cloud) (*cmd.Context, error) { 113 registeredProvidersFunc := func() []string { 114 return []string{"mock-provider"} 115 } 116 allCloudsFunc := func() (map[string]jujucloud.Cloud, error) { 117 return clouds, nil 118 } 119 cloudByNameFunc := func(cloudName string) (*jujucloud.Cloud, error) { 120 if cloud, ok := clouds[cloudName]; ok { 121 return &cloud, nil 122 } 123 return nil, errors.NotFoundf("cloud %s", cloudName) 124 } 125 command := cloud.NewDetectCredentialsCommandForTest(s.store, registeredProvidersFunc, allCloudsFunc, cloudByNameFunc) 126 err := cmdtesting.InitCommand(command, nil) 127 c.Assert(err, jc.ErrorIsNil) 128 ctx := cmdtesting.Context(c) 129 ctx.Stdin = stdin 130 return ctx, command.Run(ctx) 131 } 132 133 func (s *detectCredentialsSuite) credentialWithLabel(authType jujucloud.AuthType, label string) jujucloud.Credential { 134 cred := jujucloud.NewCredential(authType, nil) 135 cred.Label = label 136 return cred 137 } 138 139 func (s *detectCredentialsSuite) assertDetectCredential(c *gc.C, cloudName, expectedRegion, errText string) { 140 s.aCredential = jujucloud.CloudCredential{ 141 DefaultRegion: "default region", 142 AuthCredentials: map[string]jujucloud.Credential{ 143 "test": s.credentialWithLabel(jujucloud.AccessKeyAuthType, "credential")}, 144 } 145 clouds := map[string]jujucloud.Cloud{ 146 "test-cloud": { 147 Type: "mock-provider", 148 }, 149 "another-cloud": { 150 Type: "another-provider", 151 }, 152 } 153 154 stdin := strings.NewReader(fmt.Sprintf("1\n%s\nQ\n", cloudName)) 155 ctx, err := s.run(c, stdin, clouds) 156 c.Assert(err, jc.ErrorIsNil) 157 if errText == "" { 158 if expectedRegion != "" { 159 s.aCredential.DefaultRegion = expectedRegion 160 } 161 c.Assert(s.store.Credentials["test-cloud"], jc.DeepEquals, s.aCredential) 162 } else { 163 output := strings.Replace(cmdtesting.Stderr(ctx), "\n", "", -1) 164 c.Assert(output, gc.Matches, ".*"+regexp.QuoteMeta(errText)+".*") 165 } 166 } 167 168 func (s *detectCredentialsSuite) TestDetectNewCredential(c *gc.C) { 169 s.assertDetectCredential(c, "test-cloud", "", "") 170 } 171 172 func (s *detectCredentialsSuite) TestDetectCredentialOverwrites(c *gc.C) { 173 s.store.Credentials = map[string]jujucloud.CloudCredential{ 174 "test-cloud": { 175 AuthCredentials: map[string]jujucloud.Credential{ 176 "test": jujucloud.NewCredential(jujucloud.AccessKeyAuthType, nil), 177 }, 178 }, 179 } 180 s.assertDetectCredential(c, "test-cloud", "", "") 181 } 182 183 func (s *detectCredentialsSuite) TestDetectCredentialKeepsExistingRegion(c *gc.C) { 184 s.store.Credentials = map[string]jujucloud.CloudCredential{ 185 "test-cloud": { 186 DefaultRegion: "west", 187 AuthCredentials: map[string]jujucloud.Credential{ 188 "test": jujucloud.NewCredential(jujucloud.AccessKeyAuthType, nil), 189 }, 190 }, 191 } 192 s.assertDetectCredential(c, "test-cloud", "west", "") 193 } 194 195 func (s *detectCredentialsSuite) TestDetectCredentialDefaultCloud(c *gc.C) { 196 s.assertDetectCredential(c, "", "", "") 197 } 198 199 func (s *detectCredentialsSuite) TestDetectCredentialUnknownCloud(c *gc.C) { 200 s.assertDetectCredential(c, "foo", "", "cloud foo not valid") 201 } 202 203 func (s *detectCredentialsSuite) TestDetectCredentialInvalidCloud(c *gc.C) { 204 s.assertDetectCredential(c, "another-cloud", "", "chosen credentials not compatible with a another-provider cloud") 205 } 206 207 func (s *detectCredentialsSuite) TestNewDetectCredentialNoneFound(c *gc.C) { 208 stdin := strings.NewReader("") 209 ctx, err := s.run(c, stdin, nil) 210 c.Assert(err, jc.ErrorIsNil) 211 output := strings.Replace(cmdtesting.Stderr(ctx), "\n", "", -1) 212 c.Assert(output, gc.Matches, ".*No cloud credentials found.*") 213 c.Assert(s.store.Credentials, gc.HasLen, 0) 214 } 215 216 func (s *detectCredentialsSuite) TestDetectCredentialInvalidChoice(c *gc.C) { 217 s.aCredential = jujucloud.CloudCredential{ 218 DefaultRegion: "detected region", 219 AuthCredentials: map[string]jujucloud.Credential{ 220 "test": s.credentialWithLabel(jujucloud.AccessKeyAuthType, "credential 1"), 221 "another": s.credentialWithLabel(jujucloud.AccessKeyAuthType, "credential 2")}, 222 } 223 224 stdin := strings.NewReader("3\nQ\n") 225 ctx, err := s.run(c, stdin, nil) 226 c.Assert(err, jc.ErrorIsNil) 227 output := strings.Replace(cmdtesting.Stderr(ctx), "\n", "", -1) 228 c.Assert(output, gc.Matches, ".*Invalid choice, enter a number between 1 and 2.*") 229 c.Assert(s.store.Credentials, gc.HasLen, 0) 230 }