github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/model/setcredential_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for info. 3 4 package model_test 5 6 import ( 7 "regexp" 8 9 "github.com/juju/cmd" 10 "github.com/juju/cmd/cmdtesting" 11 "github.com/juju/errors" 12 jujutesting "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/names.v2" 16 17 "github.com/juju/juju/api/base" 18 "github.com/juju/juju/cloud" 19 "github.com/juju/juju/cmd/juju/model" 20 coremodel "github.com/juju/juju/core/model" 21 "github.com/juju/juju/jujuclient" 22 _ "github.com/juju/juju/provider/ec2" // needed when getting valid local credentials 23 "github.com/juju/juju/testing" 24 ) 25 26 var _ = gc.Suite(&ModelCredentialCommandSuite{}) 27 28 type ModelCredentialCommandSuite struct { 29 jujutesting.IsolationSuite 30 31 store *jujuclient.MemStore 32 33 modelClient fakeModelClient 34 cloudClient fakeCloudClient 35 rootFunc func() (base.APICallCloser, error) 36 } 37 38 func (s *ModelCredentialCommandSuite) SetUpTest(c *gc.C) { 39 s.IsolationSuite.SetUpTest(c) 40 41 s.store = jujuclient.NewMemStore() 42 s.store.CurrentControllerName = "testing" 43 s.store.Controllers["testing"] = jujuclient.ControllerDetails{} 44 s.store.Accounts["testing"] = jujuclient.AccountDetails{ 45 User: "admin", 46 } 47 err := s.store.UpdateModel("testing", "admin/mymodel", jujuclient.ModelDetails{ 48 ModelUUID: testing.ModelTag.Id(), 49 ModelType: coremodel.IAAS, 50 }) 51 c.Assert(err, jc.ErrorIsNil) 52 s.store.Models["testing"].CurrentModel = "admin/mymodel" 53 54 s.rootFunc = func() (base.APICallCloser, error) { return &fakeRoot{}, nil } 55 s.modelClient = fakeModelClient{} 56 s.cloudClient = fakeCloudClient{} 57 } 58 59 func (s *ModelCredentialCommandSuite) TestBadArguments(c *gc.C) { 60 badArgs := []struct { 61 about string 62 args []string 63 err string 64 stderr string 65 }{{ 66 about: "no arguments", 67 args: []string{}, 68 err: regexp.QuoteMeta("Usage: juju set-credential [options] <cloud name> <credential name>"), 69 stderr: "ERROR Usage: juju set-credential [options] <cloud name> <credential name>\n", 70 }, { 71 about: "1 argument", 72 args: []string{"cloud"}, 73 err: regexp.QuoteMeta("Usage: juju set-credential [options] <cloud name> <credential name>"), 74 stderr: "ERROR Usage: juju set-credential [options] <cloud name> <credential name>\n", 75 }, { 76 about: "3 argument", 77 args: []string{"cloud", "cred", "nothing"}, 78 err: regexp.QuoteMeta("Usage: juju set-credential [options] <cloud name> <credential name>"), 79 stderr: "ERROR Usage: juju set-credential [options] <cloud name> <credential name>\n", 80 }, { 81 about: "not valid cloud name", 82 args: []string{"#1foo", "cred"}, 83 err: "cloud name \"#1foo\" not valid", 84 stderr: "ERROR cloud name \"#1foo\" not valid\n", 85 }, { 86 about: "not valid cloud credential name", 87 args: []string{"cloud", "0foo"}, 88 err: "cloud credential name \"0foo\" not valid", 89 stderr: "ERROR cloud credential name \"0foo\" not valid\n", 90 }} 91 92 for i, bad := range badArgs { 93 c.Logf("%d: %v", i, bad.about) 94 ctx, err := cmdtesting.RunCommand(c, s.newSetCredentialCommand(), bad.args...) 95 c.Assert(err, gc.ErrorMatches, bad.err) 96 97 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, bad.stderr) 98 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 99 100 s.modelClient.CheckNoCalls(c) 101 s.cloudClient.CheckNoCalls(c) 102 } 103 } 104 105 func (s *ModelCredentialCommandSuite) TestRootAPIError(c *gc.C) { 106 s.rootFunc = func() (base.APICallCloser, error) { 107 return nil, errors.New("kaboom") 108 } 109 ctx, err := cmdtesting.RunCommand(c, s.newSetCredentialCommand(), "cloud", "credential") 110 c.Assert(err, gc.ErrorMatches, "opening API connection: kaboom") 111 112 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "Failed to change model credential: opening API connection: kaboom\n") 113 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 114 115 s.modelClient.CheckNoCalls(c) 116 s.cloudClient.CheckNoCalls(c) 117 } 118 119 func (s *ModelCredentialCommandSuite) TestSetCredentialNotFoundAnywhere(c *gc.C) { 120 s.assertCredentialNotFound(c, ` 121 Did not find credential remotely. Looking locally... 122 Failed to change model credential: loading credentials: credentials for cloud aws not found 123 `[1:]) 124 } 125 126 func (s *ModelCredentialCommandSuite) TestSetCredentialRemoteSearchErred(c *gc.C) { 127 s.cloudClient.SetErrors(errors.New("boom")) 128 s.assertCredentialNotFound(c, ` 129 Could not determine if there are remote credentials for the user: boom 130 Did not find credential remotely. Looking locally... 131 Failed to change model credential: loading credentials: credentials for cloud aws not found 132 `[1:]) 133 } 134 135 func (s *ModelCredentialCommandSuite) assertCredentialNotFound(c *gc.C, expectedStderr string) { 136 ctx, err := cmdtesting.RunCommand(c, s.newSetCredentialCommand(), "aws", "credential") 137 c.Assert(err, gc.ErrorMatches, "loading credentials: credentials for cloud aws not found") 138 139 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, expectedStderr) 140 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 141 142 s.modelClient.CheckNoCalls(c) 143 s.cloudClient.CheckCalls(c, []jujutesting.StubCall{ 144 {"UserCredentials", []interface{}{ 145 names.NewUserTag("admin"), 146 names.NewCloudTag("aws"), 147 }}, 148 {"Close", nil}, 149 }) 150 } 151 152 func (s *ModelCredentialCommandSuite) TestSetCredentialFoundRemote(c *gc.C) { 153 err := s.assertRemoteCredentialFound(c, ` 154 Found credential remotely, on the controller. Not looking locally... 155 Changed cloud credential on model "admin/mymodel" to "credential". 156 `[1:]) 157 c.Assert(err, jc.ErrorIsNil) 158 } 159 160 func (s *ModelCredentialCommandSuite) TestSetCredentialErred(c *gc.C) { 161 s.modelClient.SetErrors(errors.New("kaboom")) 162 err := s.assertRemoteCredentialFound(c, ` 163 Found credential remotely, on the controller. Not looking locally... 164 Failed to change model credential: kaboom 165 `[1:]) 166 c.Assert(err, gc.ErrorMatches, "kaboom") 167 } 168 169 func (s *ModelCredentialCommandSuite) assertRemoteCredentialFound(c *gc.C, expectedStderr string) error { 170 credentialTag := names.NewCloudCredentialTag("aws/admin/credential") 171 s.cloudClient.userCredentials = []names.CloudCredentialTag{credentialTag} 172 ctx, err := cmdtesting.RunCommand(c, s.newSetCredentialCommand(), "aws", "credential") 173 174 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, expectedStderr) 175 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 176 177 s.modelClient.CheckCalls(c, []jujutesting.StubCall{ 178 {"ChangeModelCredential", []interface{}{ 179 testing.ModelTag, 180 credentialTag, 181 }}, 182 {"Close", nil}, 183 }) 184 s.cloudClient.CheckCalls(c, []jujutesting.StubCall{ 185 {"UserCredentials", []interface{}{ 186 names.NewUserTag("admin"), 187 names.NewCloudTag("aws"), 188 }}, 189 {"Close", nil}, 190 }) 191 // This the error from running the command. 192 // It's returned to allow individual test to assert their expectations. 193 return err 194 } 195 196 func (s *ModelCredentialCommandSuite) TestSetCredentialLocal(c *gc.C) { 197 err := s.assertLocalCredentialUsed(c, ` 198 Did not find credential remotely. Looking locally... 199 Uploading local credential to the controller. 200 Changed cloud credential on model "admin/mymodel" to "credential". 201 `[1:]) 202 c.Assert(err, jc.ErrorIsNil) 203 204 s.modelClient.CheckCalls(c, []jujutesting.StubCall{ 205 {"ChangeModelCredential", []interface{}{ 206 testing.ModelTag, 207 names.NewCloudCredentialTag("aws/admin/credential"), 208 }}, 209 {"Close", nil}, 210 }) 211 } 212 213 func (s *ModelCredentialCommandSuite) TestSetCredentialLocalUploadFailed(c *gc.C) { 214 s.cloudClient.SetErrors(nil, errors.New("upload failed")) 215 err := s.assertLocalCredentialUsed(c, ` 216 Did not find credential remotely. Looking locally... 217 Uploading local credential to the controller. 218 Failed to change model credential: upload failed 219 `[1:]) 220 c.Assert(err, gc.ErrorMatches, "upload failed") 221 s.modelClient.CheckNoCalls(c) 222 } 223 224 func (s *ModelCredentialCommandSuite) assertLocalCredentialUsed(c *gc.C, expectedStderr string) error { 225 credential := cloud.NewCredential(cloud.AccessKeyAuthType, 226 map[string]string{ 227 "access-key": "v", 228 "secret-key": "v", 229 }, 230 ) 231 cloudCredential := &cloud.CloudCredential{ 232 AuthCredentials: map[string]cloud.Credential{ 233 "credential": credential, 234 }, 235 } 236 s.store.Credentials["aws"] = *cloudCredential 237 ctx, err := cmdtesting.RunCommand(c, s.newSetCredentialCommand(), "aws", "credential") 238 239 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, expectedStderr) 240 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 241 242 s.cloudClient.CheckCalls(c, []jujutesting.StubCall{ 243 {"UserCredentials", []interface{}{ 244 names.NewUserTag("admin"), 245 names.NewCloudTag("aws"), 246 }}, 247 {"AddCredential", []interface{}{ 248 names.NewCloudCredentialTag("aws/admin/credential").String(), 249 credential, 250 }}, 251 {"Close", nil}, 252 }) 253 return err 254 } 255 256 func (s *ModelCredentialCommandSuite) newSetCredentialCommand() cmd.Command { 257 return model.NewModelCredentialCommandForTest(&s.modelClient, &s.cloudClient, s.rootFunc, s.store) 258 } 259 260 type fakeModelClient struct { 261 jujutesting.Stub 262 } 263 264 func (f *fakeModelClient) Close() error { 265 f.MethodCall(f, "Close") 266 return f.NextErr() 267 } 268 269 func (f *fakeModelClient) ChangeModelCredential(model names.ModelTag, credential names.CloudCredentialTag) error { 270 f.MethodCall(f, "ChangeModelCredential", model, credential) 271 return f.NextErr() 272 } 273 274 type fakeCloudClient struct { 275 jujutesting.Stub 276 277 userCredentials []names.CloudCredentialTag 278 } 279 280 func (f *fakeCloudClient) Close() error { 281 f.MethodCall(f, "Close") 282 return f.NextErr() 283 } 284 285 func (f *fakeCloudClient) UserCredentials(u names.UserTag, c names.CloudTag) ([]names.CloudCredentialTag, error) { 286 f.MethodCall(f, "UserCredentials", u, c) 287 return f.userCredentials, f.NextErr() 288 } 289 290 func (f *fakeCloudClient) AddCredential(tag string, credential cloud.Credential) error { 291 f.MethodCall(f, "AddCredential", tag, credential) 292 return f.NextErr() 293 } 294 295 type fakeRoot struct { 296 base.APICaller 297 jujutesting.Stub 298 } 299 300 func (f *fakeRoot) Close() error { 301 f.MethodCall(f, "Close") 302 return f.NextErr() 303 }