github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/secrets_test.go (about) 1 // Copyright 2021 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "sort" 9 "time" 10 11 "github.com/juju/charm/v12" 12 "github.com/juju/collections/set" 13 "github.com/juju/errors" 14 "github.com/juju/names/v5" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/utils/v3" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/core/secrets" 20 "github.com/juju/juju/core/watcher" 21 "github.com/juju/juju/provider/dummy" 22 "github.com/juju/juju/state" 23 "github.com/juju/juju/state/testing" 24 "github.com/juju/juju/storage" 25 "github.com/juju/juju/storage/provider" 26 jujutesting "github.com/juju/juju/testing" 27 "github.com/juju/juju/testing/factory" 28 ) 29 30 type SecretsSuite struct { 31 testing.StateSuite 32 store state.SecretsStore 33 owner *state.Application 34 ownerUnit *state.Unit 35 relation *state.Relation 36 } 37 38 var _ = gc.Suite(&SecretsSuite{}) 39 40 func (s *SecretsSuite) SetUpTest(c *gc.C) { 41 s.StateSuite.SetUpTest(c) 42 s.store = state.NewSecrets(s.State) 43 s.owner = s.Factory.MakeApplication(c, nil) 44 s.ownerUnit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.owner}) 45 app2 := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 46 Name: "wordpress", 47 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}), 48 }) 49 ep1, err := s.owner.Endpoint("server") 50 c.Assert(err, jc.ErrorIsNil) 51 ep2, err := app2.Endpoint("db") 52 c.Assert(err, jc.ErrorIsNil) 53 s.relation = s.Factory.MakeRelation(c, &factory.RelationParams{ 54 Endpoints: []state.Endpoint{ep1, ep2}, 55 }) 56 } 57 58 func ptr[T any](v T) *T { 59 return &v 60 } 61 62 func (s *SecretsSuite) TestCreate(c *gc.C) { 63 uri := secrets.NewURI() 64 now := s.Clock.Now().Round(time.Second).UTC() 65 next := now.Add(time.Minute).Round(time.Second).UTC() 66 expire := now.Add(time.Hour).Round(time.Second).UTC() 67 p := state.CreateSecretParams{ 68 Version: 1, 69 Owner: s.owner.Tag(), 70 UpdateSecretParams: state.UpdateSecretParams{ 71 LeaderToken: &fakeToken{}, 72 RotatePolicy: ptr(secrets.RotateDaily), 73 NextRotateTime: ptr(next), 74 Description: ptr("my secret"), 75 Label: ptr("foobar"), 76 ExpireTime: ptr(expire), 77 Params: nil, 78 Data: map[string]string{"foo": "bar"}, 79 }, 80 } 81 md, err := s.store.CreateSecret(uri, p) 82 c.Assert(err, jc.ErrorIsNil) 83 mc := jc.NewMultiChecker() 84 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 85 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 86 c.Assert(md, mc, &secrets.SecretMetadata{ 87 URI: uri, 88 Version: 1, 89 Description: "my secret", 90 Label: "foobar", 91 RotatePolicy: secrets.RotateDaily, 92 NextRotateTime: ptr(next), 93 LatestRevision: 1, 94 LatestExpireTime: ptr(expire), 95 OwnerTag: s.owner.Tag().String(), 96 CreateTime: now, 97 UpdateTime: now, 98 }) 99 100 p.Label = nil 101 _, err = s.store.CreateSecret(uri, p) 102 c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) 103 } 104 105 func (s *SecretsSuite) TestCreateUserSecret(c *gc.C) { 106 uri := secrets.NewURI() 107 now := s.Clock.Now().Round(time.Second).UTC() 108 p := state.CreateSecretParams{ 109 Version: 1, 110 Owner: s.Model.Tag(), 111 UpdateSecretParams: state.UpdateSecretParams{ 112 LeaderToken: &fakeToken{}, 113 Description: ptr("my secret"), 114 Label: ptr("label-1"), 115 Params: nil, 116 Data: map[string]string{"foo": "bar"}, 117 }, 118 } 119 md, err := s.store.CreateSecret(uri, p) 120 c.Assert(err, jc.ErrorIsNil) 121 mc := jc.NewMultiChecker() 122 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 123 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 124 c.Assert(md, mc, &secrets.SecretMetadata{ 125 URI: uri, 126 Version: 1, 127 Description: "my secret", 128 Label: "label-1", 129 LatestRevision: 1, 130 OwnerTag: s.Model.Tag().String(), 131 CreateTime: now, 132 UpdateTime: now, 133 }) 134 135 uri2 := secrets.NewURI() 136 _, err = s.store.CreateSecret(uri2, p) 137 c.Assert(err, gc.ErrorMatches, fmt.Sprintf(`user secret label "label-1" already exists`)) 138 } 139 140 func (s *SecretsSuite) TestCreateBackendRef(c *gc.C) { 141 backendStore := state.NewSecretBackends(s.State) 142 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 143 ID: "backend-id", 144 Name: "foo", 145 BackendType: "vault", 146 }) 147 c.Assert(err, jc.ErrorIsNil) 148 backendRefCount, err := s.State.ReadBackendRefCount("backend-id") 149 c.Assert(err, jc.ErrorIsNil) 150 c.Assert(backendRefCount, gc.Equals, 0) 151 152 uri := secrets.NewURI() 153 p := state.CreateSecretParams{ 154 Version: 1, 155 Owner: s.owner.Tag(), 156 UpdateSecretParams: state.UpdateSecretParams{ 157 LeaderToken: &fakeToken{}, 158 ValueRef: &secrets.ValueRef{ 159 BackendID: "backend-id", 160 RevisionID: "rev-id", 161 }, 162 }, 163 } 164 _, err = s.store.CreateSecret(uri, p) 165 c.Assert(err, jc.ErrorIsNil) 166 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 167 c.Assert(err, jc.ErrorIsNil) 168 c.Assert(backendRefCount, gc.Equals, 1) 169 v, valueRef, err := s.store.GetSecretValue(uri, 1) 170 c.Assert(err, jc.ErrorIsNil) 171 c.Assert(v.EncodedValues(), gc.HasLen, 0) 172 c.Assert(valueRef, gc.NotNil) 173 c.Assert(*valueRef, jc.DeepEquals, secrets.ValueRef{ 174 BackendID: "backend-id", 175 RevisionID: "rev-id", 176 }) 177 } 178 179 func (s *SecretsSuite) TestCreateDuplicateLabelApplicationOwned(c *gc.C) { 180 uri := secrets.NewURI() 181 now := s.Clock.Now().Round(time.Second).UTC() 182 next := now.Add(time.Minute).Round(time.Second).UTC() 183 expire := now.Add(time.Hour).Round(time.Second).UTC() 184 p := state.CreateSecretParams{ 185 Version: 1, 186 Owner: s.owner.Tag(), 187 UpdateSecretParams: state.UpdateSecretParams{ 188 LeaderToken: &fakeToken{}, 189 RotatePolicy: ptr(secrets.RotateDaily), 190 NextRotateTime: ptr(next), 191 Description: ptr("my secret"), 192 Label: ptr("foobar"), 193 ExpireTime: ptr(expire), 194 Params: nil, 195 Data: map[string]string{"foo": "bar"}, 196 }, 197 } 198 md, err := s.store.CreateSecret(uri, p) 199 c.Assert(err, jc.ErrorIsNil) 200 uri2 := secrets.NewURI() 201 _, err = s.store.CreateSecret(uri2, p) 202 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 203 204 // Existing application owner label should not be used for owner label for its units. 205 uri3 := secrets.NewURI() 206 p.Owner = s.ownerUnit.Tag() 207 _, err = s.store.CreateSecret(uri3, p) 208 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 209 210 // Existing application owner label should not be used for consumer label for its units. 211 cmd := &secrets.SecretConsumerMetadata{ 212 Label: "foobar", 213 CurrentRevision: md.LatestRevision, 214 } 215 err = s.State.SaveSecretConsumer(uri, s.ownerUnit.Tag(), cmd) 216 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 217 } 218 219 func (s *SecretsSuite) TestCreateDuplicateLabelUnitOwned(c *gc.C) { 220 uri := secrets.NewURI() 221 now := s.Clock.Now().Round(time.Second).UTC() 222 next := now.Add(time.Minute).Round(time.Second).UTC() 223 expire := now.Add(time.Hour).Round(time.Second).UTC() 224 p := state.CreateSecretParams{ 225 Version: 1, 226 Owner: s.ownerUnit.Tag(), 227 UpdateSecretParams: state.UpdateSecretParams{ 228 LeaderToken: &fakeToken{}, 229 RotatePolicy: ptr(secrets.RotateDaily), 230 NextRotateTime: ptr(next), 231 Description: ptr("my secret"), 232 Label: ptr("foobar"), 233 ExpireTime: ptr(expire), 234 Params: nil, 235 Data: map[string]string{"foo": "bar"}, 236 }, 237 } 238 md, err := s.store.CreateSecret(uri, p) 239 c.Assert(err, jc.ErrorIsNil) 240 uri2 := secrets.NewURI() 241 _, err = s.store.CreateSecret(uri2, p) 242 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 243 244 // Existing unit owner label should not be used for owner label for the application. 245 uri3 := secrets.NewURI() 246 p.Owner = s.owner.Tag() 247 _, err = s.store.CreateSecret(uri3, p) 248 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 249 250 // Existing unit owner label should not be used for consumer label for the application. 251 cmd := &secrets.SecretConsumerMetadata{ 252 Label: "foobar", 253 CurrentRevision: md.LatestRevision, 254 } 255 err = s.State.SaveSecretConsumer(uri, s.owner.Tag(), cmd) 256 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 257 } 258 259 func (s *SecretsSuite) TestCreateDuplicateLabelUnitConsumed(c *gc.C) { 260 uri := secrets.NewURI() 261 p := state.CreateSecretParams{ 262 Version: 1, 263 Owner: names.NewApplicationTag("wordpress"), 264 UpdateSecretParams: state.UpdateSecretParams{ 265 LeaderToken: &fakeToken{}, 266 Params: nil, 267 Data: map[string]string{"foo": "bar"}, 268 }, 269 } 270 md, err := s.store.CreateSecret(uri, p) 271 c.Assert(err, jc.ErrorIsNil) 272 273 cmd := &secrets.SecretConsumerMetadata{ 274 Label: "foobar", 275 CurrentRevision: md.LatestRevision, 276 } 277 err = s.State.SaveSecretConsumer(uri, s.ownerUnit.Tag(), cmd) 278 c.Assert(err, jc.ErrorIsNil) 279 280 // Existing unit consumer label should not be used for owner label. 281 uri2 := secrets.NewURI() 282 p.Owner = s.ownerUnit.Tag() 283 p.Label = ptr("foobar") 284 _, err = s.store.CreateSecret(uri2, p) 285 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 286 287 // Existing unit consumer label should not be used for owner label for the application. 288 uri3 := secrets.NewURI() 289 p.Owner = s.owner.Tag() 290 p.Label = ptr("foobar") 291 _, err = s.store.CreateSecret(uri3, p) 292 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 293 294 // Existing unit consumer label should not be used for consumer label for the application. 295 cmd = &secrets.SecretConsumerMetadata{ 296 Label: "foobar", 297 CurrentRevision: md.LatestRevision, 298 } 299 err = s.State.SaveSecretConsumer(uri, s.owner.Tag(), cmd) 300 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 301 } 302 303 func (s *SecretsSuite) TestCreateDyingOwner(c *gc.C) { 304 err := s.owner.Destroy() 305 c.Assert(err, jc.ErrorIsNil) 306 307 uri := secrets.NewURI() 308 cp := state.CreateSecretParams{ 309 Version: 1, 310 Owner: s.owner.Tag(), 311 UpdateSecretParams: state.UpdateSecretParams{ 312 LeaderToken: &fakeToken{}, 313 Data: map[string]string{"foo": "bar"}, 314 }, 315 } 316 _, err = s.store.CreateSecret(uri, cp) 317 c.Assert(err, gc.ErrorMatches, `cannot create secret for owner "application-mysql" which is not alive`) 318 } 319 320 func (s *SecretsSuite) TestGetValueNotFound(c *gc.C) { 321 uri, _ := secrets.ParseURI("secret:9m4e2mr0ui3e8a215n4g") 322 _, _, err := s.store.GetSecretValue(uri, 666) 323 c.Assert(err, jc.Satisfies, errors.IsNotFound) 324 } 325 326 func (s *SecretsSuite) TestGetValue(c *gc.C) { 327 uri := secrets.NewURI() 328 p := state.CreateSecretParams{ 329 Version: 1, 330 Owner: s.owner.Tag(), 331 UpdateSecretParams: state.UpdateSecretParams{ 332 LeaderToken: &fakeToken{}, 333 Data: map[string]string{"foo": "bar"}, 334 }, 335 } 336 md, err := s.store.CreateSecret(uri, p) 337 c.Assert(err, jc.ErrorIsNil) 338 339 val, backendId, err := s.store.GetSecretValue(md.URI, 1) 340 c.Assert(err, jc.ErrorIsNil) 341 c.Assert(backendId, gc.IsNil) 342 c.Assert(val.EncodedValues(), jc.DeepEquals, map[string]string{ 343 "foo": "bar", 344 }) 345 } 346 347 func (s *SecretsSuite) TestListByOwner(c *gc.C) { 348 uri := secrets.NewURI() 349 now := s.Clock.Now().Round(time.Second).UTC() 350 next := now.Add(time.Minute).Round(time.Second).UTC() 351 expire := now.Add(time.Hour).Round(time.Second).UTC() 352 p := state.CreateSecretParams{ 353 Version: 1, 354 Owner: s.owner.Tag(), 355 UpdateSecretParams: state.UpdateSecretParams{ 356 LeaderToken: &fakeToken{}, 357 RotatePolicy: ptr(secrets.RotateDaily), 358 NextRotateTime: ptr(next), 359 Description: ptr("my secret"), 360 Label: ptr("foobar"), 361 ExpireTime: ptr(expire), 362 Params: nil, 363 Data: map[string]string{"foo": "bar"}, 364 }, 365 } 366 _, err := s.store.CreateSecret(uri, p) 367 c.Assert(err, jc.ErrorIsNil) 368 369 another := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 370 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{Name: "mariadb"}), 371 }) 372 now2 := s.Clock.Now().Round(time.Second).UTC() 373 uri2 := secrets.NewURI() 374 p2 := state.CreateSecretParams{ 375 Version: 1, 376 Owner: another.Tag(), 377 UpdateSecretParams: state.UpdateSecretParams{ 378 LeaderToken: &fakeToken{}, 379 Data: map[string]string{"foo": "bar"}, 380 }, 381 } 382 _, err = s.store.CreateSecret(uri2, p2) 383 c.Assert(err, jc.ErrorIsNil) 384 385 // Create another secret to ensure it is excluded. 386 uri3 := secrets.NewURI() 387 p.Owner = names.NewApplicationTag("wordpress") 388 _, err = s.store.CreateSecret(uri3, p) 389 c.Assert(err, jc.ErrorIsNil) 390 391 expectedList := []*secrets.SecretMetadata{{ 392 URI: uri, 393 RotatePolicy: secrets.RotateDaily, 394 NextRotateTime: ptr(next), 395 LatestRevision: 1, 396 LatestExpireTime: ptr(expire), 397 Version: 1, 398 OwnerTag: s.owner.Tag().String(), 399 Description: "my secret", 400 Label: "foobar", 401 CreateTime: now, 402 UpdateTime: now, 403 }, { 404 URI: uri2, 405 LatestRevision: 1, 406 Version: 1, 407 OwnerTag: another.Tag().String(), 408 CreateTime: now2, 409 UpdateTime: now2, 410 }} 411 list, err := s.store.ListSecrets(state.SecretsFilter{ 412 OwnerTags: []names.Tag{s.owner.Tag(), names.NewApplicationTag("mariadb")}, 413 }) 414 c.Assert(err, jc.ErrorIsNil) 415 416 mc := jc.NewMultiChecker() 417 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 418 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 419 420 sortMD := func(l []*secrets.SecretMetadata) { 421 sort.Slice(l, func(i, j int) bool { 422 return l[i].URI.String() < l[j].URI.String() 423 }) 424 } 425 sortMD(list) 426 sortMD(expectedList) 427 c.Assert(list, mc, expectedList) 428 } 429 430 func (s *SecretsSuite) TestListByURI(c *gc.C) { 431 uri := secrets.NewURI() 432 now := s.Clock.Now().Round(time.Second).UTC() 433 next := now.Add(time.Minute).Round(time.Second).UTC() 434 expire := now.Add(time.Hour).Round(time.Second).UTC() 435 p := state.CreateSecretParams{ 436 Version: 1, 437 Owner: s.owner.Tag(), 438 UpdateSecretParams: state.UpdateSecretParams{ 439 LeaderToken: &fakeToken{}, 440 RotatePolicy: ptr(secrets.RotateDaily), 441 NextRotateTime: ptr(next), 442 Description: ptr("my secret"), 443 Label: ptr("foobar"), 444 ExpireTime: ptr(expire), 445 Params: nil, 446 Data: map[string]string{"foo": "bar"}, 447 }, 448 } 449 _, err := s.store.CreateSecret(uri, p) 450 c.Assert(err, jc.ErrorIsNil) 451 452 // Create another secret to ensure it is excluded. 453 uri2 := secrets.NewURI() 454 p.Owner = names.NewApplicationTag("wordpress") 455 _, err = s.store.CreateSecret(uri2, p) 456 c.Assert(err, jc.ErrorIsNil) 457 458 list, err := s.store.ListSecrets(state.SecretsFilter{ 459 URI: uri, 460 }) 461 c.Assert(err, jc.ErrorIsNil) 462 mc := jc.NewMultiChecker() 463 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 464 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 465 c.Assert(list, mc, []*secrets.SecretMetadata{{ 466 URI: uri, 467 RotatePolicy: secrets.RotateDaily, 468 NextRotateTime: ptr(next), 469 LatestRevision: 1, 470 LatestExpireTime: ptr(expire), 471 Version: 1, 472 OwnerTag: s.owner.Tag().String(), 473 Description: "my secret", 474 Label: "foobar", 475 CreateTime: now, 476 UpdateTime: now, 477 }}) 478 } 479 480 func (s *SecretsSuite) TestListByLabel(c *gc.C) { 481 uri := secrets.NewURI() 482 now := s.Clock.Now().Round(time.Second).UTC() 483 next := now.Add(time.Minute).Round(time.Second).UTC() 484 expire := now.Add(time.Hour).Round(time.Second).UTC() 485 p := state.CreateSecretParams{ 486 Version: 1, 487 Owner: s.owner.Tag(), 488 UpdateSecretParams: state.UpdateSecretParams{ 489 LeaderToken: &fakeToken{}, 490 RotatePolicy: ptr(secrets.RotateDaily), 491 NextRotateTime: ptr(next), 492 Description: ptr("my secret"), 493 Label: ptr("foobar"), 494 ExpireTime: ptr(expire), 495 Params: nil, 496 Data: map[string]string{"foo": "bar"}, 497 }, 498 } 499 _, err := s.store.CreateSecret(uri, p) 500 c.Assert(err, jc.ErrorIsNil) 501 502 // Create another secret to ensure it is excluded. 503 uri2 := secrets.NewURI() 504 p.Label = ptr("another") 505 _, err = s.store.CreateSecret(uri2, p) 506 c.Assert(err, jc.ErrorIsNil) 507 508 list, err := s.store.ListSecrets(state.SecretsFilter{ 509 Label: ptr("foobar"), 510 }) 511 c.Assert(err, jc.ErrorIsNil) 512 mc := jc.NewMultiChecker() 513 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 514 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 515 c.Assert(list, mc, []*secrets.SecretMetadata{{ 516 URI: uri, 517 RotatePolicy: secrets.RotateDaily, 518 NextRotateTime: ptr(next), 519 LatestRevision: 1, 520 LatestExpireTime: ptr(expire), 521 Version: 1, 522 OwnerTag: s.owner.Tag().String(), 523 Description: "my secret", 524 Label: "foobar", 525 CreateTime: now, 526 UpdateTime: now, 527 }}) 528 } 529 530 func (s *SecretsSuite) TestListByConsumer(c *gc.C) { 531 uri := secrets.NewURI() 532 now := s.Clock.Now().Round(time.Second).UTC() 533 subject := names.NewApplicationTag("wordpress") 534 535 cp := state.CreateSecretParams{ 536 Version: 1, 537 Owner: s.owner.Tag(), 538 UpdateSecretParams: state.UpdateSecretParams{ 539 LeaderToken: &fakeToken{}, 540 Description: ptr("my secret"), 541 Data: map[string]string{"foo": "bar"}, 542 }, 543 } 544 _, err := s.store.CreateSecret(uri, cp) 545 c.Assert(err, jc.ErrorIsNil) 546 547 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 548 LeaderToken: &fakeToken{}, 549 Scope: s.relation.Tag(), 550 Subject: subject, 551 Role: secrets.RoleView, 552 }) 553 c.Assert(err, jc.ErrorIsNil) 554 555 // Create another secret to ensure it is excluded. 556 uri2 := secrets.NewURI() 557 cp.Owner = names.NewApplicationTag("wordpress") 558 _, err = s.store.CreateSecret(uri2, cp) 559 c.Assert(err, jc.ErrorIsNil) 560 561 list, err := s.store.ListSecrets(state.SecretsFilter{ 562 ConsumerTags: []names.Tag{subject}, 563 }) 564 c.Assert(err, jc.ErrorIsNil) 565 mc := jc.NewMultiChecker() 566 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 567 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 568 c.Assert(list, mc, []*secrets.SecretMetadata{{ 569 URI: uri, 570 LatestRevision: 1, 571 Version: 1, 572 OwnerTag: s.owner.Tag().String(), 573 Description: "my secret", 574 CreateTime: now, 575 UpdateTime: now, 576 }}) 577 } 578 579 func (s *SecretsSuite) TestListModelSecrets(c *gc.C) { 580 backendStore := state.NewSecretBackends(s.State) 581 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 582 ID: "backend-id", 583 Name: "foo", 584 BackendType: "vault", 585 }) 586 c.Assert(err, jc.ErrorIsNil) 587 backendRefCount, err := s.State.ReadBackendRefCount("backend-id") 588 c.Assert(err, jc.ErrorIsNil) 589 c.Assert(backendRefCount, gc.Equals, 0) 590 591 uri := secrets.NewURI() 592 p := state.CreateSecretParams{ 593 Version: 1, 594 Owner: s.owner.Tag(), 595 UpdateSecretParams: state.UpdateSecretParams{ 596 LeaderToken: &fakeToken{}, 597 Data: map[string]string{"foo": "bar"}, 598 }, 599 } 600 _, err = s.store.CreateSecret(uri, p) 601 c.Assert(err, jc.ErrorIsNil) 602 603 uri2 := secrets.NewURI() 604 p2 := state.CreateSecretParams{ 605 Version: 1, 606 Owner: s.owner.Tag(), 607 UpdateSecretParams: state.UpdateSecretParams{ 608 LeaderToken: &fakeToken{}, 609 ValueRef: &secrets.ValueRef{BackendID: "backend-id"}, 610 }, 611 } 612 _, err = s.store.CreateSecret(uri2, p2) 613 c.Assert(err, jc.ErrorIsNil) 614 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 615 c.Assert(err, jc.ErrorIsNil) 616 c.Assert(backendRefCount, gc.Equals, 1) 617 618 caasSt := s.newCAASState(c) 619 caasSecrets := state.NewSecrets(caasSt) 620 uri3 := secrets.NewURI() 621 p3 := state.CreateSecretParams{ 622 Version: 1, 623 Owner: names.NewApplicationTag("wordpress"), 624 UpdateSecretParams: state.UpdateSecretParams{ 625 LeaderToken: &fakeToken{}, 626 ValueRef: &secrets.ValueRef{BackendID: caasSt.ModelUUID()}, 627 }, 628 } 629 _, err = caasSecrets.CreateSecret(uri3, p3) 630 c.Assert(err, jc.ErrorIsNil) 631 632 result, err := s.store.ListModelSecrets(true) 633 c.Assert(err, jc.ErrorIsNil) 634 c.Assert(result, jc.DeepEquals, map[string]set.Strings{ 635 s.State.ControllerUUID(): set.NewStrings(uri.ID), 636 "backend-id": set.NewStrings(uri2.ID), 637 caasSt.ModelUUID(): set.NewStrings(uri3.ID), 638 }) 639 640 result, err = s.store.ListModelSecrets(false) 641 c.Assert(err, jc.ErrorIsNil) 642 c.Assert(result, jc.DeepEquals, map[string]set.Strings{ 643 s.State.ControllerUUID(): set.NewStrings(uri.ID), 644 "backend-id": set.NewStrings(uri2.ID), 645 }) 646 } 647 648 func (s *SecretsSuite) newCAASState(c *gc.C) *state.State { 649 cfg := jujutesting.CustomModelConfig(c, jujutesting.Attrs{ 650 "name": "caasmodel", 651 "uuid": utils.MustNewUUID().String(), 652 }) 653 _, st, err := s.Controller.NewModel(state.ModelArgs{ 654 Type: state.ModelTypeCAAS, 655 CloudName: "dummy", 656 CloudRegion: "dummy-region", 657 Config: cfg, 658 Owner: s.Owner, 659 StorageProviderRegistry: storage.ChainedProviderRegistry{ 660 dummy.StorageProviders(), 661 provider.CommonStorageProviders(), 662 }, 663 }) 664 c.Assert(err, jc.ErrorIsNil) 665 s.AddCleanup(func(*gc.C) { st.Close() }) 666 s.Factory = factory.NewFactory(st, s.StatePool) 667 s.Factory.MakeApplication(c, &factory.ApplicationParams{ 668 Name: "wordpress", 669 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}), 670 }) 671 return st 672 } 673 674 func (s *SecretsSuite) TestUpdateNothing(c *gc.C) { 675 up := state.UpdateSecretParams{} 676 uri := secrets.NewURI() 677 _, err := s.store.UpdateSecret(uri, up) 678 c.Assert(err, gc.ErrorMatches, "must specify a new value or metadata to update a secret") 679 } 680 681 func (s *SecretsSuite) TestUpdateAll(c *gc.C) { 682 uri := secrets.NewURI() 683 now := s.Clock.Now().Round(time.Second).UTC() 684 next := now.Add(time.Minute).Round(time.Second).UTC() 685 cp := state.CreateSecretParams{ 686 Version: 1, 687 Owner: s.owner.Tag(), 688 UpdateSecretParams: state.UpdateSecretParams{ 689 LeaderToken: &fakeToken{}, 690 RotatePolicy: ptr(secrets.RotateDaily), 691 NextRotateTime: ptr(next), 692 Description: ptr("my secret"), 693 Label: ptr("foobar"), 694 Data: map[string]string{"foo": "bar"}, 695 }, 696 } 697 md, err := s.store.CreateSecret(uri, cp) 698 c.Assert(err, jc.ErrorIsNil) 699 newData := map[string]string{"foo": "bar", "hello": "world"} 700 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 701 LeaderToken: &fakeToken{}, 702 Description: ptr("big secret"), 703 Label: ptr("new label"), 704 RotatePolicy: ptr(secrets.RotateHourly), 705 NextRotateTime: ptr(next), 706 Data: newData, 707 }) 708 } 709 710 func (s *SecretsSuite) TestUpdateRotateInterval(c *gc.C) { 711 uri := secrets.NewURI() 712 now := s.Clock.Now().Round(time.Second).UTC() 713 next := now.Add(time.Minute).Round(time.Second).UTC() 714 cp := state.CreateSecretParams{ 715 Version: 1, 716 Owner: s.owner.Tag(), 717 UpdateSecretParams: state.UpdateSecretParams{ 718 LeaderToken: &fakeToken{}, 719 RotatePolicy: ptr(secrets.RotateDaily), 720 NextRotateTime: ptr(next), 721 Data: map[string]string{"foo": "bar"}, 722 }, 723 } 724 md, err := s.store.CreateSecret(uri, cp) 725 c.Assert(err, jc.ErrorIsNil) 726 s.assertUpdatedSecret(c, md, 1, state.UpdateSecretParams{ 727 LeaderToken: &fakeToken{}, 728 RotatePolicy: ptr(secrets.RotateHourly), 729 NextRotateTime: ptr(next), 730 }) 731 } 732 733 func (s *SecretsSuite) TestUpdateExpiry(c *gc.C) { 734 uri := secrets.NewURI() 735 now := s.Clock.Now().Round(time.Second).UTC() 736 next := now.Add(time.Minute).Round(time.Second).UTC() 737 cp := state.CreateSecretParams{ 738 Version: 1, 739 Owner: s.owner.Tag(), 740 UpdateSecretParams: state.UpdateSecretParams{ 741 LeaderToken: &fakeToken{}, 742 RotatePolicy: ptr(secrets.RotateDaily), 743 NextRotateTime: ptr(next), 744 Data: map[string]string{"foo": "bar"}, 745 }, 746 } 747 md, err := s.store.CreateSecret(uri, cp) 748 c.Assert(err, jc.ErrorIsNil) 749 s.assertUpdatedSecret(c, md, 1, state.UpdateSecretParams{ 750 LeaderToken: &fakeToken{}, 751 ExpireTime: ptr(next), 752 }) 753 754 s.assertUpdatedSecret(c, md, 1, state.UpdateSecretParams{ 755 LeaderToken: &fakeToken{}, 756 ExpireTime: ptr(time.Time{}), 757 }) 758 } 759 760 func (s *SecretsSuite) TestUpdateDuplicateLabel(c *gc.C) { 761 uri := secrets.NewURI() 762 cp := state.CreateSecretParams{ 763 Version: 1, 764 Owner: s.owner.Tag(), 765 UpdateSecretParams: state.UpdateSecretParams{ 766 LeaderToken: &fakeToken{}, 767 Label: ptr("label"), 768 Description: ptr("description"), 769 Data: map[string]string{"foo": "bar"}, 770 }, 771 } 772 _, err := s.store.CreateSecret(uri, cp) 773 c.Assert(err, jc.ErrorIsNil) 774 uri2 := secrets.NewURI() 775 cp.Label = ptr("label2") 776 _, err = s.store.CreateSecret(uri2, cp) 777 c.Assert(err, jc.ErrorIsNil) 778 _, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 779 LeaderToken: &fakeToken{}, 780 Label: ptr("label2"), 781 }) 782 c.Assert(errors.Is(err, state.LabelExists), jc.IsTrue) 783 784 _, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 785 LeaderToken: &fakeToken{}, 786 Label: ptr("label"), 787 }) 788 c.Assert(err, jc.ErrorIsNil) 789 } 790 791 func (s *SecretsSuite) TestUpdateData(c *gc.C) { 792 uri := secrets.NewURI() 793 now := s.Clock.Now().Round(time.Second).UTC() 794 next := now.Add(time.Minute).Round(time.Second).UTC() 795 cp := state.CreateSecretParams{ 796 Version: 1, 797 Owner: s.owner.Tag(), 798 UpdateSecretParams: state.UpdateSecretParams{ 799 LeaderToken: &fakeToken{}, 800 RotatePolicy: ptr(secrets.RotateDaily), 801 NextRotateTime: ptr(next), 802 Data: map[string]string{"foo": "bar"}, 803 }, 804 } 805 md, err := s.store.CreateSecret(uri, cp) 806 c.Assert(err, jc.ErrorIsNil) 807 newData := map[string]string{"foo": "bar", "hello": "world"} 808 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 809 LeaderToken: &fakeToken{}, 810 Data: newData, 811 }) 812 } 813 814 func (s *SecretsSuite) TestUpdateAutoPrune(c *gc.C) { 815 uri := secrets.NewURI() 816 now := s.Clock.Now().Round(time.Second).UTC() 817 next := now.Add(time.Minute).Round(time.Second).UTC() 818 cp := state.CreateSecretParams{ 819 Version: 1, 820 Owner: s.owner.Tag(), 821 UpdateSecretParams: state.UpdateSecretParams{ 822 LeaderToken: &fakeToken{}, 823 RotatePolicy: ptr(secrets.RotateDaily), 824 NextRotateTime: ptr(next), 825 Data: map[string]string{"foo": "bar"}, 826 }, 827 } 828 md, err := s.store.CreateSecret(uri, cp) 829 c.Assert(err, jc.ErrorIsNil) 830 c.Assert(md.AutoPrune, jc.IsFalse) 831 c.Assert(md.LatestRevision, gc.Equals, 1) 832 s.assertUpdatedSecret( 833 c, md, 834 1, // Update AutoPrune should not increment the revision. 835 state.UpdateSecretParams{ 836 LeaderToken: &fakeToken{}, 837 AutoPrune: ptr(true), 838 }, 839 ) 840 } 841 842 func (s *SecretsSuite) TestUpdateDataSetsLatestConsumerRevision(c *gc.C) { 843 uri := secrets.NewURI() 844 now := s.Clock.Now().Round(time.Second).UTC() 845 next := now.Add(time.Minute).Round(time.Second).UTC() 846 cp := state.CreateSecretParams{ 847 Version: 1, 848 Owner: s.owner.Tag(), 849 UpdateSecretParams: state.UpdateSecretParams{ 850 LeaderToken: &fakeToken{}, 851 RotatePolicy: ptr(secrets.RotateDaily), 852 NextRotateTime: ptr(next), 853 Data: map[string]string{"foo": "bar"}, 854 }, 855 } 856 md, err := s.store.CreateSecret(uri, cp) 857 c.Assert(err, jc.ErrorIsNil) 858 cmd := &secrets.SecretConsumerMetadata{ 859 Label: "foobar", 860 CurrentRevision: 1, 861 } 862 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 863 c.Assert(err, jc.ErrorIsNil) 864 newData := map[string]string{"foo": "bar", "hello": "world"} 865 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 866 LeaderToken: &fakeToken{}, 867 Data: newData, 868 }) 869 cmd, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 870 c.Assert(err, jc.ErrorIsNil) 871 c.Assert(cmd, jc.DeepEquals, &secrets.SecretConsumerMetadata{ 872 Label: "foobar", 873 CurrentRevision: 1, 874 LatestRevision: 2, 875 }) 876 } 877 878 func (s *SecretsSuite) TestUpdateOwnerLabel(c *gc.C) { 879 uri := secrets.NewURI() 880 now := s.Clock.Now().Round(time.Second).UTC() 881 next := now.Add(time.Minute).Round(time.Second).UTC() 882 cp := state.CreateSecretParams{ 883 Version: 1, 884 Owner: s.owner.Tag(), 885 UpdateSecretParams: state.UpdateSecretParams{ 886 LeaderToken: &fakeToken{}, 887 RotatePolicy: ptr(secrets.RotateDaily), 888 NextRotateTime: ptr(next), 889 Data: map[string]string{"foo": "bar"}, 890 }, 891 } 892 md, err := s.store.CreateSecret(uri, cp) 893 c.Assert(err, jc.ErrorIsNil) 894 s.assertUpdatedSecret(c, md, 1, state.UpdateSecretParams{ 895 LeaderToken: &fakeToken{}, 896 Label: ptr("foobar2"), 897 }) 898 // Ensure it can be reset back to an older value. 899 s.assertUpdatedSecret(c, md, 1, state.UpdateSecretParams{ 900 LeaderToken: &fakeToken{}, 901 Label: ptr("foobar"), 902 }) 903 } 904 905 func (s *SecretsSuite) TestUpdateDataSetsLatestConsumerRevisionConcurrentAdd(c *gc.C) { 906 uri := secrets.NewURI() 907 now := s.Clock.Now().Round(time.Second).UTC() 908 cp := state.CreateSecretParams{ 909 Version: 1, 910 Owner: s.owner.Tag(), 911 UpdateSecretParams: state.UpdateSecretParams{ 912 LeaderToken: &fakeToken{}, 913 RotatePolicy: ptr(secrets.RotateDaily), 914 NextRotateTime: ptr(now.Add(time.Minute)), 915 Data: map[string]string{"foo": "bar"}, 916 }, 917 } 918 md, err := s.store.CreateSecret(uri, cp) 919 c.Assert(err, jc.ErrorIsNil) 920 cmd := &secrets.SecretConsumerMetadata{ 921 Label: "foobar", 922 CurrentRevision: 1, 923 } 924 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 925 c.Assert(err, jc.ErrorIsNil) 926 927 state.SetBeforeHooks(c, s.State, func() { 928 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 929 c.Assert(err, jc.ErrorIsNil) 930 }) 931 932 newData := map[string]string{"foo": "bar", "hello": "world"} 933 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 934 LeaderToken: &fakeToken{}, 935 Data: newData, 936 }) 937 cmd, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 938 c.Assert(err, jc.ErrorIsNil) 939 c.Assert(cmd.LatestRevision, gc.Equals, 2) 940 cmd, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 941 c.Assert(err, jc.ErrorIsNil) 942 c.Assert(cmd.LatestRevision, gc.Equals, 2) 943 } 944 945 func (s *SecretsSuite) TestUpdateDataSetsLatestConsumerRevisionConcurrentRemove(c *gc.C) { 946 uri := secrets.NewURI() 947 now := s.Clock.Now().Round(time.Second).UTC() 948 next := now.Add(time.Minute).Round(time.Second).UTC() 949 cp := state.CreateSecretParams{ 950 Version: 1, 951 Owner: s.owner.Tag(), 952 UpdateSecretParams: state.UpdateSecretParams{ 953 LeaderToken: &fakeToken{}, 954 RotatePolicy: ptr(secrets.RotateDaily), 955 NextRotateTime: ptr(next), 956 Data: map[string]string{"foo": "bar"}, 957 }, 958 } 959 md, err := s.store.CreateSecret(uri, cp) 960 c.Assert(err, jc.ErrorIsNil) 961 cmd := &secrets.SecretConsumerMetadata{ 962 Label: "foobar", 963 CurrentRevision: 1, 964 } 965 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 966 c.Assert(err, jc.ErrorIsNil) 967 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mysql/0"), cmd) 968 c.Assert(err, jc.ErrorIsNil) 969 970 state.SetBeforeHooks(c, s.State, func() { 971 consColl, closer := state.GetCollection(s.State, "secretConsumers") 972 defer closer() 973 err := consColl.Writeable().RemoveId(state.DocID(s.State, fmt.Sprintf("%s#unit-mysql-0", uri.ID))) 974 c.Assert(err, jc.ErrorIsNil) 975 976 err = state.IncSecretConsumerRefCount(s.State, uri, 1) 977 c.Assert(err, jc.ErrorIsNil) 978 }) 979 980 newData := map[string]string{"foo": "bar", "hello": "world"} 981 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 982 LeaderToken: &fakeToken{}, 983 Data: newData, 984 }) 985 cmd, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 986 c.Assert(err, jc.ErrorIsNil) 987 c.Assert(cmd.LatestRevision, gc.Equals, 2) 988 _, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mysql/0")) 989 c.Assert(err, jc.Satisfies, errors.IsNotFound) 990 } 991 992 func (s *SecretsSuite) assertUpdatedSecret(c *gc.C, original *secrets.SecretMetadata, expectedRevision int, update state.UpdateSecretParams) { 993 expected := *original 994 expected.LatestRevision = expectedRevision 995 if update.RotatePolicy != nil { 996 expected.RotatePolicy = *update.RotatePolicy 997 expected.NextRotateTime = update.NextRotateTime 998 } 999 if update.Description != nil { 1000 expected.Description = *update.Description 1001 } 1002 if update.AutoPrune != nil { 1003 expected.AutoPrune = *update.AutoPrune 1004 } 1005 if update.Label != nil { 1006 expected.Label = *update.Label 1007 } 1008 if update.ExpireTime != nil && !update.ExpireTime.IsZero() { 1009 expected.LatestExpireTime = update.ExpireTime 1010 } 1011 1012 s.Clock.Advance(time.Hour) 1013 updated := s.Clock.Now().Round(time.Second).UTC() 1014 expected.UpdateTime = updated 1015 md, err := s.store.UpdateSecret(original.URI, update) 1016 c.Assert(err, jc.ErrorIsNil) 1017 1018 list, err := s.store.ListSecrets(state.SecretsFilter{}) 1019 c.Assert(err, jc.ErrorIsNil) 1020 mc := jc.NewMultiChecker() 1021 mc.AddExpr(`(*_[_]).CreateTime`, jc.Almost, jc.ExpectedValue) 1022 mc.AddExpr(`(*_[_]).UpdateTime`, jc.Almost, jc.ExpectedValue) 1023 c.Assert(list, mc, []*secrets.SecretMetadata{&expected}) 1024 expectedData := map[string]string{"foo": "bar"} 1025 if update.Data != nil { 1026 expectedData = update.Data 1027 } 1028 val, valueRef, err := s.store.GetSecretValue(md.URI, expectedRevision) 1029 c.Assert(err, jc.ErrorIsNil) 1030 if update.ValueRef != nil { 1031 c.Assert(valueRef, gc.NotNil) 1032 c.Assert(*update.ValueRef, jc.DeepEquals, *valueRef) 1033 } else { 1034 c.Assert(valueRef, gc.IsNil) 1035 c.Assert(val.EncodedValues(), jc.DeepEquals, expectedData) 1036 } 1037 if update.ExpireTime != nil { 1038 revs, err := s.store.ListSecretRevisions(md.URI) 1039 c.Assert(err, jc.ErrorIsNil) 1040 for _, r := range revs { 1041 if r.ExpireTime == nil && update.ExpireTime.IsZero() { 1042 return 1043 } 1044 if r.ExpireTime != nil && r.ExpireTime.Equal(update.ExpireTime.Round(time.Second).UTC()) { 1045 return 1046 } 1047 } 1048 c.Fatalf("expire time not set for secret revision %d", expectedRevision) 1049 md, err := s.store.GetSecret(original.URI) 1050 c.Assert(err, jc.ErrorIsNil) 1051 if update.ExpireTime.IsZero() { 1052 c.Assert(md.LatestExpireTime, gc.IsNil) 1053 } else { 1054 c.Assert(md.LatestExpireTime, gc.Equals, update.ExpireTime.Round(time.Second).UTC()) 1055 } 1056 } 1057 if update.NextRotateTime != nil { 1058 nextTime := state.GetSecretNextRotateTime(c, s.State, md.URI.ID) 1059 c.Assert(nextTime, gc.Equals, *update.NextRotateTime) 1060 } 1061 } 1062 1063 func (s *SecretsSuite) TestUpdateConcurrent(c *gc.C) { 1064 uri := secrets.NewURI() 1065 1066 now := s.Clock.Now().Round(time.Second).UTC() 1067 next := now.Add(time.Minute).Round(time.Second).UTC() 1068 cp := state.CreateSecretParams{ 1069 Version: 1, 1070 Owner: s.owner.Tag(), 1071 UpdateSecretParams: state.UpdateSecretParams{ 1072 LeaderToken: &fakeToken{}, 1073 RotatePolicy: ptr(secrets.RotateDaily), 1074 NextRotateTime: ptr(next), 1075 Data: map[string]string{"foo": "bar"}, 1076 }, 1077 } 1078 md, err := s.store.CreateSecret(uri, cp) 1079 1080 state.SetBeforeHooks(c, s.State, func() { 1081 up := state.UpdateSecretParams{ 1082 LeaderToken: &fakeToken{}, 1083 RotatePolicy: ptr(secrets.RotateYearly), 1084 NextRotateTime: ptr(next), 1085 Params: nil, 1086 Data: map[string]string{"foo": "baz", "goodbye": "world"}, 1087 } 1088 md, err = s.store.UpdateSecret(md.URI, up) 1089 c.Assert(err, jc.ErrorIsNil) 1090 }) 1091 newData := map[string]string{"foo": "bar", "hello": "world"} 1092 s.assertUpdatedSecret(c, md, 3, state.UpdateSecretParams{ 1093 LeaderToken: &fakeToken{}, 1094 RotatePolicy: ptr(secrets.RotateHourly), 1095 NextRotateTime: ptr(next), 1096 Data: newData, 1097 }) 1098 } 1099 1100 func (s *SecretsSuite) TestChangeSecretBackendExternalToExternal(c *gc.C) { 1101 backendStore := state.NewSecretBackends(s.State) 1102 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1103 ID: "old-backend-id", 1104 Name: "foo", 1105 BackendType: "vault", 1106 }) 1107 c.Assert(err, jc.ErrorIsNil) 1108 backendRefCount, err := s.State.ReadBackendRefCount("old-backend-id") 1109 c.Assert(err, jc.ErrorIsNil) 1110 c.Assert(backendRefCount, gc.Equals, 0) 1111 1112 _, err = backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1113 ID: "new-backend-id", 1114 Name: "bar", 1115 BackendType: "vault", 1116 }) 1117 c.Assert(err, jc.ErrorIsNil) 1118 backendRefCount, err = s.State.ReadBackendRefCount("new-backend-id") 1119 c.Assert(err, jc.ErrorIsNil) 1120 c.Assert(backendRefCount, gc.Equals, 0) 1121 1122 uri := secrets.NewURI() 1123 p := state.CreateSecretParams{ 1124 Version: 1, 1125 Owner: s.owner.Tag(), 1126 UpdateSecretParams: state.UpdateSecretParams{ 1127 LeaderToken: &fakeToken{}, 1128 ValueRef: &secrets.ValueRef{ 1129 BackendID: "old-backend-id", 1130 RevisionID: "rev-id", 1131 }, 1132 }, 1133 } 1134 _, err = s.store.CreateSecret(uri, p) 1135 c.Assert(err, jc.ErrorIsNil) 1136 1137 backendRefCount, err = s.State.ReadBackendRefCount("old-backend-id") 1138 c.Assert(err, jc.ErrorIsNil) 1139 c.Assert(backendRefCount, gc.Equals, 1) 1140 1141 val, valRef, err := s.store.GetSecretValue(uri, 1) 1142 c.Assert(err, jc.ErrorIsNil) 1143 c.Assert(val.IsEmpty(), jc.IsTrue) 1144 c.Assert(valRef, gc.DeepEquals, &secrets.ValueRef{ 1145 BackendID: "old-backend-id", 1146 RevisionID: "rev-id", 1147 }) 1148 1149 err = s.store.ChangeSecretBackend(state.ChangeSecretBackendParams{ 1150 URI: uri, 1151 Token: &fakeToken{}, 1152 Revision: 1, 1153 ValueRef: &secrets.ValueRef{ 1154 BackendID: "new-backend-id", 1155 RevisionID: "rev-id", 1156 }, 1157 }) 1158 c.Assert(err, jc.ErrorIsNil) 1159 1160 backendRefCount, err = s.State.ReadBackendRefCount("old-backend-id") 1161 c.Assert(err, jc.ErrorIsNil) 1162 c.Assert(backendRefCount, gc.Equals, 0) 1163 1164 backendRefCount, err = s.State.ReadBackendRefCount("new-backend-id") 1165 c.Assert(err, jc.ErrorIsNil) 1166 c.Assert(backendRefCount, gc.Equals, 1) 1167 1168 val, valRef, err = s.store.GetSecretValue(uri, 1) 1169 c.Assert(err, jc.ErrorIsNil) 1170 c.Assert(val.IsEmpty(), jc.IsTrue) 1171 c.Assert(valRef, jc.DeepEquals, &secrets.ValueRef{ 1172 BackendID: "new-backend-id", 1173 RevisionID: "rev-id", 1174 }) 1175 } 1176 1177 func (s *SecretsSuite) TestChangeSecretBackendInternalToExternal(c *gc.C) { 1178 backendStore := state.NewSecretBackends(s.State) 1179 1180 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1181 ID: "new-backend-id", 1182 Name: "bar", 1183 BackendType: "vault", 1184 }) 1185 c.Assert(err, jc.ErrorIsNil) 1186 1187 uri := secrets.NewURI() 1188 p := state.CreateSecretParams{ 1189 Version: 1, 1190 Owner: s.owner.Tag(), 1191 UpdateSecretParams: state.UpdateSecretParams{ 1192 LeaderToken: &fakeToken{}, 1193 Data: map[string]string{"foo": "bar"}, 1194 }, 1195 } 1196 _, err = s.store.CreateSecret(uri, p) 1197 c.Assert(err, jc.ErrorIsNil) 1198 1199 _, err = s.State.ReadBackendRefCount(s.Model.UUID()) 1200 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1201 _, err = s.State.ReadBackendRefCount(s.State.ControllerUUID()) 1202 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1203 1204 backendRefCount, err := s.State.ReadBackendRefCount("new-backend-id") 1205 c.Assert(err, jc.ErrorIsNil) 1206 c.Assert(backendRefCount, gc.Equals, 0) 1207 1208 val, valRef, err := s.store.GetSecretValue(uri, 1) 1209 c.Assert(err, jc.ErrorIsNil) 1210 c.Assert(val, jc.DeepEquals, secrets.NewSecretValue(map[string]string{"foo": "bar"})) 1211 c.Assert(valRef, gc.IsNil) 1212 1213 err = s.store.ChangeSecretBackend(state.ChangeSecretBackendParams{ 1214 URI: uri, 1215 Token: &fakeToken{}, 1216 Revision: 1, 1217 ValueRef: &secrets.ValueRef{ 1218 BackendID: "new-backend-id", 1219 RevisionID: "rev-id", 1220 }, 1221 }) 1222 c.Assert(err, jc.ErrorIsNil) 1223 1224 _, err = s.State.ReadBackendRefCount(s.Model.UUID()) 1225 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1226 _, err = s.State.ReadBackendRefCount(s.State.ControllerUUID()) 1227 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1228 1229 backendRefCount, err = s.State.ReadBackendRefCount("new-backend-id") 1230 c.Assert(err, jc.ErrorIsNil) 1231 c.Assert(backendRefCount, gc.Equals, 1) 1232 1233 val, valRef, err = s.store.GetSecretValue(uri, 1) 1234 c.Assert(err, jc.ErrorIsNil) 1235 c.Assert(val.IsEmpty(), jc.IsTrue) 1236 c.Assert(valRef, jc.DeepEquals, &secrets.ValueRef{ 1237 BackendID: "new-backend-id", 1238 RevisionID: "rev-id", 1239 }) 1240 } 1241 1242 func (s *SecretsSuite) TestChangeSecretBackendExternalToInternal(c *gc.C) { 1243 backendStore := state.NewSecretBackends(s.State) 1244 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1245 ID: "backend-id", 1246 Name: "foo", 1247 BackendType: "vault", 1248 }) 1249 c.Assert(err, jc.ErrorIsNil) 1250 backendRefCount, err := s.State.ReadBackendRefCount("backend-id") 1251 c.Assert(err, jc.ErrorIsNil) 1252 c.Assert(backendRefCount, gc.Equals, 0) 1253 1254 uri := secrets.NewURI() 1255 p := state.CreateSecretParams{ 1256 Version: 1, 1257 Owner: s.owner.Tag(), 1258 UpdateSecretParams: state.UpdateSecretParams{ 1259 LeaderToken: &fakeToken{}, 1260 ValueRef: &secrets.ValueRef{ 1261 BackendID: "backend-id", 1262 RevisionID: "rev-id", 1263 }, 1264 }, 1265 } 1266 _, err = s.store.CreateSecret(uri, p) 1267 c.Assert(err, jc.ErrorIsNil) 1268 1269 _, err = s.State.ReadBackendRefCount(s.Model.UUID()) 1270 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1271 _, err = s.State.ReadBackendRefCount(s.State.ControllerUUID()) 1272 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1273 1274 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 1275 c.Assert(err, jc.ErrorIsNil) 1276 c.Assert(backendRefCount, gc.Equals, 1) 1277 1278 val, valRef, err := s.store.GetSecretValue(uri, 1) 1279 c.Assert(err, jc.ErrorIsNil) 1280 c.Assert(val.IsEmpty(), jc.IsTrue) 1281 c.Assert(valRef, gc.DeepEquals, &secrets.ValueRef{ 1282 BackendID: "backend-id", 1283 RevisionID: "rev-id", 1284 }) 1285 1286 err = s.store.ChangeSecretBackend(state.ChangeSecretBackendParams{ 1287 URI: uri, 1288 Token: &fakeToken{}, 1289 Data: map[string]string{"foo": "bar"}, 1290 Revision: 1, 1291 }) 1292 c.Assert(err, jc.ErrorIsNil) 1293 1294 _, err = s.State.ReadBackendRefCount(s.Model.UUID()) 1295 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1296 _, err = s.State.ReadBackendRefCount(s.State.ControllerUUID()) 1297 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1298 1299 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 1300 c.Assert(err, jc.ErrorIsNil) 1301 c.Assert(backendRefCount, gc.Equals, 0) 1302 1303 val, valRef, err = s.store.GetSecretValue(uri, 1) 1304 c.Assert(err, jc.ErrorIsNil) 1305 c.Assert(val, jc.DeepEquals, secrets.NewSecretValue(map[string]string{"foo": "bar"})) 1306 c.Assert(valRef, gc.IsNil) 1307 } 1308 1309 func (s *SecretsSuite) TestSecretGrants(c *gc.C) { 1310 uri := secrets.NewURI() 1311 1312 now := s.Clock.Now().Round(time.Second).UTC() 1313 next := now.Add(time.Minute).Round(time.Second).UTC() 1314 cp := state.CreateSecretParams{ 1315 Version: 1, 1316 Owner: s.owner.Tag(), 1317 UpdateSecretParams: state.UpdateSecretParams{ 1318 Label: strPtr("label-1"), 1319 LeaderToken: &fakeToken{}, 1320 RotatePolicy: ptr(secrets.RotateDaily), 1321 NextRotateTime: ptr(next), 1322 Data: map[string]string{"foo": "bar"}, 1323 }, 1324 } 1325 md, err := s.store.CreateSecret(uri, cp) 1326 c.Check(err, jc.ErrorIsNil) 1327 c.Check(md.URI, jc.DeepEquals, uri) 1328 1329 subject := names.NewApplicationTag("wordpress") 1330 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1331 LeaderToken: &fakeToken{}, 1332 Scope: s.relation.Tag(), 1333 Subject: subject, 1334 Role: secrets.RoleView, 1335 }) 1336 c.Assert(err, jc.ErrorIsNil) 1337 1338 access, err := s.store.SecretGrants(uri, secrets.RoleView) 1339 c.Assert(err, jc.ErrorIsNil) 1340 c.Assert(access, jc.DeepEquals, []secrets.AccessInfo{ 1341 { 1342 Target: subject.String(), 1343 Scope: "relation-wordpress.db#mysql.server", 1344 Role: secrets.RoleView, 1345 }, 1346 }) 1347 } 1348 1349 func (s *SecretsSuite) TestGetSecret(c *gc.C) { 1350 uri := secrets.NewURI() 1351 1352 now := s.Clock.Now().Round(time.Second).UTC() 1353 next := now.Add(time.Minute).Round(time.Second).UTC() 1354 cp := state.CreateSecretParams{ 1355 Version: 1, 1356 Owner: s.owner.Tag(), 1357 UpdateSecretParams: state.UpdateSecretParams{ 1358 Label: strPtr("label-1"), 1359 LeaderToken: &fakeToken{}, 1360 RotatePolicy: ptr(secrets.RotateDaily), 1361 NextRotateTime: ptr(next), 1362 Data: map[string]string{"foo": "bar"}, 1363 }, 1364 } 1365 md, err := s.store.CreateSecret(uri, cp) 1366 c.Check(err, jc.ErrorIsNil) 1367 c.Check(md.URI, jc.DeepEquals, uri) 1368 1369 md, err = s.store.GetSecret(uri) 1370 c.Check(err, jc.ErrorIsNil) 1371 c.Check(md.URI, jc.DeepEquals, uri) 1372 } 1373 1374 func (s *SecretsSuite) TestListSecretRevisions(c *gc.C) { 1375 uri := secrets.NewURI() 1376 now := s.Clock.Now().Round(time.Second).UTC() 1377 next := now.Add(time.Minute).Round(time.Second).UTC() 1378 cp := state.CreateSecretParams{ 1379 Version: 1, 1380 Owner: s.owner.Tag(), 1381 UpdateSecretParams: state.UpdateSecretParams{ 1382 LeaderToken: &fakeToken{}, 1383 RotatePolicy: ptr(secrets.RotateDaily), 1384 NextRotateTime: ptr(next), 1385 Data: map[string]string{"foo": "bar"}, 1386 }, 1387 } 1388 md, err := s.store.CreateSecret(uri, cp) 1389 c.Assert(err, jc.ErrorIsNil) 1390 newData := map[string]string{"foo": "bar", "hello": "world"} 1391 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 1392 LeaderToken: &fakeToken{}, 1393 Data: newData, 1394 }) 1395 1396 backendStore := state.NewSecretBackends(s.State) 1397 backendID, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1398 Name: "myvault", 1399 BackendType: "vault", 1400 }) 1401 c.Assert(err, jc.ErrorIsNil) 1402 updateTime := s.Clock.Now().Round(time.Second).UTC() 1403 s.assertUpdatedSecret(c, md, 3, state.UpdateSecretParams{ 1404 LeaderToken: &fakeToken{}, 1405 ValueRef: &secrets.ValueRef{ 1406 BackendID: backendID, 1407 RevisionID: "rev-id", 1408 }, 1409 }) 1410 updateTime2 := s.Clock.Now().Round(time.Second).UTC() 1411 r, err := s.store.ListSecretRevisions(uri) 1412 c.Assert(err, jc.ErrorIsNil) 1413 1414 mc := jc.NewMultiChecker() 1415 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 1416 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 1417 c.Assert(r, mc, []*secrets.SecretRevisionMetadata{{ 1418 Revision: 1, 1419 CreateTime: now, 1420 UpdateTime: now, 1421 }, { 1422 Revision: 2, 1423 CreateTime: updateTime, 1424 UpdateTime: updateTime, 1425 }, { 1426 Revision: 3, 1427 ValueRef: &secrets.ValueRef{ 1428 BackendID: backendID, 1429 RevisionID: "rev-id", 1430 }, 1431 BackendName: ptr("myvault"), 1432 CreateTime: updateTime2, 1433 UpdateTime: updateTime2, 1434 }}) 1435 } 1436 1437 func (s *SecretsSuite) TestListUnusedSecretRevisions(c *gc.C) { 1438 uri := secrets.NewURI() 1439 now := s.Clock.Now().Round(time.Second).UTC() 1440 next := now.Add(time.Minute).Round(time.Second).UTC() 1441 cp := state.CreateSecretParams{ 1442 Version: 1, 1443 Owner: s.owner.Tag(), 1444 UpdateSecretParams: state.UpdateSecretParams{ 1445 LeaderToken: &fakeToken{}, 1446 RotatePolicy: ptr(secrets.RotateDaily), 1447 NextRotateTime: ptr(next), 1448 Data: map[string]string{"foo": "bar"}, 1449 }, 1450 } 1451 md, err := s.store.CreateSecret(uri, cp) 1452 c.Assert(err, jc.ErrorIsNil) 1453 newData := map[string]string{"foo": "bar", "hello": "world"} 1454 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 1455 LeaderToken: &fakeToken{}, 1456 Data: newData, 1457 }) 1458 1459 backendStore := state.NewSecretBackends(s.State) 1460 backendID, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1461 Name: "myvault", 1462 BackendType: "vault", 1463 }) 1464 c.Assert(err, jc.ErrorIsNil) 1465 s.assertUpdatedSecret(c, md, 3, state.UpdateSecretParams{ 1466 LeaderToken: &fakeToken{}, 1467 ValueRef: &secrets.ValueRef{ 1468 BackendID: backendID, 1469 RevisionID: "rev-id", 1470 }, 1471 }) 1472 r, err := s.store.ListUnusedSecretRevisions(uri) 1473 c.Assert(err, jc.ErrorIsNil) 1474 1475 mc := jc.NewMultiChecker() 1476 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 1477 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 1478 c.Assert(r, mc, []int{ 1479 1, 2, 1480 // The latest revision `3` is still in use, so it's not returned. 1481 }) 1482 } 1483 1484 func (s *SecretsSuite) TestGetSecretRevision(c *gc.C) { 1485 uri := secrets.NewURI() 1486 cp := state.CreateSecretParams{ 1487 Version: 1, 1488 Owner: s.owner.Tag(), 1489 UpdateSecretParams: state.UpdateSecretParams{ 1490 LeaderToken: &fakeToken{}, 1491 Data: map[string]string{"foo": "bar"}, 1492 }, 1493 } 1494 md, err := s.store.CreateSecret(uri, cp) 1495 c.Assert(err, jc.ErrorIsNil) 1496 newData := map[string]string{"foo": "bar", "hello": "world"} 1497 s.assertUpdatedSecret(c, md, 2, state.UpdateSecretParams{ 1498 LeaderToken: &fakeToken{}, 1499 Data: newData, 1500 }) 1501 r, err := s.store.GetSecretRevision(uri, 2) 1502 c.Assert(err, jc.ErrorIsNil) 1503 updateTime := s.Clock.Now().Round(time.Second).UTC() 1504 mc := jc.NewMultiChecker() 1505 mc.AddExpr(`_.CreateTime`, jc.Almost, jc.ExpectedValue) 1506 mc.AddExpr(`_.UpdateTime`, jc.Almost, jc.ExpectedValue) 1507 c.Assert(r, mc, &secrets.SecretRevisionMetadata{ 1508 Revision: 2, 1509 CreateTime: updateTime, 1510 UpdateTime: updateTime, 1511 }) 1512 } 1513 1514 func (s *SecretsSuite) TestGetSecretConsumerAndGetSecretConsumerURI(c *gc.C) { 1515 cp := state.CreateSecretParams{ 1516 Version: 1, 1517 Owner: s.owner.Tag(), 1518 UpdateSecretParams: state.UpdateSecretParams{ 1519 LeaderToken: &fakeToken{}, 1520 Data: map[string]string{"foo": "bar"}, 1521 Label: strPtr("owner-label"), 1522 }, 1523 } 1524 uri := secrets.NewURI() 1525 _, err := s.store.CreateSecret(uri, cp) 1526 c.Assert(err, jc.ErrorIsNil) 1527 1528 _, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1529 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1530 md := &secrets.SecretConsumerMetadata{ 1531 Label: "consumer-label", 1532 CurrentRevision: 666, 1533 } 1534 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), md) 1535 c.Assert(err, jc.ErrorIsNil) 1536 1537 _, err = s.State.GetSecretConsumer(nil, names.NewUnitTag("mariadb/0")) 1538 c.Check(err, gc.ErrorMatches, `empty URI`) 1539 1540 md2, err := s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1541 c.Check(err, jc.ErrorIsNil) 1542 c.Check(md2, jc.DeepEquals, md) 1543 1544 uri3, err := s.State.GetURIByConsumerLabel("consumer-label", names.NewUnitTag("mariadb/0")) 1545 c.Check(err, jc.ErrorIsNil) 1546 c.Check(uri3, jc.DeepEquals, uri) 1547 1548 _, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mysql/0")) 1549 c.Check(err, jc.Satisfies, errors.IsNotFound) 1550 } 1551 1552 func (s *SecretsSuite) TestGetSecretConsumerCrossModelURI(c *gc.C) { 1553 cp := state.CreateSecretParams{ 1554 Version: 1, 1555 Owner: s.owner.Tag(), 1556 UpdateSecretParams: state.UpdateSecretParams{ 1557 LeaderToken: &fakeToken{}, 1558 Data: map[string]string{"foo": "bar"}, 1559 Label: strPtr("owner-label"), 1560 }, 1561 } 1562 uri := secrets.NewURI().WithSource("deadbeef-1bad-500d-9000-4b1d0d06f00d") 1563 _, err := s.store.CreateSecret(uri, cp) 1564 c.Assert(err, jc.ErrorIsNil) 1565 1566 _, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1567 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1568 md := &secrets.SecretConsumerMetadata{ 1569 Label: "consumer-label", 1570 CurrentRevision: 666, 1571 } 1572 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), md) 1573 c.Assert(err, jc.ErrorIsNil) 1574 1575 _, err = s.State.GetSecretConsumer(nil, names.NewUnitTag("mariadb/0")) 1576 c.Check(err, gc.ErrorMatches, `empty URI`) 1577 1578 md2, err := s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1579 c.Check(err, jc.ErrorIsNil) 1580 c.Check(md2, jc.DeepEquals, md) 1581 1582 uri3, err := s.State.GetURIByConsumerLabel("consumer-label", names.NewUnitTag("mariadb/0")) 1583 c.Check(err, jc.ErrorIsNil) 1584 c.Check(uri3, jc.DeepEquals, uri) 1585 } 1586 1587 func (s *SecretsSuite) TestSaveSecretConsumer(c *gc.C) { 1588 cp := state.CreateSecretParams{ 1589 Version: 1, 1590 Owner: s.owner.Tag(), 1591 UpdateSecretParams: state.UpdateSecretParams{ 1592 LeaderToken: &fakeToken{}, 1593 Data: map[string]string{"foo": "bar"}, 1594 }, 1595 } 1596 uri := secrets.NewURI() 1597 md, err := s.store.CreateSecret(uri, cp) 1598 c.Assert(err, jc.ErrorIsNil) 1599 c.Assert(md.LatestRevision, gc.Equals, 1) 1600 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 1), jc.IsFalse) 1601 1602 cmd := &secrets.SecretConsumerMetadata{ 1603 Label: "foobar", 1604 CurrentRevision: md.LatestRevision, 1605 LatestRevision: md.LatestRevision, 1606 } 1607 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 1608 c.Assert(err, jc.ErrorIsNil) 1609 md2, err := s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1610 c.Assert(err, jc.ErrorIsNil) 1611 c.Assert(md2, jc.DeepEquals, cmd) 1612 c.Assert(md2.LatestRevision, gc.Equals, 1) 1613 c.Assert(md2.CurrentRevision, gc.Equals, 1) 1614 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 1), jc.IsFalse) 1615 1616 // secret revison ++, but not obsolete. 1617 md, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 1618 LeaderToken: &fakeToken{}, 1619 Data: map[string]string{"foo": "bar", "baz": "qux"}, 1620 }) 1621 c.Assert(err, jc.ErrorIsNil) 1622 c.Assert(md.LatestRevision, gc.Equals, 2) 1623 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 1), jc.IsFalse) 1624 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 2), jc.IsFalse) 1625 1626 // consumer latest revison ++, but not obsolete. 1627 cmd.LatestRevision = md.LatestRevision 1628 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 1629 c.Assert(err, jc.ErrorIsNil) 1630 md2, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1631 c.Assert(err, jc.ErrorIsNil) 1632 c.Assert(md2, jc.DeepEquals, cmd) 1633 c.Assert(md2.LatestRevision, gc.Equals, 2) 1634 c.Assert(md2.CurrentRevision, gc.Equals, 1) 1635 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 1), jc.IsFalse) 1636 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 2), jc.IsFalse) 1637 1638 // consumer current revison ++, then obsolete. 1639 cmd.CurrentRevision = md.LatestRevision 1640 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 1641 c.Assert(err, jc.ErrorIsNil) 1642 md2, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1643 c.Assert(err, jc.ErrorIsNil) 1644 c.Assert(md2, jc.DeepEquals, cmd) 1645 c.Assert(md2.LatestRevision, gc.Equals, 2) 1646 c.Assert(md2.CurrentRevision, gc.Equals, 2) 1647 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 1), jc.IsTrue) 1648 c.Assert(s.State.IsSecretRevisionObsolete(c, uri, 2), jc.IsFalse) 1649 } 1650 1651 func (s *SecretsSuite) TestSaveSecretConsumerConcurrent(c *gc.C) { 1652 cp := state.CreateSecretParams{ 1653 Version: 1, 1654 Owner: s.owner.Tag(), 1655 UpdateSecretParams: state.UpdateSecretParams{ 1656 LeaderToken: &fakeToken{}, 1657 Data: map[string]string{"foo": "bar"}, 1658 }, 1659 } 1660 uri := secrets.NewURI() 1661 _, err := s.store.CreateSecret(uri, cp) 1662 c.Assert(err, jc.ErrorIsNil) 1663 md := &secrets.SecretConsumerMetadata{ 1664 Label: "foobar", 1665 CurrentRevision: 666, 1666 } 1667 state.SetBeforeHooks(c, s.State, func() { 1668 err := s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), &secrets.SecretConsumerMetadata{CurrentRevision: 668}) 1669 c.Assert(err, jc.ErrorIsNil) 1670 }) 1671 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), md) 1672 c.Assert(err, jc.ErrorIsNil) 1673 md2, err := s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1674 c.Assert(err, jc.ErrorIsNil) 1675 c.Assert(md2, jc.DeepEquals, md) 1676 } 1677 1678 func (s *SecretsSuite) TestSaveSecretConsumerDifferentModel(c *gc.C) { 1679 uri := secrets.NewURI().WithSource("some-uuid") 1680 md := &secrets.SecretConsumerMetadata{ 1681 Label: "foobar", 1682 CurrentRevision: 666, 1683 } 1684 err := s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), md) 1685 c.Assert(err, jc.ErrorIsNil) 1686 md2, err := s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1687 c.Assert(err, jc.ErrorIsNil) 1688 c.Assert(md2, jc.DeepEquals, md) 1689 md.CurrentRevision = 668 1690 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), md) 1691 c.Assert(err, jc.ErrorIsNil) 1692 md2, err = s.State.GetSecretConsumer(uri, names.NewUnitTag("mariadb/0")) 1693 c.Assert(err, jc.ErrorIsNil) 1694 c.Assert(md2, jc.DeepEquals, md) 1695 } 1696 1697 func (s *SecretsSuite) TestSecretGrantAccess(c *gc.C) { 1698 uri := secrets.NewURI() 1699 subject := names.NewApplicationTag("wordpress") 1700 err := s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1701 LeaderToken: &fakeToken{}, 1702 Scope: s.relation.Tag(), 1703 Subject: subject, 1704 Role: secrets.RoleView, 1705 }) 1706 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1707 1708 cp := state.CreateSecretParams{ 1709 Version: 1, 1710 Owner: s.owner.Tag(), 1711 UpdateSecretParams: state.UpdateSecretParams{ 1712 LeaderToken: &fakeToken{}, 1713 Data: map[string]string{"foo": "bar"}, 1714 }, 1715 } 1716 _, err = s.store.CreateSecret(uri, cp) 1717 c.Assert(err, jc.ErrorIsNil) 1718 1719 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1720 LeaderToken: &fakeToken{}, 1721 Scope: s.relation.Tag(), 1722 Subject: subject, 1723 Role: secrets.RoleView, 1724 }) 1725 c.Assert(err, jc.ErrorIsNil) 1726 access, err := s.State.SecretAccess(uri, subject) 1727 c.Assert(err, jc.ErrorIsNil) 1728 c.Assert(access, gc.Equals, secrets.RoleView) 1729 } 1730 1731 func (s *SecretsSuite) TestSecretGrantCrossModelOffer(c *gc.C) { 1732 s.assertSecretGrantCrossModelOffer(c, true, false) 1733 } 1734 1735 func (s *SecretsSuite) TestSecretGrantCrossModelConsumer(c *gc.C) { 1736 s.assertSecretGrantCrossModelOffer(c, false, false) 1737 } 1738 1739 func (s *SecretsSuite) TestSecretGrantCrossModelConsumerUnit(c *gc.C) { 1740 s.assertSecretGrantCrossModelOffer(c, false, true) 1741 } 1742 1743 func (s *SecretsSuite) TestSecretGrantCrossModelUnit(c *gc.C) { 1744 s.assertSecretGrantCrossModelOffer(c, true, true) 1745 } 1746 1747 func (s *SecretsSuite) assertSecretGrantCrossModelOffer(c *gc.C, offer, unit bool) { 1748 rwordpress, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{ 1749 Name: "remote-wordpress", 1750 SourceModel: names.NewModelTag("source-model"), 1751 IsConsumerProxy: offer, 1752 OfferUUID: "offer-uuid", 1753 Endpoints: []charm.Relation{{ 1754 Interface: "mysql", 1755 Limit: 1, 1756 Name: "db", 1757 Role: charm.RoleRequirer, 1758 Scope: charm.ScopeGlobal, 1759 }}, 1760 }) 1761 c.Assert(err, jc.ErrorIsNil) 1762 wordpressEP, err := rwordpress.Endpoint("db") 1763 c.Assert(err, jc.ErrorIsNil) 1764 mysqlEP, err := s.owner.Endpoint("server") 1765 c.Assert(err, jc.ErrorIsNil) 1766 relation, err := s.State.AddRelation(wordpressEP, mysqlEP) 1767 c.Assert(err, jc.ErrorIsNil) 1768 1769 uri := secrets.NewURI() 1770 cp := state.CreateSecretParams{ 1771 Version: 1, 1772 Owner: s.owner.Tag(), 1773 UpdateSecretParams: state.UpdateSecretParams{ 1774 LeaderToken: &fakeToken{}, 1775 Data: map[string]string{"foo": "bar"}, 1776 }, 1777 } 1778 _, err = s.store.CreateSecret(uri, cp) 1779 c.Assert(err, jc.ErrorIsNil) 1780 1781 subject := rwordpress.Tag() 1782 if unit { 1783 subject = names.NewUnitTag(rwordpress.Name() + "/0") 1784 } 1785 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1786 LeaderToken: &fakeToken{}, 1787 Scope: relation.Tag(), 1788 Subject: subject, 1789 Role: secrets.RoleView, 1790 }) 1791 if offer && !unit { 1792 c.Assert(err, jc.ErrorIsNil) 1793 access, err := s.State.SecretAccess(uri, rwordpress.Tag()) 1794 c.Assert(err, jc.ErrorIsNil) 1795 c.Assert(access, gc.Equals, secrets.RoleView) 1796 } else { 1797 c.Assert(err, jc.Satisfies, errors.IsNotSupported) 1798 } 1799 } 1800 1801 func (s *SecretsSuite) TestSecretGrantAccessDyingScope(c *gc.C) { 1802 uri := secrets.NewURI() 1803 cp := state.CreateSecretParams{ 1804 Version: 1, 1805 Owner: s.owner.Tag(), 1806 UpdateSecretParams: state.UpdateSecretParams{ 1807 LeaderToken: &fakeToken{}, 1808 Data: map[string]string{"foo": "bar"}, 1809 }, 1810 } 1811 _, err := s.store.CreateSecret(uri, cp) 1812 c.Assert(err, jc.ErrorIsNil) 1813 1814 // Ensure destroy only sets relation to dying. 1815 wordpress, err := s.State.Application("wordpress") 1816 c.Assert(err, jc.ErrorIsNil) 1817 unit, err := wordpress.AddUnit(state.AddUnitParams{}) 1818 c.Assert(err, jc.ErrorIsNil) 1819 ru, err := s.relation.Unit(unit) 1820 c.Assert(err, jc.ErrorIsNil) 1821 err = ru.EnterScope(nil) 1822 c.Assert(err, jc.ErrorIsNil) 1823 1824 _, err = s.relation.DestroyWithForce(true, time.Second) 1825 c.Assert(err, jc.ErrorIsNil) 1826 1827 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1828 LeaderToken: &fakeToken{}, 1829 Scope: s.relation.Tag(), 1830 Subject: wordpress.Tag(), 1831 Role: secrets.RoleView, 1832 }) 1833 c.Assert(err, gc.ErrorMatches, `cannot grant access to secret in scope of "relation-wordpress.db#mysql.server" which is not alive`) 1834 } 1835 1836 func (s *SecretsSuite) TestSecretGrantAccessDyingSubject(c *gc.C) { 1837 uri := secrets.NewURI() 1838 cp := state.CreateSecretParams{ 1839 Version: 1, 1840 Owner: s.owner.Tag(), 1841 UpdateSecretParams: state.UpdateSecretParams{ 1842 LeaderToken: &fakeToken{}, 1843 Data: map[string]string{"foo": "bar"}, 1844 }, 1845 } 1846 _, err := s.store.CreateSecret(uri, cp) 1847 c.Assert(err, jc.ErrorIsNil) 1848 1849 // Ensure destroy only sets app to dying. 1850 wordpress, err := s.State.Application("wordpress") 1851 c.Assert(err, jc.ErrorIsNil) 1852 unit, err := wordpress.AddUnit(state.AddUnitParams{}) 1853 c.Assert(err, jc.ErrorIsNil) 1854 ru, err := s.relation.Unit(unit) 1855 c.Assert(err, jc.ErrorIsNil) 1856 err = ru.EnterScope(nil) 1857 c.Assert(err, jc.ErrorIsNil) 1858 1859 err = wordpress.Destroy() 1860 c.Assert(err, jc.ErrorIsNil) 1861 1862 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1863 LeaderToken: &fakeToken{}, 1864 Scope: s.relation.Tag(), 1865 Subject: wordpress.Tag(), 1866 Role: secrets.RoleView, 1867 }) 1868 c.Assert(err, gc.ErrorMatches, `cannot grant access to secret in scope of "relation-wordpress.db#mysql.server" which is not alive`) 1869 } 1870 1871 func (s *SecretsSuite) TestSecretRevokeAccess(c *gc.C) { 1872 uri := secrets.NewURI() 1873 cp := state.CreateSecretParams{ 1874 Version: 1, 1875 Owner: s.owner.Tag(), 1876 UpdateSecretParams: state.UpdateSecretParams{ 1877 LeaderToken: &fakeToken{}, 1878 Data: map[string]string{"foo": "bar"}, 1879 }, 1880 } 1881 _, err := s.store.CreateSecret(uri, cp) 1882 c.Assert(err, jc.ErrorIsNil) 1883 1884 subject := names.NewApplicationTag("wordpress") 1885 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1886 LeaderToken: &fakeToken{}, 1887 Scope: s.relation.Tag(), 1888 Subject: subject, 1889 Role: secrets.RoleView, 1890 }) 1891 c.Assert(err, jc.ErrorIsNil) 1892 access, err := s.State.SecretAccess(uri, subject) 1893 c.Assert(err, jc.ErrorIsNil) 1894 c.Assert(access, gc.Equals, secrets.RoleView) 1895 1896 err = s.State.RevokeSecretAccess(uri, state.SecretAccessParams{ 1897 LeaderToken: &fakeToken{}, 1898 Subject: subject, 1899 }) 1900 c.Assert(err, jc.ErrorIsNil) 1901 access, err = s.State.SecretAccess(uri, subject) 1902 c.Assert(err, jc.ErrorIsNil) 1903 c.Assert(access, gc.Equals, secrets.RoleNone) 1904 1905 err = s.State.RevokeSecretAccess(uri, state.SecretAccessParams{ 1906 LeaderToken: &fakeToken{}, 1907 Subject: subject, 1908 }) 1909 c.Assert(err, jc.ErrorIsNil) 1910 } 1911 1912 func (s *SecretsSuite) TestSecretAccessScope(c *gc.C) { 1913 uri := secrets.NewURI() 1914 subject := names.NewApplicationTag("wordpress") 1915 1916 cp := state.CreateSecretParams{ 1917 Version: 1, 1918 Owner: s.owner.Tag(), 1919 UpdateSecretParams: state.UpdateSecretParams{ 1920 LeaderToken: &fakeToken{}, 1921 Data: map[string]string{"foo": "bar"}, 1922 }, 1923 } 1924 _, err := s.store.CreateSecret(uri, cp) 1925 c.Assert(err, jc.ErrorIsNil) 1926 1927 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1928 LeaderToken: &fakeToken{}, 1929 Scope: s.relation.Tag(), 1930 Subject: subject, 1931 Role: secrets.RoleView, 1932 }) 1933 c.Assert(err, jc.ErrorIsNil) 1934 scope, err := s.State.SecretAccessScope(uri, subject) 1935 c.Assert(err, jc.ErrorIsNil) 1936 c.Assert(scope, jc.DeepEquals, s.relation.Tag()) 1937 } 1938 1939 func (s *SecretsSuite) TestDelete(c *gc.C) { 1940 subject := names.NewApplicationTag("wordpress") 1941 create := func(label string) *secrets.URI { 1942 uri := secrets.NewURI() 1943 now := s.Clock.Now().Round(time.Second).UTC() 1944 next := now.Add(time.Minute).Round(time.Second).UTC() 1945 cp := state.CreateSecretParams{ 1946 Version: 1, 1947 Owner: s.owner.Tag(), 1948 UpdateSecretParams: state.UpdateSecretParams{ 1949 LeaderToken: &fakeToken{}, 1950 RotatePolicy: ptr(secrets.RotateDaily), 1951 NextRotateTime: ptr(next), 1952 Label: ptr(label), 1953 Data: map[string]string{"foo": "bar"}, 1954 }, 1955 } 1956 _, err := s.store.CreateSecret(uri, cp) 1957 c.Assert(err, jc.ErrorIsNil) 1958 cmd := &secrets.SecretConsumerMetadata{ 1959 Label: "consumer-" + label, 1960 CurrentRevision: 1, 1961 } 1962 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), cmd) 1963 c.Assert(err, jc.ErrorIsNil) 1964 err = s.State.GrantSecretAccess(uri, state.SecretAccessParams{ 1965 LeaderToken: &fakeToken{}, 1966 Scope: s.relation.Tag(), 1967 Subject: subject, 1968 Role: secrets.RoleView, 1969 }) 1970 c.Assert(err, jc.ErrorIsNil) 1971 return uri 1972 } 1973 backendStore := state.NewSecretBackends(s.State) 1974 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 1975 ID: "backend-id", 1976 Name: "foo", 1977 BackendType: "vault", 1978 }) 1979 c.Assert(err, jc.ErrorIsNil) 1980 backendRefCount, err := s.State.ReadBackendRefCount("backend-id") 1981 c.Assert(err, jc.ErrorIsNil) 1982 c.Assert(backendRefCount, gc.Equals, 0) 1983 1984 uri1 := create("label1") 1985 up := state.UpdateSecretParams{ 1986 LeaderToken: &fakeToken{}, 1987 ValueRef: &secrets.ValueRef{ 1988 BackendID: "backend-id", 1989 RevisionID: "rev-id", 1990 }, 1991 } 1992 _, err = s.store.UpdateSecret(uri1, up) 1993 c.Assert(err, jc.ErrorIsNil) 1994 1995 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 1996 c.Assert(err, jc.ErrorIsNil) 1997 c.Assert(backendRefCount, gc.Equals, 1) 1998 1999 uri2 := create("label2") 2000 2001 external, err := s.store.DeleteSecret(uri1) 2002 c.Assert(err, jc.ErrorIsNil) 2003 c.Assert(external, jc.DeepEquals, []secrets.ValueRef{{ 2004 BackendID: "backend-id", 2005 RevisionID: "rev-id", 2006 }}) 2007 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 2008 c.Assert(err, jc.ErrorIsNil) 2009 c.Assert(backendRefCount, gc.Equals, 0) 2010 2011 _, _, err = s.store.GetSecretValue(uri1, 1) 2012 c.Assert(err, jc.Satisfies, errors.IsNotFound) 2013 external, err = s.store.DeleteSecret(uri1) 2014 c.Assert(err, jc.ErrorIsNil) 2015 c.Assert(external, gc.HasLen, 0) 2016 2017 // Check that other secret info remains intact. 2018 secretRevisionsCollection, closer := state.GetCollection(s.State, "secretRevisions") 2019 defer closer() 2020 n, err := secretRevisionsCollection.FindId(uri2.ID + "/1").Count() 2021 c.Assert(err, jc.ErrorIsNil) 2022 c.Assert(n, gc.Equals, 1) 2023 n, err = secretRevisionsCollection.Find(nil).Count() 2024 c.Assert(err, jc.ErrorIsNil) 2025 c.Assert(n, gc.Equals, 1) 2026 2027 secretRotateCollection, closer := state.GetCollection(s.State, "secretRotate") 2028 defer closer() 2029 n, err = secretRotateCollection.FindId(uri2.ID).Count() 2030 c.Assert(err, jc.ErrorIsNil) 2031 c.Assert(n, gc.Equals, 1) 2032 n, err = secretRotateCollection.Find(nil).Count() 2033 c.Assert(err, jc.ErrorIsNil) 2034 c.Assert(n, gc.Equals, 1) 2035 2036 secretConsumersCollection, closer := state.GetCollection(s.State, "secretConsumers") 2037 defer closer() 2038 n, err = secretConsumersCollection.FindId(uri2.ID + "#unit-mariadb-0").Count() 2039 c.Assert(err, jc.ErrorIsNil) 2040 c.Assert(n, gc.Equals, 1) 2041 n, err = secretConsumersCollection.Find(nil).Count() 2042 c.Assert(err, jc.ErrorIsNil) 2043 c.Assert(n, gc.Equals, 1) 2044 2045 secretPermissionsCollection, closer := state.GetCollection(s.State, "secretPermissions") 2046 defer closer() 2047 n, err = secretPermissionsCollection.FindId(uri2.ID + "#application-wordpress").Count() 2048 c.Assert(err, jc.ErrorIsNil) 2049 c.Assert(n, gc.Equals, 1) 2050 n, err = secretPermissionsCollection.Find(nil).Count() 2051 c.Assert(err, jc.ErrorIsNil) 2052 c.Assert(n, gc.Equals, 1) 2053 2054 refCountsCollection, closer := state.GetCollection(s.State, "refcounts") 2055 defer closer() 2056 n, err = refCountsCollection.FindId(uri2.ID + "#consumer").Count() 2057 c.Assert(err, jc.ErrorIsNil) 2058 c.Assert(n, gc.Equals, 1) 2059 n, err = refCountsCollection.FindId(uri1.ID + "#consumer").Count() 2060 c.Assert(err, jc.ErrorIsNil) 2061 c.Assert(n, gc.Equals, 0) 2062 2063 // Check we can now reuse the label. 2064 create("label1") 2065 } 2066 2067 func (s *SecretsSuite) TestDeleteRevisions(c *gc.C) { 2068 backendStore := state.NewSecretBackends(s.State) 2069 _, err := backendStore.CreateSecretBackend(state.CreateSecretBackendParams{ 2070 ID: "backend-id", 2071 Name: "foo", 2072 BackendType: "vault", 2073 }) 2074 c.Assert(err, jc.ErrorIsNil) 2075 backendRefCount, err := s.State.ReadBackendRefCount("backend-id") 2076 c.Assert(err, jc.ErrorIsNil) 2077 c.Assert(backendRefCount, gc.Equals, 0) 2078 2079 uri := secrets.NewURI() 2080 cp := state.CreateSecretParams{ 2081 Version: 1, 2082 Owner: s.owner.Tag(), 2083 UpdateSecretParams: state.UpdateSecretParams{ 2084 LeaderToken: &fakeToken{}, 2085 Data: map[string]string{"foo": "bar"}, 2086 }, 2087 } 2088 _, err = s.store.CreateSecret(uri, cp) 2089 c.Assert(err, jc.ErrorIsNil) 2090 _, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2091 LeaderToken: &fakeToken{}, 2092 Data: map[string]string{"foo": "bar2"}, 2093 }) 2094 c.Assert(err, jc.ErrorIsNil) 2095 _, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2096 LeaderToken: &fakeToken{}, 2097 ValueRef: &secrets.ValueRef{ 2098 BackendID: "backend-id", 2099 RevisionID: "rev-id", 2100 }, 2101 }) 2102 c.Assert(err, jc.ErrorIsNil) 2103 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 2104 c.Assert(err, jc.ErrorIsNil) 2105 c.Assert(backendRefCount, gc.Equals, 1) 2106 2107 external, err := s.store.DeleteSecret(uri, 1) 2108 c.Assert(err, jc.ErrorIsNil) 2109 c.Assert(external, gc.HasLen, 0) 2110 _, _, err = s.store.GetSecretValue(uri, 1) 2111 c.Assert(err, jc.Satisfies, errors.IsNotFound) 2112 val, _, err := s.store.GetSecretValue(uri, 2) 2113 c.Assert(err, jc.ErrorIsNil) 2114 c.Assert(val.EncodedValues(), jc.DeepEquals, map[string]string{"foo": "bar2"}) 2115 _, ref, err := s.store.GetSecretValue(uri, 3) 2116 c.Assert(err, jc.ErrorIsNil) 2117 c.Assert(ref, gc.NotNil) 2118 c.Assert(ref, jc.DeepEquals, &secrets.ValueRef{ 2119 BackendID: "backend-id", 2120 RevisionID: "rev-id", 2121 }) 2122 2123 external, err = s.store.DeleteSecret(uri, 1, 2, 3) 2124 c.Assert(err, jc.ErrorIsNil) 2125 c.Assert(external, jc.DeepEquals, []secrets.ValueRef{{ 2126 BackendID: "backend-id", 2127 RevisionID: "rev-id", 2128 }}) 2129 _, _, err = s.store.GetSecretValue(uri, 3) 2130 c.Assert(err, jc.Satisfies, errors.IsNotFound) 2131 _, err = s.store.GetSecret(uri) 2132 c.Assert(err, jc.Satisfies, errors.IsNotFound) 2133 2134 backendRefCount, err = s.State.ReadBackendRefCount("backend-id") 2135 c.Assert(err, jc.ErrorIsNil) 2136 c.Assert(backendRefCount, gc.Equals, 0) 2137 } 2138 2139 func (s *SecretsSuite) TestSecretRotated(c *gc.C) { 2140 uri := secrets.NewURI() 2141 2142 now := s.Clock.Now().Round(time.Second).UTC() 2143 next := now.Add(time.Minute).Round(time.Second).UTC() 2144 cp := state.CreateSecretParams{ 2145 Version: 1, 2146 Owner: s.owner.Tag(), 2147 UpdateSecretParams: state.UpdateSecretParams{ 2148 LeaderToken: &fakeToken{}, 2149 RotatePolicy: ptr(secrets.RotateDaily), 2150 NextRotateTime: ptr(next), 2151 Data: map[string]string{"foo": "bar"}, 2152 }, 2153 } 2154 md, err := s.store.CreateSecret(uri, cp) 2155 c.Assert(err, jc.ErrorIsNil) 2156 next2 := now.Add(time.Hour).Round(time.Second).UTC() 2157 err = s.State.SecretRotated(uri, next2) 2158 c.Assert(err, jc.ErrorIsNil) 2159 2160 nextTime := state.GetSecretNextRotateTime(c, s.State, md.URI.ID) 2161 c.Assert(nextTime, gc.Equals, next2) 2162 } 2163 2164 func (s *SecretsSuite) TestSecretRotatedConcurrent(c *gc.C) { 2165 uri := secrets.NewURI() 2166 2167 now := s.Clock.Now().Round(time.Second).UTC() 2168 next := now.Add(time.Minute).Round(time.Second).UTC() 2169 cp := state.CreateSecretParams{ 2170 Version: 1, 2171 Owner: s.owner.Tag(), 2172 UpdateSecretParams: state.UpdateSecretParams{ 2173 LeaderToken: &fakeToken{}, 2174 RotatePolicy: ptr(secrets.RotateDaily), 2175 NextRotateTime: ptr(next), 2176 Data: map[string]string{"foo": "bar"}, 2177 }, 2178 } 2179 md, err := s.store.CreateSecret(uri, cp) 2180 c.Assert(err, jc.ErrorIsNil) 2181 2182 later := now.Add(time.Hour).Round(time.Second).UTC() 2183 later2 := now.Add(2 * time.Hour).Round(time.Second).UTC() 2184 state.SetBeforeHooks(c, s.State, func() { 2185 err := s.State.SecretRotated(uri, later) 2186 c.Assert(err, jc.ErrorIsNil) 2187 }) 2188 2189 err = s.State.SecretRotated(uri, later2) 2190 c.Assert(err, jc.ErrorIsNil) 2191 2192 nextTime := state.GetSecretNextRotateTime(c, s.State, md.URI.ID) 2193 c.Assert(nextTime, gc.Equals, later) 2194 } 2195 2196 type SecretsRotationWatcherSuite struct { 2197 testing.StateSuite 2198 store state.SecretsStore 2199 2200 ownerApp *state.Application 2201 ownerUnit *state.Unit 2202 } 2203 2204 var _ = gc.Suite(&SecretsRotationWatcherSuite{}) 2205 2206 func (s *SecretsRotationWatcherSuite) SetUpTest(c *gc.C) { 2207 s.StateSuite.SetUpTest(c) 2208 s.store = state.NewSecrets(s.State) 2209 s.ownerApp = s.Factory.MakeApplication(c, nil) 2210 s.ownerUnit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.ownerApp}) 2211 } 2212 2213 func (s *SecretsRotationWatcherSuite) setupWatcher(c *gc.C) (state.SecretsTriggerWatcher, *secrets.URI) { 2214 uri := secrets.NewURI() 2215 now := s.Clock.Now().Round(time.Second).UTC() 2216 next := now.Add(time.Minute).Round(time.Second).UTC() 2217 cp := state.CreateSecretParams{ 2218 Version: 1, 2219 Owner: s.ownerApp.Tag(), 2220 UpdateSecretParams: state.UpdateSecretParams{ 2221 LeaderToken: &fakeToken{}, 2222 RotatePolicy: ptr(secrets.RotateDaily), 2223 NextRotateTime: ptr(next), 2224 Data: map[string]string{"foo": "bar"}, 2225 }, 2226 } 2227 md, err := s.store.CreateSecret(uri, cp) 2228 c.Assert(err, jc.ErrorIsNil) 2229 w, err := s.State.WatchSecretsRotationChanges( 2230 []names.Tag{s.ownerApp.Tag(), s.ownerUnit.Tag()}) 2231 c.Assert(err, jc.ErrorIsNil) 2232 2233 wc := testing.NewSecretsTriggerWatcherC(c, w) 2234 wc.AssertChange(watcher.SecretTriggerChange{ 2235 URI: md.URI, 2236 NextTriggerTime: next, 2237 }) 2238 wc.AssertNoChange() 2239 return w, uri 2240 } 2241 2242 func (s *SecretsRotationWatcherSuite) TestWatchInitialEvent(c *gc.C) { 2243 w, _ := s.setupWatcher(c) 2244 testing.AssertStop(c, w) 2245 } 2246 2247 func (s *SecretsRotationWatcherSuite) TestWatchSingleUpdate(c *gc.C) { 2248 w, uri := s.setupWatcher(c) 2249 wc := testing.NewSecretsTriggerWatcherC(c, w) 2250 defer testing.AssertStop(c, w) 2251 2252 now := s.Clock.Now().Round(time.Second).UTC() 2253 next := now.Add(2 * time.Hour).Round(time.Second).UTC() 2254 err := s.State.SecretRotated(uri, next) 2255 c.Assert(err, jc.ErrorIsNil) 2256 2257 wc.AssertChange(watcher.SecretTriggerChange{ 2258 URI: uri, 2259 NextTriggerTime: next, 2260 }) 2261 wc.AssertNoChange() 2262 } 2263 2264 func (s *SecretsRotationWatcherSuite) TestWatchDelete(c *gc.C) { 2265 w, uri := s.setupWatcher(c) 2266 wc := testing.NewSecretsTriggerWatcherC(c, w) 2267 defer testing.AssertStop(c, w) 2268 2269 md, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2270 LeaderToken: &fakeToken{}, 2271 RotatePolicy: ptr(secrets.RotateNever), 2272 }) 2273 c.Assert(err, jc.ErrorIsNil) 2274 2275 wc.AssertChange(watcher.SecretTriggerChange{ 2276 URI: md.URI, 2277 }) 2278 wc.AssertNoChange() 2279 } 2280 2281 func (s *SecretsRotationWatcherSuite) TestWatchMultipleUpdatesSameSecret(c *gc.C) { 2282 w, uri := s.setupWatcher(c) 2283 wc := testing.NewSecretsTriggerWatcherC(c, w) 2284 defer testing.AssertStop(c, w) 2285 2286 // TODO(quiescence): these two changes should be one event. 2287 now := s.Clock.Now().Round(time.Second).UTC() 2288 next := now.Add(time.Minute).Round(time.Second).UTC() 2289 err := s.State.SecretRotated(uri, next) 2290 c.Assert(err, jc.ErrorIsNil) 2291 wc.AssertChange(watcher.SecretTriggerChange{ 2292 URI: uri, 2293 NextTriggerTime: next, 2294 }) 2295 next2 := now.Add(time.Hour).Round(time.Second).UTC() 2296 err = s.State.SecretRotated(uri, next2) 2297 c.Assert(err, jc.ErrorIsNil) 2298 2299 wc.AssertChange(watcher.SecretTriggerChange{ 2300 URI: uri, 2301 NextTriggerTime: next2, 2302 }) 2303 wc.AssertNoChange() 2304 } 2305 2306 func (s *SecretsRotationWatcherSuite) TestWatchMultipleUpdatesSameSecretDeleted(c *gc.C) { 2307 w, uri := s.setupWatcher(c) 2308 wc := testing.NewSecretsTriggerWatcherC(c, w) 2309 defer testing.AssertStop(c, w) 2310 2311 // TODO(quiescence): these two changes should be one event. 2312 now := s.Clock.Now().Round(time.Second).UTC() 2313 next := now.Add(time.Hour).Round(time.Second).UTC() 2314 err := s.State.SecretRotated(uri, next) 2315 c.Assert(err, jc.ErrorIsNil) 2316 wc.AssertChange(watcher.SecretTriggerChange{ 2317 URI: uri, 2318 NextTriggerTime: next, 2319 }) 2320 md, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2321 LeaderToken: &fakeToken{}, 2322 RotatePolicy: ptr(secrets.RotateNever), 2323 }) 2324 c.Assert(err, jc.ErrorIsNil) 2325 2326 wc.AssertChange(watcher.SecretTriggerChange{ 2327 URI: md.URI, 2328 }) 2329 wc.AssertNoChange() 2330 } 2331 2332 func (s *SecretsRotationWatcherSuite) TestWatchMultipleUpdates(c *gc.C) { 2333 w, uri := s.setupWatcher(c) 2334 wc := testing.NewSecretsTriggerWatcherC(c, w) 2335 defer testing.AssertStop(c, w) 2336 2337 // TODO(quiescence): these two changes should be one event. 2338 now := s.Clock.Now().Round(time.Second).UTC() 2339 next := now.Add(time.Hour).Round(time.Second).UTC() 2340 err := s.State.SecretRotated(uri, next) 2341 c.Assert(err, jc.ErrorIsNil) 2342 wc.AssertChange(watcher.SecretTriggerChange{ 2343 URI: uri, 2344 NextTriggerTime: next, 2345 }) 2346 2347 uri2 := secrets.NewURI() 2348 next2 := now.Add(time.Minute).Round(time.Second).UTC() 2349 md2, err := s.store.CreateSecret(uri2, state.CreateSecretParams{ 2350 Version: 1, 2351 Owner: s.ownerApp.Tag(), 2352 UpdateSecretParams: state.UpdateSecretParams{ 2353 LeaderToken: &fakeToken{}, 2354 RotatePolicy: ptr(secrets.RotateHourly), 2355 NextRotateTime: ptr(next2), 2356 Data: map[string]string{"foo": "bar"}, 2357 }, 2358 }) 2359 c.Assert(err, jc.ErrorIsNil) 2360 wc.AssertChange(watcher.SecretTriggerChange{ 2361 URI: md2.URI, 2362 NextTriggerTime: next2, 2363 }) 2364 2365 md, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2366 LeaderToken: &fakeToken{}, 2367 RotatePolicy: ptr(secrets.RotateNever), 2368 }) 2369 c.Assert(err, jc.ErrorIsNil) 2370 2371 wc.AssertChange(watcher.SecretTriggerChange{ 2372 URI: md.URI, 2373 }) 2374 wc.AssertNoChange() 2375 } 2376 2377 func (s *SecretsRotationWatcherSuite) TestWatchRestartChangeOwners(c *gc.C) { 2378 w, uri := s.setupWatcher(c) 2379 wc := testing.NewSecretsTriggerWatcherC(c, w) 2380 defer testing.AssertStop(c, w) 2381 2382 now := s.Clock.Now().Round(time.Second).UTC() 2383 next1 := now.Add(time.Minute).Round(time.Second).UTC() 2384 next2 := now.Add(time.Minute).Round(time.Second).UTC() 2385 2386 uri2 := secrets.NewURI() 2387 cp := state.CreateSecretParams{ 2388 Version: 1, 2389 Owner: s.ownerUnit.Tag(), 2390 UpdateSecretParams: state.UpdateSecretParams{ 2391 LeaderToken: &fakeToken{}, 2392 RotatePolicy: ptr(secrets.RotateHourly), 2393 NextRotateTime: ptr(next2), 2394 Data: map[string]string{"foo": "bar"}, 2395 }, 2396 } 2397 _, err := s.store.CreateSecret(uri2, cp) 2398 c.Assert(err, jc.ErrorIsNil) 2399 2400 next3 := now.Add(time.Minute).Round(time.Second).UTC() 2401 anotherUnit := s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.ownerApp}) 2402 2403 uri3 := secrets.NewURI() 2404 cp = state.CreateSecretParams{ 2405 Version: 1, 2406 Owner: anotherUnit.Tag(), 2407 UpdateSecretParams: state.UpdateSecretParams{ 2408 LeaderToken: &fakeToken{}, 2409 RotatePolicy: ptr(secrets.RotateHourly), 2410 NextRotateTime: ptr(next3), 2411 Data: map[string]string{"foo": "bar"}, 2412 }, 2413 } 2414 _, err = s.store.CreateSecret(uri3, cp) 2415 c.Assert(err, jc.ErrorIsNil) 2416 2417 wc.AssertChange(watcher.SecretTriggerChange{ 2418 URI: uri2, 2419 NextTriggerTime: next2, 2420 }) 2421 2422 wc.AssertNoChange() 2423 testing.AssertStop(c, w) 2424 2425 w, err = s.State.WatchSecretsRotationChanges( 2426 []names.Tag{s.ownerApp.Tag(), anotherUnit.Tag()}) 2427 c.Assert(err, jc.ErrorIsNil) 2428 2429 wc = testing.NewSecretsTriggerWatcherC(c, w) 2430 defer testing.AssertStop(c, w) 2431 2432 wc.AssertChange(watcher.SecretTriggerChange{ 2433 URI: uri, 2434 NextTriggerTime: next1, 2435 }, watcher.SecretTriggerChange{ 2436 URI: uri3, 2437 NextTriggerTime: next3, 2438 }) 2439 wc.AssertNoChange() 2440 } 2441 2442 type SecretsExpiryWatcherSuite struct { 2443 testing.StateSuite 2444 store state.SecretsStore 2445 2446 ownerApp *state.Application 2447 ownerUnit *state.Unit 2448 } 2449 2450 var _ = gc.Suite(&SecretsExpiryWatcherSuite{}) 2451 2452 func (s *SecretsExpiryWatcherSuite) SetUpTest(c *gc.C) { 2453 s.StateSuite.SetUpTest(c) 2454 s.store = state.NewSecrets(s.State) 2455 s.ownerApp = s.Factory.MakeApplication(c, nil) 2456 s.ownerUnit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.ownerApp}) 2457 } 2458 2459 func (s *SecretsExpiryWatcherSuite) setupWatcher(c *gc.C) (state.SecretsTriggerWatcher, *secrets.URI) { 2460 uri := secrets.NewURI() 2461 now := s.Clock.Now().Round(time.Second).UTC() 2462 next := now.Add(time.Minute).Round(time.Second).UTC() 2463 cp := state.CreateSecretParams{ 2464 Version: 1, 2465 Owner: s.ownerApp.Tag(), 2466 UpdateSecretParams: state.UpdateSecretParams{ 2467 LeaderToken: &fakeToken{}, 2468 ExpireTime: ptr(next), 2469 Data: map[string]string{"foo": "bar"}, 2470 }, 2471 } 2472 md, err := s.store.CreateSecret(uri, cp) 2473 c.Assert(err, jc.ErrorIsNil) 2474 w, err := s.State.WatchSecretRevisionsExpiryChanges( 2475 []names.Tag{s.ownerApp.Tag(), s.ownerUnit.Tag()}) 2476 c.Assert(err, jc.ErrorIsNil) 2477 2478 wc := testing.NewSecretsTriggerWatcherC(c, w) 2479 wc.AssertChange(watcher.SecretTriggerChange{ 2480 URI: md.URI, 2481 Revision: 1, 2482 NextTriggerTime: next, 2483 }) 2484 wc.AssertNoChange() 2485 return w, uri 2486 } 2487 2488 func (s *SecretsExpiryWatcherSuite) TestWatchInitialEvent(c *gc.C) { 2489 w, _ := s.setupWatcher(c) 2490 testing.AssertStop(c, w) 2491 } 2492 2493 func (s *SecretsExpiryWatcherSuite) TestWatchSingleUpdate(c *gc.C) { 2494 w, uri := s.setupWatcher(c) 2495 wc := testing.NewSecretsTriggerWatcherC(c, w) 2496 defer testing.AssertStop(c, w) 2497 2498 now := s.Clock.Now().Round(time.Second).UTC() 2499 next := now.Add(2 * time.Hour).Round(time.Second).UTC() 2500 2501 s.Clock.Advance(time.Hour) 2502 updated := s.Clock.Now().Round(time.Second).UTC() 2503 update := state.UpdateSecretParams{ 2504 LeaderToken: &fakeToken{}, 2505 ExpireTime: ptr(next), 2506 } 2507 md, err := s.store.UpdateSecret(uri, update) 2508 c.Assert(err, jc.ErrorIsNil) 2509 c.Assert(md.LatestExpireTime, gc.NotNil) 2510 c.Assert(*md.LatestExpireTime, gc.Equals, next) 2511 2512 revs, err := s.store.ListSecretRevisions(md.URI) 2513 c.Assert(err, jc.ErrorIsNil) 2514 for _, r := range revs { 2515 if r.ExpireTime != nil && r.ExpireTime.Equal(update.ExpireTime.Round(time.Second).UTC()) { 2516 c.Assert(r.UpdateTime, jc.Almost, updated) 2517 return 2518 } 2519 } 2520 c.Fatalf("expire time not set for secret revision %d", 2) 2521 2522 wc.AssertChange(watcher.SecretTriggerChange{ 2523 URI: uri, 2524 Revision: 3, 2525 NextTriggerTime: next, 2526 }) 2527 wc.AssertNoChange() 2528 } 2529 2530 func (s *SecretsExpiryWatcherSuite) TestWatchSetExpiryToNil(c *gc.C) { 2531 w, uri := s.setupWatcher(c) 2532 wc := testing.NewSecretsTriggerWatcherC(c, w) 2533 defer testing.AssertStop(c, w) 2534 2535 md, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2536 LeaderToken: &fakeToken{}, 2537 ExpireTime: ptr(time.Time{}), 2538 }) 2539 c.Assert(err, jc.ErrorIsNil) 2540 2541 wc.AssertChange(watcher.SecretTriggerChange{ 2542 URI: md.URI, 2543 Revision: 1, 2544 }) 2545 wc.AssertNoChange() 2546 } 2547 2548 func (s *SecretsExpiryWatcherSuite) TestWatchMultipleUpdates(c *gc.C) { 2549 w, uri := s.setupWatcher(c) 2550 wc := testing.NewSecretsTriggerWatcherC(c, w) 2551 defer testing.AssertStop(c, w) 2552 2553 now := s.Clock.Now().Round(time.Second).UTC() 2554 md, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2555 LeaderToken: &fakeToken{}, 2556 ExpireTime: ptr(time.Time{}), 2557 }) 2558 c.Assert(err, jc.ErrorIsNil) 2559 2560 next := now.Add(2 * time.Hour).Round(time.Second).UTC() 2561 update := state.UpdateSecretParams{ 2562 LeaderToken: &fakeToken{}, 2563 ExpireTime: ptr(next), 2564 } 2565 _, err = s.store.UpdateSecret(uri, update) 2566 c.Assert(err, jc.ErrorIsNil) 2567 2568 wc.AssertChange(watcher.SecretTriggerChange{ 2569 URI: md.URI, 2570 Revision: 1, 2571 }, watcher.SecretTriggerChange{ 2572 URI: md.URI, 2573 Revision: 1, 2574 NextTriggerTime: next, 2575 }) 2576 wc.AssertNoChange() 2577 } 2578 2579 func (s *SecretsExpiryWatcherSuite) TestWatchRemoveSecret(c *gc.C) { 2580 w, uri := s.setupWatcher(c) 2581 wc := testing.NewSecretsTriggerWatcherC(c, w) 2582 defer testing.AssertStop(c, w) 2583 2584 _, err := s.store.DeleteSecret(uri) 2585 c.Assert(err, jc.ErrorIsNil) 2586 2587 wc.AssertChange(watcher.SecretTriggerChange{ 2588 URI: uri, 2589 Revision: 1, 2590 }) 2591 wc.AssertNoChange() 2592 2593 uri2 := secrets.NewURI() 2594 now := s.Clock.Now().Round(time.Second).UTC() 2595 next := now.Add(time.Minute).Round(time.Second).UTC() 2596 cp := state.CreateSecretParams{ 2597 Version: 1, 2598 Owner: s.ownerUnit.Tag(), 2599 UpdateSecretParams: state.UpdateSecretParams{ 2600 LeaderToken: &fakeToken{}, 2601 ExpireTime: ptr(next), 2602 Data: map[string]string{"foo": "bar"}, 2603 }, 2604 } 2605 _, err = s.store.CreateSecret(uri2, cp) 2606 c.Assert(err, jc.ErrorIsNil) 2607 wc.AssertChange(watcher.SecretTriggerChange{ 2608 URI: uri2, 2609 Revision: 1, 2610 NextTriggerTime: next, 2611 }) 2612 wc.AssertNoChange() 2613 2614 _, err = s.store.DeleteSecret(uri2) 2615 c.Assert(err, jc.ErrorIsNil) 2616 2617 wc.AssertChange(watcher.SecretTriggerChange{ 2618 URI: uri2, 2619 Revision: 1, 2620 }) 2621 wc.AssertNoChange() 2622 } 2623 2624 func (s *SecretsExpiryWatcherSuite) TestWatchRemoveRevision(c *gc.C) { 2625 w, uri := s.setupWatcher(c) 2626 wc := testing.NewSecretsTriggerWatcherC(c, w) 2627 defer testing.AssertStop(c, w) 2628 2629 now := s.Clock.Now().Round(time.Second).UTC() 2630 triggerTime := now.Add(time.Minute).Round(time.Second).UTC() 2631 _, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2632 LeaderToken: &fakeToken{}, 2633 Data: map[string]string{"foo": "bar2"}, 2634 }) 2635 c.Assert(err, jc.ErrorIsNil) 2636 wc.AssertChange(watcher.SecretTriggerChange{ 2637 URI: uri, 2638 Revision: 1, 2639 NextTriggerTime: triggerTime, 2640 }) 2641 wc.AssertNoChange() 2642 2643 _, err = s.store.DeleteSecret(uri, 1) 2644 c.Assert(err, jc.ErrorIsNil) 2645 2646 wc.AssertChange(watcher.SecretTriggerChange{ 2647 URI: uri, 2648 Revision: 1, 2649 }) 2650 wc.AssertNoChange() 2651 } 2652 2653 func (s *SecretsExpiryWatcherSuite) TestWatchRestartChangeOwners(c *gc.C) { 2654 w, uri := s.setupWatcher(c) 2655 wc := testing.NewSecretsTriggerWatcherC(c, w) 2656 defer testing.AssertStop(c, w) 2657 2658 now := s.Clock.Now().Round(time.Second).UTC() 2659 next1 := now.Add(time.Minute).Round(time.Second).UTC() 2660 next2 := now.Add(time.Minute).Round(time.Second).UTC() 2661 2662 uri2 := secrets.NewURI() 2663 cp := state.CreateSecretParams{ 2664 Version: 1, 2665 Owner: s.ownerUnit.Tag(), 2666 UpdateSecretParams: state.UpdateSecretParams{ 2667 LeaderToken: &fakeToken{}, 2668 ExpireTime: ptr(next2), 2669 Data: map[string]string{"foo": "bar"}, 2670 }, 2671 } 2672 _, err := s.store.CreateSecret(uri2, cp) 2673 c.Assert(err, jc.ErrorIsNil) 2674 2675 next3 := now.Add(time.Minute).Round(time.Second).UTC() 2676 2677 anotherUnit := s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.ownerApp}) 2678 uri3 := secrets.NewURI() 2679 cp = state.CreateSecretParams{ 2680 Version: 1, 2681 Owner: anotherUnit.Tag(), 2682 UpdateSecretParams: state.UpdateSecretParams{ 2683 LeaderToken: &fakeToken{}, 2684 ExpireTime: ptr(next3), 2685 Data: map[string]string{"foo": "bar"}, 2686 }, 2687 } 2688 _, err = s.store.CreateSecret(uri3, cp) 2689 c.Assert(err, jc.ErrorIsNil) 2690 2691 wc.AssertChange(watcher.SecretTriggerChange{ 2692 URI: uri2, 2693 Revision: 1, 2694 NextTriggerTime: next2, 2695 }) 2696 2697 wc.AssertNoChange() 2698 testing.AssertStop(c, w) 2699 2700 w, err = s.State.WatchSecretRevisionsExpiryChanges( 2701 []names.Tag{s.ownerApp.Tag(), anotherUnit.Tag()}) 2702 c.Assert(err, jc.ErrorIsNil) 2703 2704 wc = testing.NewSecretsTriggerWatcherC(c, w) 2705 defer testing.AssertStop(c, w) 2706 2707 wc.AssertChange(watcher.SecretTriggerChange{ 2708 URI: uri, 2709 Revision: 1, 2710 NextTriggerTime: next1, 2711 }, watcher.SecretTriggerChange{ 2712 URI: uri3, 2713 Revision: 1, 2714 NextTriggerTime: next3, 2715 }) 2716 wc.AssertNoChange() 2717 } 2718 2719 type SecretsConsumedWatcherSuite struct { 2720 testing.StateSuite 2721 store state.SecretsStore 2722 2723 owner *state.Application 2724 } 2725 2726 var _ = gc.Suite(&SecretsConsumedWatcherSuite{}) 2727 2728 func (s *SecretsConsumedWatcherSuite) SetUpTest(c *gc.C) { 2729 s.StateSuite.SetUpTest(c) 2730 s.store = state.NewSecrets(s.State) 2731 s.owner = s.Factory.MakeApplication(c, nil) 2732 } 2733 2734 func (s *SecretsConsumedWatcherSuite) TestWatcherInitialEvent(c *gc.C) { 2735 w, err := s.State.WatchConsumedSecretsChanges(names.NewUnitTag("mariadb/0")) 2736 c.Assert(err, jc.ErrorIsNil) 2737 wc := testing.NewStringsWatcherC(c, w) 2738 wc.AssertChange() 2739 2740 testing.AssertStop(c, w) 2741 } 2742 2743 func (s *SecretsConsumedWatcherSuite) setupWatcher(c *gc.C) (state.StringsWatcher, *secrets.URI) { 2744 uri := secrets.NewURI() 2745 cp := state.CreateSecretParams{ 2746 Version: 1, 2747 Owner: s.owner.Tag(), 2748 UpdateSecretParams: state.UpdateSecretParams{ 2749 LeaderToken: &fakeToken{}, 2750 Data: map[string]string{"foo": "bar"}, 2751 }, 2752 } 2753 _, err := s.store.CreateSecret(uri, cp) 2754 c.Assert(err, jc.ErrorIsNil) 2755 2756 uri2 := secrets.NewURI() 2757 cp = state.CreateSecretParams{ 2758 Version: 1, 2759 Owner: s.owner.Tag(), 2760 UpdateSecretParams: state.UpdateSecretParams{ 2761 LeaderToken: &fakeToken{}, 2762 Data: map[string]string{"foo": "bar"}, 2763 }, 2764 } 2765 _, err = s.store.CreateSecret(uri2, cp) 2766 c.Assert(err, jc.ErrorIsNil) 2767 _, err = s.store.UpdateSecret(uri2, state.UpdateSecretParams{ 2768 LeaderToken: &fakeToken{}, 2769 Data: secrets.SecretData{"foo": "bar2"}, 2770 }) 2771 c.Assert(err, jc.ErrorIsNil) 2772 2773 err = s.State.SaveSecretConsumer(uri, names.NewUnitTag("mariadb/0"), &secrets.SecretConsumerMetadata{ 2774 CurrentRevision: 1, 2775 LatestRevision: 1, 2776 }) 2777 c.Assert(err, jc.ErrorIsNil) 2778 err = s.State.SaveSecretConsumer(uri2, names.NewUnitTag("mariadb/0"), &secrets.SecretConsumerMetadata{ 2779 CurrentRevision: 1, 2780 LatestRevision: 2, 2781 }) 2782 c.Assert(err, jc.ErrorIsNil) 2783 2784 w, err := s.State.WatchConsumedSecretsChanges(names.NewUnitTag("mariadb/0")) 2785 c.Assert(err, jc.ErrorIsNil) 2786 wc := testing.NewStringsWatcherC(c, w) 2787 2788 // No event until rev > 1, so just the one change. 2789 wc.AssertChange(uri2.String()) 2790 return w, uri 2791 } 2792 2793 func (s *SecretsConsumedWatcherSuite) TestWatcherStartStop(c *gc.C) { 2794 w, _ := s.setupWatcher(c) 2795 testing.AssertStop(c, w) 2796 } 2797 2798 func (s *SecretsConsumedWatcherSuite) TestWatchSingleUpdate(c *gc.C) { 2799 w, uri := s.setupWatcher(c) 2800 wc := testing.NewStringsWatcherC(c, w) 2801 defer testing.AssertStop(c, w) 2802 2803 _, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2804 LeaderToken: &fakeToken{}, 2805 Data: secrets.SecretData{"foo": "bar2"}, 2806 }) 2807 c.Assert(err, jc.ErrorIsNil) 2808 2809 wc.AssertChange(uri.String()) 2810 wc.AssertNoChange() 2811 } 2812 2813 func (s *SecretsConsumedWatcherSuite) TestWatchMultipleSecrets(c *gc.C) { 2814 w, uri := s.setupWatcher(c) 2815 wc := testing.NewStringsWatcherC(c, w) 2816 defer testing.AssertStop(c, w) 2817 2818 uri2 := secrets.NewURI() 2819 cp := state.CreateSecretParams{ 2820 Version: 1, 2821 Owner: s.owner.Tag(), 2822 UpdateSecretParams: state.UpdateSecretParams{ 2823 LeaderToken: &fakeToken{}, 2824 Data: map[string]string{"foo2": "bar"}, 2825 }, 2826 } 2827 _, err := s.store.CreateSecret(uri2, cp) 2828 c.Assert(err, jc.ErrorIsNil) 2829 2830 err = s.State.SaveSecretConsumer(uri2, names.NewUnitTag("mariadb/0"), &secrets.SecretConsumerMetadata{CurrentRevision: 1}) 2831 c.Assert(err, jc.ErrorIsNil) 2832 // No event until rev > 1. 2833 wc.AssertNoChange() 2834 2835 _, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2836 LeaderToken: &fakeToken{}, 2837 Data: secrets.SecretData{"foo": "bar2"}, 2838 }) 2839 c.Assert(err, jc.ErrorIsNil) 2840 2841 wc.AssertChange(uri.String()) 2842 wc.AssertNoChange() 2843 2844 _, err = s.store.UpdateSecret(uri2, state.UpdateSecretParams{ 2845 LeaderToken: &fakeToken{}, 2846 Data: secrets.SecretData{"foo2": "bar2"}, 2847 }) 2848 c.Assert(err, jc.ErrorIsNil) 2849 2850 wc.AssertChange(uri2.String()) 2851 wc.AssertNoChange() 2852 } 2853 2854 func (s *SecretsConsumedWatcherSuite) TestWatchConsumedDeleted(c *gc.C) { 2855 w, uri := s.setupWatcher(c) 2856 wc := testing.NewStringsWatcherC(c, w) 2857 defer testing.AssertStop(c, w) 2858 2859 err := s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 2860 CurrentRevision: 1, 2861 }) 2862 c.Assert(err, jc.ErrorIsNil) 2863 wc.AssertNoChange() 2864 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("baz"), &secrets.SecretConsumerMetadata{ 2865 CurrentRevision: 1, 2866 }) 2867 c.Assert(err, jc.ErrorIsNil) 2868 wc.AssertNoChange() 2869 2870 _, err = s.store.DeleteSecret(uri) 2871 c.Assert(err, jc.ErrorIsNil) 2872 wc.AssertChange(uri.String()) 2873 wc.AssertNoChange() 2874 } 2875 2876 type SecretsRemoteConsumerWatcherSuite struct { 2877 testing.StateSuite 2878 store state.SecretsStore 2879 2880 owner *state.Application 2881 } 2882 2883 var _ = gc.Suite(&SecretsRemoteConsumerWatcherSuite{}) 2884 2885 func (s *SecretsRemoteConsumerWatcherSuite) SetUpTest(c *gc.C) { 2886 s.StateSuite.SetUpTest(c) 2887 s.store = state.NewSecrets(s.State) 2888 s.owner = s.Factory.MakeApplication(c, nil) 2889 } 2890 2891 func (s *SecretsRemoteConsumerWatcherSuite) TestWatcherInitialEvent(c *gc.C) { 2892 w, err := s.State.WatchRemoteConsumedSecretsChanges("remote-app") 2893 c.Assert(err, jc.ErrorIsNil) 2894 wc := testing.NewStringsWatcherC(c, w) 2895 wc.AssertChange() 2896 2897 testing.AssertStop(c, w) 2898 } 2899 2900 func (s *SecretsRemoteConsumerWatcherSuite) setupWatcher(c *gc.C) (state.StringsWatcher, *secrets.URI) { 2901 uri := secrets.NewURI() 2902 cp := state.CreateSecretParams{ 2903 Version: 1, 2904 Owner: s.owner.Tag(), 2905 UpdateSecretParams: state.UpdateSecretParams{ 2906 LeaderToken: &fakeToken{}, 2907 Data: map[string]string{"foo": "bar"}, 2908 }, 2909 } 2910 _, err := s.store.CreateSecret(uri, cp) 2911 c.Assert(err, jc.ErrorIsNil) 2912 2913 uri2 := secrets.NewURI() 2914 cp = state.CreateSecretParams{ 2915 Version: 1, 2916 Owner: s.owner.Tag(), 2917 UpdateSecretParams: state.UpdateSecretParams{ 2918 LeaderToken: &fakeToken{}, 2919 Data: map[string]string{"foo": "bar"}, 2920 }, 2921 } 2922 _, err = s.store.CreateSecret(uri2, cp) 2923 c.Assert(err, jc.ErrorIsNil) 2924 _, err = s.store.UpdateSecret(uri2, state.UpdateSecretParams{ 2925 LeaderToken: &fakeToken{}, 2926 Data: secrets.SecretData{"foo": "bar2"}, 2927 }) 2928 c.Assert(err, jc.ErrorIsNil) 2929 2930 err = s.State.SaveSecretRemoteConsumer(uri, names.NewUnitTag("remote-app/0"), &secrets.SecretConsumerMetadata{ 2931 CurrentRevision: 1, 2932 LatestRevision: 1, 2933 }) 2934 c.Assert(err, jc.ErrorIsNil) 2935 err = s.State.SaveSecretRemoteConsumer(uri2, names.NewUnitTag("remote-app/0"), &secrets.SecretConsumerMetadata{ 2936 CurrentRevision: 1, 2937 LatestRevision: 2, 2938 }) 2939 c.Assert(err, jc.ErrorIsNil) 2940 2941 w, err := s.State.WatchRemoteConsumedSecretsChanges("remote-app") 2942 c.Assert(err, jc.ErrorIsNil) 2943 wc := testing.NewStringsWatcherC(c, w) 2944 2945 // No event until rev > 1, so just the one change. 2946 wc.AssertChange(uri2.String()) 2947 return w, uri 2948 } 2949 2950 func (s *SecretsRemoteConsumerWatcherSuite) TestWatcherStartStop(c *gc.C) { 2951 w, _ := s.setupWatcher(c) 2952 testing.AssertStop(c, w) 2953 } 2954 2955 func (s *SecretsRemoteConsumerWatcherSuite) TestWatchSingleUpdate(c *gc.C) { 2956 w, uri := s.setupWatcher(c) 2957 wc := testing.NewStringsWatcherC(c, w) 2958 defer testing.AssertStop(c, w) 2959 2960 _, err := s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2961 LeaderToken: &fakeToken{}, 2962 Data: secrets.SecretData{"foo": "bar2"}, 2963 }) 2964 c.Assert(err, jc.ErrorIsNil) 2965 2966 wc.AssertChange(uri.String()) 2967 wc.AssertNoChange() 2968 } 2969 2970 func (s *SecretsRemoteConsumerWatcherSuite) TestWatchMultipleSecrets(c *gc.C) { 2971 w, uri := s.setupWatcher(c) 2972 wc := testing.NewStringsWatcherC(c, w) 2973 defer testing.AssertStop(c, w) 2974 2975 uri2 := secrets.NewURI() 2976 cp := state.CreateSecretParams{ 2977 Version: 1, 2978 Owner: s.owner.Tag(), 2979 UpdateSecretParams: state.UpdateSecretParams{ 2980 LeaderToken: &fakeToken{}, 2981 Data: map[string]string{"foo2": "bar"}, 2982 }, 2983 } 2984 _, err := s.store.CreateSecret(uri2, cp) 2985 c.Assert(err, jc.ErrorIsNil) 2986 2987 err = s.State.SaveSecretRemoteConsumer(uri2, names.NewUnitTag("remote-app/0"), &secrets.SecretConsumerMetadata{CurrentRevision: 1}) 2988 c.Assert(err, jc.ErrorIsNil) 2989 // No event until rev > 1. 2990 wc.AssertNoChange() 2991 2992 _, err = s.store.UpdateSecret(uri, state.UpdateSecretParams{ 2993 LeaderToken: &fakeToken{}, 2994 Data: secrets.SecretData{"foo": "bar2"}, 2995 }) 2996 c.Assert(err, jc.ErrorIsNil) 2997 2998 wc.AssertChange(uri.String()) 2999 wc.AssertNoChange() 3000 3001 _, err = s.store.UpdateSecret(uri2, state.UpdateSecretParams{ 3002 LeaderToken: &fakeToken{}, 3003 Data: secrets.SecretData{"foo2": "bar2"}, 3004 }) 3005 c.Assert(err, jc.ErrorIsNil) 3006 3007 wc.AssertChange(uri2.String()) 3008 wc.AssertNoChange() 3009 } 3010 3011 func (s *SecretsRemoteConsumerWatcherSuite) TestWatchConsumedDeleted(c *gc.C) { 3012 w, uri := s.setupWatcher(c) 3013 wc := testing.NewStringsWatcherC(c, w) 3014 defer testing.AssertStop(c, w) 3015 3016 err := s.State.SaveSecretRemoteConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3017 CurrentRevision: 1, 3018 }) 3019 c.Assert(err, jc.ErrorIsNil) 3020 wc.AssertNoChange() 3021 err = s.State.SaveSecretRemoteConsumer(uri, names.NewApplicationTag("baz"), &secrets.SecretConsumerMetadata{ 3022 CurrentRevision: 1, 3023 }) 3024 c.Assert(err, jc.ErrorIsNil) 3025 wc.AssertNoChange() 3026 3027 _, err = s.store.DeleteSecret(uri) 3028 c.Assert(err, jc.ErrorIsNil) 3029 wc.AssertChange(uri.String()) 3030 wc.AssertNoChange() 3031 } 3032 3033 type SecretsObsoleteWatcherSuite struct { 3034 testing.StateSuite 3035 store state.SecretsStore 3036 3037 ownerApp *state.Application 3038 ownerUnit *state.Unit 3039 } 3040 3041 var _ = gc.Suite(&SecretsObsoleteWatcherSuite{}) 3042 3043 func (s *SecretsObsoleteWatcherSuite) SetUpTest(c *gc.C) { 3044 s.StateSuite.SetUpTest(c) 3045 s.store = state.NewSecrets(s.State) 3046 s.ownerApp = s.Factory.MakeApplication(c, nil) 3047 s.ownerUnit = s.Factory.MakeUnit(c, &factory.UnitParams{Application: s.ownerApp}) 3048 } 3049 3050 func (s *SecretsObsoleteWatcherSuite) setupWatcher(c *gc.C, forAutoPrune bool) (state.StringsWatcher, *secrets.URI) { 3051 uri := secrets.NewURI() 3052 cp := state.CreateSecretParams{ 3053 Version: 1, 3054 Owner: s.ownerApp.Tag(), 3055 UpdateSecretParams: state.UpdateSecretParams{ 3056 LeaderToken: &fakeToken{}, 3057 Data: map[string]string{"foo": "bar"}, 3058 }, 3059 } 3060 if forAutoPrune { 3061 cp.Owner = names.NewModelTag(s.State.ModelUUID()) 3062 } 3063 _, err := s.store.CreateSecret(uri, cp) 3064 c.Assert(err, jc.ErrorIsNil) 3065 var w state.StringsWatcher 3066 if forAutoPrune { 3067 w, err = s.store.WatchRevisionsToPrune( 3068 []names.Tag{names.NewModelTag(s.State.ModelUUID())}, 3069 ) 3070 } else { 3071 w, err = s.store.WatchObsolete( 3072 []names.Tag{s.ownerApp.Tag(), s.ownerUnit.Tag()}, 3073 ) 3074 } 3075 c.Assert(err, jc.ErrorIsNil) 3076 3077 wc := testing.NewStringsWatcherC(c, w) 3078 wc.AssertChange() 3079 wc.AssertNoChange() 3080 return w, uri 3081 } 3082 3083 func (s *SecretsObsoleteWatcherSuite) TestWatcherStartStop(c *gc.C) { 3084 w, _ := s.setupWatcher(c, false) 3085 testing.AssertStop(c, w) 3086 } 3087 3088 func (s *SecretsObsoleteWatcherSuite) TestWatchObsoleteRevisions(c *gc.C) { 3089 w, uri := s.setupWatcher(c, false) 3090 wc := testing.NewStringsWatcherC(c, w) 3091 defer testing.AssertStop(c, w) 3092 3093 err := s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3094 CurrentRevision: 1, 3095 }) 3096 c.Assert(err, jc.ErrorIsNil) 3097 wc.AssertNoChange() 3098 3099 p := state.UpdateSecretParams{ 3100 LeaderToken: &fakeToken{}, 3101 Data: map[string]string{"foo": "bar2"}, 3102 } 3103 _, err = s.store.UpdateSecret(uri, p) 3104 c.Assert(err, jc.ErrorIsNil) 3105 wc.AssertNoChange() 3106 3107 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo2"), &secrets.SecretConsumerMetadata{ 3108 CurrentRevision: 2, 3109 }) 3110 c.Assert(err, jc.ErrorIsNil) 3111 wc.AssertNoChange() 3112 3113 // The previous consumer of rev 1 now uses rev 2; rev 1 is orphaned. 3114 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3115 CurrentRevision: 2, 3116 }) 3117 c.Assert(err, jc.ErrorIsNil) 3118 wc.AssertChange(uri.String() + "/1") 3119 wc.AssertNoChange() 3120 3121 // The latest added revision is never obsolete. 3122 p = state.UpdateSecretParams{ 3123 LeaderToken: &fakeToken{}, 3124 Data: map[string]string{"foo": "bar3"}, 3125 } 3126 _, err = s.store.UpdateSecret(uri, p) 3127 c.Assert(err, jc.ErrorIsNil) 3128 wc.AssertChange(uri.String() + "/1") 3129 wc.AssertNoChange() 3130 3131 // New revision 4 added, so rev 3 is now also obsolete. 3132 p = state.UpdateSecretParams{ 3133 LeaderToken: &fakeToken{}, 3134 Data: map[string]string{"foo": "bar4"}, 3135 } 3136 _, err = s.store.UpdateSecret(uri, p) 3137 c.Assert(err, jc.ErrorIsNil) 3138 wc.AssertChange(uri.String()+"/1", uri.String()+"/3") 3139 wc.AssertNoChange() 3140 } 3141 3142 func (s *SecretsObsoleteWatcherSuite) TestWatchObsoleteRevisionsToPrune(c *gc.C) { 3143 w, uri := s.setupWatcher(c, true) 3144 wc := testing.NewStringsWatcherC(c, w) 3145 defer testing.AssertStop(c, w) 3146 3147 err := s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3148 CurrentRevision: 1, 3149 }) 3150 c.Assert(err, jc.ErrorIsNil) 3151 wc.AssertNoChange() 3152 3153 p := state.UpdateSecretParams{ 3154 LeaderToken: &fakeToken{}, 3155 Data: map[string]string{"foo": "bar2"}, 3156 } 3157 _, err = s.store.UpdateSecret(uri, p) 3158 c.Assert(err, jc.ErrorIsNil) 3159 // No change because AutoPrune is not turned on. 3160 wc.AssertNoChange() 3161 3162 // The previous consumer of rev 1 now uses rev 2; rev 1 is orphaned. 3163 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3164 CurrentRevision: 2, 3165 }) 3166 c.Assert(err, jc.ErrorIsNil) 3167 // No change because AutoPrune is not turned on. 3168 wc.AssertNoChange() 3169 3170 // turn on AutoPrune. 3171 p = state.UpdateSecretParams{ 3172 AutoPrune: ptr(true), 3173 LeaderToken: &fakeToken{}, 3174 Data: map[string]string{"foo": "bar3"}, 3175 } 3176 _, err = s.store.UpdateSecret(uri, p) 3177 c.Assert(err, jc.ErrorIsNil) 3178 wc.AssertChange(uri.String() + "/1") 3179 wc.AssertNoChange() 3180 3181 // New revision 4 added, so rev 3 is now also obsolete. 3182 p = state.UpdateSecretParams{ 3183 LeaderToken: &fakeToken{}, 3184 Data: map[string]string{"foo": "bar4"}, 3185 } 3186 _, err = s.store.UpdateSecret(uri, p) 3187 c.Assert(err, jc.ErrorIsNil) 3188 wc.AssertChange(uri.String()+"/1", uri.String()+"/3") 3189 wc.AssertNoChange() 3190 3191 // The previous consumer of rev 1 now uses rev 2; rev 1 is orphaned. 3192 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3193 CurrentRevision: 4, 3194 }) 3195 c.Assert(err, jc.ErrorIsNil) 3196 wc.AssertChange(uri.String()+"/1", uri.String()+"/2", uri.String()+"/3") 3197 wc.AssertNoChange() 3198 } 3199 3200 func (s *SecretsObsoleteWatcherSuite) TestWatchOwnedDeleted(c *gc.C) { 3201 w, uri := s.setupWatcher(c, false) 3202 wc := testing.NewStringsWatcherC(c, w) 3203 defer testing.AssertStop(c, w) 3204 3205 owner2 := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 3206 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{ 3207 Name: "wordpress", 3208 }), 3209 }) 3210 uri2 := secrets.NewURI() 3211 cp := state.CreateSecretParams{ 3212 Version: 1, 3213 Owner: owner2.Tag(), 3214 UpdateSecretParams: state.UpdateSecretParams{ 3215 LeaderToken: &fakeToken{}, 3216 Data: map[string]string{"foo": "bar"}, 3217 }, 3218 } 3219 _, err := s.store.CreateSecret(uri2, cp) 3220 c.Assert(err, jc.ErrorIsNil) 3221 3222 uri3 := secrets.NewURI() 3223 cp = state.CreateSecretParams{ 3224 Version: 1, 3225 Owner: s.ownerUnit.Tag(), 3226 UpdateSecretParams: state.UpdateSecretParams{ 3227 LeaderToken: &fakeToken{}, 3228 Data: map[string]string{"foo": "bar"}, 3229 }, 3230 } 3231 _, err = s.store.CreateSecret(uri3, cp) 3232 c.Assert(err, jc.ErrorIsNil) 3233 3234 _, err = s.store.DeleteSecret(uri) 3235 c.Assert(err, jc.ErrorIsNil) 3236 wc.AssertChange(uri.String()) 3237 wc.AssertNoChange() 3238 3239 _, err = s.store.DeleteSecret(uri2) 3240 c.Assert(err, jc.ErrorIsNil) 3241 wc.AssertNoChange() 3242 3243 _, err = s.store.DeleteSecret(uri3) 3244 c.Assert(err, jc.ErrorIsNil) 3245 wc.AssertChange(uri3.String()) 3246 wc.AssertNoChange() 3247 } 3248 3249 func (s *SecretsObsoleteWatcherSuite) TestWatchDeletedSupercedesObsolete(c *gc.C) { 3250 w, uri := s.setupWatcher(c, false) 3251 wc := testing.NewStringsWatcherC(c, w) 3252 defer testing.AssertStop(c, w) 3253 3254 err := s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3255 CurrentRevision: 1, 3256 }) 3257 c.Assert(err, jc.ErrorIsNil) 3258 wc.AssertNoChange() 3259 3260 p := state.UpdateSecretParams{ 3261 LeaderToken: &fakeToken{}, 3262 Data: map[string]string{"foo": "bar2"}, 3263 } 3264 _, err = s.store.UpdateSecret(uri, p) 3265 c.Assert(err, jc.ErrorIsNil) 3266 wc.AssertNoChange() 3267 3268 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo2"), &secrets.SecretConsumerMetadata{ 3269 CurrentRevision: 2, 3270 }) 3271 c.Assert(err, jc.ErrorIsNil) 3272 wc.AssertNoChange() 3273 3274 // The previous consumer of rev 1 now uses rev 2; rev 1 is orphaned. 3275 err = s.State.SaveSecretConsumer(uri, names.NewApplicationTag("foo"), &secrets.SecretConsumerMetadata{ 3276 CurrentRevision: 2, 3277 }) 3278 c.Assert(err, jc.ErrorIsNil) 3279 3280 // Deleting the secret removes any pending orphaned changes. 3281 _, err = s.store.DeleteSecret(uri) 3282 c.Assert(err, jc.ErrorIsNil) 3283 wc.AssertChange(uri.String()) 3284 wc.AssertNoChange() 3285 }