github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/cloudcredentials_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/errors" 11 "github.com/juju/loggo" 12 "github.com/juju/names/v5" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/cloud" 17 "github.com/juju/juju/core/status" 18 "github.com/juju/juju/state" 19 statetesting "github.com/juju/juju/state/testing" 20 "github.com/juju/juju/testing/factory" 21 ) 22 23 type CloudCredentialsSuite struct { 24 ConnSuite 25 } 26 27 var _ = gc.Suite(&CloudCredentialsSuite{}) 28 29 func (s *CloudCredentialsSuite) TestUpdateCloudCredentialNew(c *gc.C) { 30 err := s.State.AddCloud(cloud.Cloud{ 31 Name: "stratus", 32 Type: "low", 33 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 34 }, s.Owner.Name()) 35 c.Assert(err, jc.ErrorIsNil) 36 37 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 38 "foo": "foo val", 39 "bar": "bar val", 40 }) 41 tag := names.NewCloudCredentialTag("stratus/bob/foobar") 42 err = s.State.UpdateCloudCredential(tag, cred) 43 c.Assert(err, jc.ErrorIsNil) 44 45 out, err := s.State.CloudCredential(tag) 46 c.Assert(err, jc.ErrorIsNil) 47 48 expected := statetesting.CloudCredential(cloud.AccessKeyAuthType, 49 map[string]string{"bar": "bar val", "foo": "foo val"}, 50 ) 51 expected.DocID = "stratus#bob#foobar" 52 expected.Owner = "bob" 53 expected.Cloud = "stratus" 54 expected.Name = "foobar" 55 c.Assert(out, jc.DeepEquals, expected) 56 } 57 58 func (s *CloudCredentialsSuite) TestCreateInvalidCredential(c *gc.C) { 59 err := s.State.AddCloud(cloud.Cloud{ 60 Name: "stratus", 61 Type: "low", 62 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 63 }, s.Owner.Name()) 64 c.Assert(err, jc.ErrorIsNil) 65 66 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 67 "foo": "foo val", 68 "bar": "bar val", 69 }) 70 // Setting of these properties should have no effect when creating a new credential. 71 cred.Invalid = true 72 cred.InvalidReason = "because am testing you" 73 tag := names.NewCloudCredentialTag("stratus/bob/foobar") 74 err = s.State.UpdateCloudCredential(tag, cred) 75 c.Assert(err, gc.ErrorMatches, "creating cloud credential: adding invalid credential not supported") 76 } 77 78 func (s *CloudCredentialsSuite) TestUpdateCloudCredentialsExisting(c *gc.C) { 79 err := s.State.AddCloud(cloud.Cloud{ 80 Name: "stratus", 81 Type: "low", 82 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 83 }, s.Owner.Name()) 84 c.Assert(err, jc.ErrorIsNil) 85 86 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 87 "foo": "foo val", 88 "bar": "bar val", 89 }) 90 tag := names.NewCloudCredentialTag("stratus/bob/foobar") 91 err = s.State.UpdateCloudCredential(tag, cred) 92 c.Assert(err, jc.ErrorIsNil) 93 94 cred = cloud.NewCredential(cloud.UserPassAuthType, map[string]string{ 95 "user": "bob's nephew", 96 "password": "simple", 97 }) 98 cred.Revoked = true 99 err = s.State.UpdateCloudCredential(tag, cred) 100 c.Assert(err, jc.ErrorIsNil) 101 102 out, err := s.State.CloudCredential(tag) 103 c.Assert(err, jc.ErrorIsNil) 104 105 expected := statetesting.CloudCredential(cloud.UserPassAuthType, map[string]string{ 106 "user": "bob's nephew", 107 "password": "simple", 108 }) 109 expected.DocID = "stratus#bob#foobar" 110 expected.Owner = "bob" 111 expected.Cloud = "stratus" 112 expected.Name = "foobar" 113 expected.Revoked = true 114 115 c.Assert(out, jc.DeepEquals, expected) 116 } 117 118 func assertCredentialCreated(c *gc.C, testSuite ConnSuite) (string, *state.User, names.CloudCredentialTag) { 119 owner := testSuite.Factory.MakeUser(c, &factory.UserParams{ 120 Password: "secret", 121 Name: "bob", 122 }) 123 124 cloudName := "stratus" 125 err := testSuite.State.AddCloud(cloud.Cloud{ 126 Name: cloudName, 127 Type: "low", 128 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 129 Regions: []cloud.Region{{Name: "dummy-region", Endpoint: "endpoint"}}, 130 }, owner.Name()) 131 c.Assert(err, jc.ErrorIsNil) 132 133 tag := createCredential(c, testSuite, cloudName, owner.Name(), "foobar") 134 return cloudName, owner, tag 135 } 136 137 func createCredential(c *gc.C, testSuite ConnSuite, cloudName, userName, credentialName string) names.CloudCredentialTag { 138 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 139 "foo": "foo val", 140 "bar": "bar val", 141 }) 142 tag := names.NewCloudCredentialTag(fmt.Sprintf("%v/%v/%v", cloudName, userName, credentialName)) 143 err := testSuite.State.UpdateCloudCredential(tag, cred) 144 c.Assert(err, jc.ErrorIsNil) 145 return tag 146 } 147 148 func assertModelCreated(c *gc.C, testSuite ConnSuite, cloudName string, credentialTag names.CloudCredentialTag, owner names.Tag, modelName string) string { 149 // Test model needs to be on the test cloud for all validation to pass. 150 modelState := testSuite.Factory.MakeModel(c, &factory.ModelParams{ 151 Name: modelName, 152 CloudCredential: credentialTag, 153 Owner: owner, 154 CloudName: cloudName, 155 }) 156 defer modelState.Close() 157 testModel, err := modelState.Model() 158 c.Assert(err, jc.ErrorIsNil) 159 assertModelStatus(c, testSuite.StatePool, testModel.UUID(), status.Available) 160 return testModel.UUID() 161 } 162 163 func assertModelSuspended(c *gc.C, testSuite ConnSuite) (names.CloudCredentialTag, string) { 164 // 1. Create a credential 165 cloudName, credentialOwner, credentialTag := assertCredentialCreated(c, testSuite) 166 167 // 2. Create model on the test cloud with test credential 168 modelUUID := assertModelCreated(c, testSuite, cloudName, credentialTag, credentialOwner.Tag(), "model-for-cloud") 169 170 // 3. update credential to be invalid and check model is suspended 171 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 172 "foo": "foo val", 173 "bar": "bar val", 174 }) 175 cred.Invalid = true 176 cred.InvalidReason = "because it is really really invalid" 177 err := testSuite.State.UpdateCloudCredential(credentialTag, cred) 178 c.Assert(err, jc.ErrorIsNil) 179 assertModelStatus(c, testSuite.StatePool, modelUUID, status.Suspended) 180 181 return credentialTag, modelUUID 182 } 183 184 func assertModelStatus(c *gc.C, pool *state.StatePool, testModelUUID string, expectedStatus status.Status) { 185 aModel, helper, err := pool.GetModel(testModelUUID) 186 c.Assert(err, jc.ErrorIsNil) 187 defer helper.Release() 188 modelStatus, err := aModel.Status() 189 c.Assert(err, jc.ErrorIsNil) 190 c.Assert(modelStatus.Status, gc.DeepEquals, expectedStatus) 191 } 192 193 func (s *CloudCredentialsSuite) TestUpdateCloudCredentialsTouchesCredentialModels(c *gc.C) { 194 // This test checks that models are affected when their credential validity is changed... 195 // 1. create a credential 196 // 2. set a model to use it 197 // 3. update credential to be invalid and check model is suspended 198 // 4. update credential bar its validity, check no changes in model state 199 // 5. mark credential as valid and check that model is unsuspended 200 201 // 1.2.3. 202 tag, testModelUUID := assertModelSuspended(c, s.ConnSuite) 203 204 // 4. 205 storedCred, err := s.State.CloudCredential(tag) 206 c.Assert(err, jc.ErrorIsNil) 207 c.Assert(storedCred.IsValid(), jc.IsFalse) 208 209 cred := cloud.NewCredential(cloud.UserPassAuthType, map[string]string{ 210 "user": "bob's nephew", 211 "password": "simple", 212 }) 213 cred.Revoked = true 214 // all other credential attributes remain unchanged 215 cred.Invalid = storedCred.Invalid 216 cred.InvalidReason = storedCred.InvalidReason 217 218 err = s.State.UpdateCloudCredential(tag, cred) 219 c.Assert(err, jc.ErrorIsNil) 220 assertModelStatus(c, s.StatePool, testModelUUID, status.Suspended) 221 222 // 5. 223 cred.Invalid = !storedCred.Invalid 224 cred.InvalidReason = "" 225 err = s.State.UpdateCloudCredential(tag, cred) 226 c.Assert(err, jc.ErrorIsNil) 227 assertModelStatus(c, s.StatePool, testModelUUID, status.Available) 228 } 229 230 func (s *CloudCredentialsSuite) TestRemoveModelsCredential(c *gc.C) { 231 cloudName, credentialOwner, credentialTag := assertCredentialCreated(c, s.ConnSuite) 232 modelUUID := assertModelCreated(c, s.ConnSuite, cloudName, credentialTag, credentialOwner.Tag(), "model-for-cloud") 233 234 err := s.State.RemoveModelsCredential(credentialTag) 235 c.Assert(err, jc.ErrorIsNil) 236 237 aModel, helper, err := s.StatePool.GetModel(modelUUID) 238 c.Assert(err, jc.ErrorIsNil) 239 defer helper.Release() 240 _, isSet := aModel.CloudCredentialTag() 241 c.Assert(isSet, jc.IsFalse) 242 _, isSet, err = aModel.CloudCredential() 243 c.Assert(err, jc.ErrorIsNil) 244 c.Assert(isSet, jc.IsFalse) 245 } 246 247 func (s *CloudCredentialsSuite) TestRemoveModelsCredentialConcurrentModelDelete(c *gc.C) { 248 logger := loggo.GetLogger("juju.state") 249 logger.SetLogLevel(loggo.TRACE) 250 cloudName, credentialOwner, credentialTag := assertCredentialCreated(c, s.ConnSuite) 251 modelUUID := assertModelCreated(c, s.ConnSuite, cloudName, credentialTag, credentialOwner.Tag(), "model-for-cloud") 252 253 deleteModel := func() { 254 aModel, helper, err := s.StatePool.GetModel(modelUUID) 255 c.Assert(err, jc.ErrorIsNil) 256 defer helper.Release() 257 err = aModel.SetDead() 258 c.Assert(err, jc.ErrorIsNil) 259 c.Assert(aModel.Refresh(), jc.ErrorIsNil) 260 c.Assert(aModel.Life(), gc.Equals, state.Dead) 261 } 262 defer state.SetBeforeHooks(c, s.State, deleteModel).Check() 263 264 err := s.State.RemoveModelsCredential(credentialTag) 265 c.Assert(err, jc.ErrorIsNil) 266 267 aModel, helper, err := s.StatePool.GetModel(modelUUID) 268 c.Assert(err, jc.ErrorIsNil) 269 defer helper.Release() 270 _, isSet := aModel.CloudCredentialTag() 271 // Since the model was marked 'dead' in the middle of 1st transaction attempt, 272 // and 2nd attempt would not have picked it up, the model credential would not actually be cleared. 273 c.Assert(isSet, jc.IsTrue) 274 _, isSet, err = aModel.CloudCredential() 275 c.Assert(err, jc.ErrorIsNil) 276 c.Assert(isSet, jc.IsTrue) 277 c.Assert(c.GetTestLog(), jc.Contains, "creating operations to remove models credential, attempt 1") 278 } 279 280 func (s *CloudCredentialsSuite) TestRemoveModelsCredentialNotUsed(c *gc.C) { 281 _, _, credentialTag := assertCredentialCreated(c, s.ConnSuite) 282 err := s.State.RemoveModelsCredential(credentialTag) 283 c.Assert(err, jc.ErrorIsNil) 284 } 285 286 func (s *CloudCredentialsSuite) assertCredentialInvalidated(c *gc.C, tag names.CloudCredentialTag) { 287 err := s.State.AddCloud(cloud.Cloud{ 288 Name: "stratus", 289 Type: "low", 290 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 291 }, s.Owner.Name()) 292 c.Assert(err, jc.ErrorIsNil) 293 294 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 295 "foo": "foo val", 296 "bar": "bar val", 297 }) 298 err = s.State.UpdateCloudCredential(tag, cred) 299 c.Assert(err, jc.ErrorIsNil) 300 301 cred = cloud.NewCredential(cloud.UserPassAuthType, map[string]string{ 302 "user": "bob's nephew", 303 "password": "simple", 304 }) 305 cred.Invalid = true 306 cred.InvalidReason = "because it is really really invalid" 307 err = s.State.UpdateCloudCredential(tag, cred) 308 c.Assert(err, jc.ErrorIsNil) 309 310 out, err := s.State.CloudCredential(tag) 311 c.Assert(err, jc.ErrorIsNil) 312 313 expected := statetesting.CloudCredential(cloud.UserPassAuthType, map[string]string{ 314 "user": "bob's nephew", 315 "password": "simple", 316 }) 317 expected.DocID = strings.Replace(tag.Id(), "/", "#", -1) 318 expected.Owner = tag.Owner().Id() 319 expected.Cloud = tag.Cloud().Id() 320 expected.Name = tag.Name() 321 expected.Invalid = true 322 expected.InvalidReason = "because it is really really invalid" 323 324 c.Assert(out, jc.DeepEquals, expected) 325 } 326 327 func (s *CloudCredentialsSuite) TestInvalidateCredential(c *gc.C) { 328 s.assertCredentialInvalidated(c, names.NewCloudCredentialTag("stratus/bob/foobar")) 329 } 330 331 func (s *CloudCredentialsSuite) assertCredentialMarkedValid(c *gc.C, tag names.CloudCredentialTag, credential cloud.Credential) { 332 err := s.State.UpdateCloudCredential(tag, credential) 333 c.Assert(err, jc.ErrorIsNil) 334 335 out, err := s.State.CloudCredential(tag) 336 c.Assert(err, jc.ErrorIsNil) 337 c.Assert(out.IsValid(), jc.IsTrue) 338 } 339 340 func (s *CloudCredentialsSuite) TestMarkInvalidCredentialAsValidExplicitly(c *gc.C) { 341 tag := names.NewCloudCredentialTag("stratus/bob/foobar") 342 // This call will ensure that there is an invalid credential to test with. 343 s.assertCredentialInvalidated(c, tag) 344 345 cred := cloud.NewCredential(cloud.UserPassAuthType, map[string]string{ 346 "user": "bob's nephew", 347 "password": "simple", 348 }) 349 cred.Invalid = false 350 s.assertCredentialMarkedValid(c, tag, cred) 351 } 352 353 func (s *CloudCredentialsSuite) TestMarkInvalidCredentialAsValidImplicitly(c *gc.C) { 354 tag := names.NewCloudCredentialTag("stratus/bob/foobar") 355 // This call will ensure that there is an invalid credential to test with. 356 s.assertCredentialInvalidated(c, tag) 357 358 cred := cloud.NewCredential(cloud.UserPassAuthType, map[string]string{ 359 "user": "bob's nephew", 360 "password": "simple", 361 }) 362 s.assertCredentialMarkedValid(c, tag, cred) 363 } 364 365 func (s *CloudCredentialsSuite) TestUpdateCloudCredentialInvalidAuthType(c *gc.C) { 366 err := s.State.AddCloud(cloud.Cloud{ 367 Name: "stratus", 368 Type: "low", 369 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType}, 370 }, s.Owner.Name()) 371 c.Assert(err, jc.ErrorIsNil) 372 tag := names.NewCloudCredentialTag("stratus/bob/foobar") 373 cred := cloud.NewCredential(cloud.UserPassAuthType, nil) 374 err = s.State.UpdateCloudCredential(tag, cred) 375 c.Assert(err, gc.ErrorMatches, `updating cloud credentials: validating credential "stratus/bob/foobar" for cloud "stratus": supported auth-types \["access-key"\], "userpass" not supported`) 376 } 377 378 func (s *CloudCredentialsSuite) TestCloudCredentialsEmpty(c *gc.C) { 379 creds, err := s.State.CloudCredentials(names.NewUserTag("bob"), "dummy") 380 c.Assert(err, jc.ErrorIsNil) 381 c.Assert(creds, gc.HasLen, 0) 382 } 383 384 func (s *CloudCredentialsSuite) TestCloudCredentials(c *gc.C) { 385 err := s.State.AddCloud(cloud.Cloud{ 386 Name: "stratus", 387 Type: "low", 388 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 389 }, s.Owner.Name()) 390 c.Assert(err, jc.ErrorIsNil) 391 otherUser := s.Factory.MakeUser(c, nil).UserTag() 392 393 tag1 := names.NewCloudCredentialTag("stratus/bob/bobcred1") 394 cred1 := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 395 "foo": "foo val", 396 "bar": "bar val", 397 }) 398 err = s.State.UpdateCloudCredential(tag1, cred1) 399 c.Assert(err, jc.ErrorIsNil) 400 401 tag2 := names.NewCloudCredentialTag("stratus/" + otherUser.Id() + "/foobar") 402 tag3 := names.NewCloudCredentialTag("stratus/bob/bobcred2") 403 cred2 := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 404 "baz": "baz val", 405 "qux": "qux val", 406 }) 407 err = s.State.UpdateCloudCredential(tag2, cred2) 408 c.Assert(err, jc.ErrorIsNil) 409 err = s.State.UpdateCloudCredential(tag3, cred2) 410 c.Assert(err, jc.ErrorIsNil) 411 412 cred1.Label = "bobcred1" 413 cred2.Label = "bobcred2" 414 415 expected1 := statetesting.CloudCredential(cloud.AccessKeyAuthType, map[string]string{ 416 "foo": "foo val", 417 "bar": "bar val", 418 }) 419 expected1.DocID = "stratus#bob#bobcred1" 420 expected1.Owner = "bob" 421 expected1.Cloud = "stratus" 422 expected1.Name = "bobcred1" 423 424 expected2 := statetesting.CloudCredential(cloud.AccessKeyAuthType, map[string]string{ 425 "baz": "baz val", 426 "qux": "qux val", 427 }) 428 expected2.DocID = "stratus#bob#bobcred2" 429 expected2.Owner = "bob" 430 expected2.Cloud = "stratus" 431 expected2.Name = "bobcred2" 432 433 for _, userName := range []string{"bob", "bob"} { 434 creds, err := s.State.CloudCredentials(names.NewUserTag(userName), "stratus") 435 c.Assert(err, jc.ErrorIsNil) 436 c.Assert(creds, jc.DeepEquals, map[string]state.Credential{ 437 tag1.Id(): expected1, 438 tag3.Id(): expected2, 439 }) 440 } 441 } 442 443 func (s *CloudCredentialsSuite) TestRemoveCredentials(c *gc.C) { 444 // Create it. 445 err := s.State.AddCloud(cloud.Cloud{ 446 Name: "stratus", 447 Type: "low", 448 AuthTypes: cloud.AuthTypes{cloud.AccessKeyAuthType, cloud.UserPassAuthType}, 449 }, s.Owner.Name()) 450 c.Assert(err, jc.ErrorIsNil) 451 452 tag := names.NewCloudCredentialTag("stratus/bob/bobcred1") 453 cred := cloud.NewCredential(cloud.AccessKeyAuthType, map[string]string{ 454 "foo": "foo val", 455 "bar": "bar val", 456 }) 457 err = s.State.UpdateCloudCredential(tag, cred) 458 c.Assert(err, jc.ErrorIsNil) 459 _, err = s.State.CloudCredential(tag) 460 c.Assert(err, jc.ErrorIsNil) 461 462 // Remove it. 463 err = s.State.RemoveCloudCredential(tag) 464 c.Assert(err, jc.ErrorIsNil) 465 466 // Check it. 467 _, err = s.State.CloudCredential(tag) 468 c.Assert(err, jc.Satisfies, errors.IsNotFound) 469 } 470 471 func (s *CloudCredentialsSuite) createCredentialWatcher(c *gc.C, st *state.State, cred names.CloudCredentialTag) ( 472 state.NotifyWatcher, statetesting.NotifyWatcherC, 473 ) { 474 w := st.WatchCredential(cred) 475 s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) }) 476 return w, statetesting.NewNotifyWatcherC(c, w) 477 } 478 479 func (s *CloudCredentialsSuite) TestWatchCredential(c *gc.C) { 480 cred := names.NewCloudCredentialTag("dummy/fred/default") 481 w, wc := s.createCredentialWatcher(c, s.State, cred) 482 wc.AssertOneChange() // Initial event. 483 484 // Create 485 dummyCred := cloud.NewCredential(cloud.EmptyAuthType, nil) 486 err := s.State.UpdateCloudCredential(cred, dummyCred) 487 c.Assert(err, jc.ErrorIsNil) 488 wc.AssertOneChange() 489 490 // Revoke 491 dummyCred.Revoked = true 492 err = s.State.UpdateCloudCredential(cred, dummyCred) 493 c.Assert(err, jc.ErrorIsNil) 494 wc.AssertOneChange() 495 496 // Remove. 497 err = s.State.RemoveCloudCredential(cred) 498 c.Assert(err, jc.ErrorIsNil) 499 wc.AssertOneChange() 500 501 statetesting.AssertStop(c, w) 502 wc.AssertClosed() 503 } 504 505 func (s *CloudCredentialsSuite) TestWatchCredentialIgnoresOther(c *gc.C) { 506 cred := names.NewCloudCredentialTag("dummy/fred/default") 507 w, wc := s.createCredentialWatcher(c, s.State, cred) 508 wc.AssertOneChange() // Initial event. 509 510 anotherCred := names.NewCloudCredentialTag("dummy/mary/default") 511 dummyCred := cloud.NewCredential(cloud.EmptyAuthType, nil) 512 err := s.State.UpdateCloudCredential(anotherCred, dummyCred) 513 c.Assert(err, jc.ErrorIsNil) 514 wc.AssertNoChange() 515 516 statetesting.AssertStop(c, w) 517 wc.AssertClosed() 518 } 519 520 func (s *CloudCredentialsSuite) createCloudCredential(c *gc.C, cloudName, userName, credentialName string) (names.CloudCredentialTag, state.Credential) { 521 authType := cloud.AccessKeyAuthType 522 attributes := map[string]string{ 523 "foo": "foo val", 524 "bar": "bar val", 525 } 526 527 err := s.State.AddCloud(cloud.Cloud{ 528 Name: cloudName, 529 Type: "low", 530 AuthTypes: cloud.AuthTypes{authType, cloud.UserPassAuthType}, 531 }, s.Owner.Name()) 532 c.Assert(err, jc.ErrorIsNil) 533 534 cred := cloud.NewCredential(authType, attributes) 535 536 // Cloud credential tag to use when looking up this credential. 537 tag := names.NewCloudCredentialTag(fmt.Sprintf("%s/%s/%s", cloudName, userName, credentialName)) 538 err = s.State.UpdateCloudCredential(tag, cred) 539 c.Assert(err, jc.ErrorIsNil) 540 541 // Credential data as stored in state. 542 expected := state.Credential{} 543 expected.DocID = fmt.Sprintf("%s#%s#%s", cloudName, userName, credentialName) 544 expected.Owner = userName 545 expected.Cloud = cloudName 546 expected.Name = credentialName 547 expected.AuthType = string(authType) 548 expected.Attributes = attributes 549 550 return tag, expected 551 } 552 553 func (s *CloudCredentialsSuite) TestAllCloudCredentialsNotFound(c *gc.C) { 554 out, err := s.State.AllCloudCredentials(names.NewUserTag("bob")) 555 c.Assert(err, gc.ErrorMatches, "cloud credentials for \"bob\" not found") 556 c.Assert(out, gc.IsNil) 557 } 558 559 func (s *CloudCredentialsSuite) TestAllCloudCredentials(c *gc.C) { 560 _, one := s.createCloudCredential(c, "cirrus", "bob", "foobar") 561 _, two := s.createCloudCredential(c, "stratus", "bob", "foobar") 562 563 // Added to make sure it is not returned. 564 s.createCloudCredential(c, "cumulus", "mary", "foobar") 565 566 out, err := s.State.AllCloudCredentials(names.NewUserTag("bob")) 567 c.Assert(err, jc.ErrorIsNil) 568 c.Assert(out, jc.DeepEquals, []state.Credential{one, two}) 569 } 570 571 func (s *CloudCredentialsSuite) TestInvalidateCloudCredential(c *gc.C) { 572 oneTag, one := s.createCloudCredential(c, "cirrus", "bob", "foobar") 573 c.Assert(one.IsValid(), jc.IsTrue) 574 575 reason := "testing, testing 1,2,3" 576 err := s.State.InvalidateCloudCredential(oneTag, reason) 577 c.Assert(err, jc.ErrorIsNil) 578 579 updated, err := s.State.CloudCredential(oneTag) 580 c.Assert(err, jc.ErrorIsNil) 581 c.Assert(updated.IsValid(), jc.IsFalse) 582 c.Assert(updated.InvalidReason, gc.DeepEquals, reason) 583 } 584 585 func (s *CloudCredentialsSuite) TestInvalidateCloudCredentialNotFound(c *gc.C) { 586 tag := names.NewCloudCredentialTag("cloud/user/credential") 587 err := s.State.InvalidateCloudCredential(tag, "just does not matter") 588 c.Assert(err, jc.Satisfies, errors.IsNotFound) 589 }