github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/secretbackends_test.go (about) 1 // Copyright 2022 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "sort" 8 "time" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/core/secrets" 15 "github.com/juju/juju/core/watcher" 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/state/testing" 18 ) 19 20 type SecretBackendsSuite struct { 21 testing.StateSuite 22 storage state.SecretBackendsStorage 23 store state.SecretsStore 24 } 25 26 var _ = gc.Suite(&SecretBackendsSuite{}) 27 28 func (s *SecretBackendsSuite) SetUpTest(c *gc.C) { 29 s.StateSuite.SetUpTest(c) 30 s.storage = state.NewSecretBackends(s.State) 31 s.store = state.NewSecrets(s.State) 32 } 33 34 func (s *SecretBackendsSuite) TestCreate(c *gc.C) { 35 now := s.Clock.Now().Round(time.Second).UTC() 36 next := now.Add(time.Minute).Round(time.Second).UTC() 37 config := map[string]interface{}{"foo.key": "bar"} 38 p := state.CreateSecretBackendParams{ 39 Name: "myvault", 40 BackendType: "vault", 41 TokenRotateInterval: ptr(666 * time.Minute), 42 NextRotateTime: ptr(next), 43 Config: config, 44 } 45 id, err := s.storage.CreateSecretBackend(p) 46 c.Assert(id, gc.Not(gc.Equals), "") 47 c.Assert(err, jc.ErrorIsNil) 48 backend, err := s.storage.GetSecretBackend("myvault") 49 c.Assert(err, jc.ErrorIsNil) 50 c.Assert(backend.ID, gc.NotNil) 51 backend.ID = "" 52 c.Assert(backend, jc.DeepEquals, &secrets.SecretBackend{ 53 Name: "myvault", 54 BackendType: "vault", 55 TokenRotateInterval: ptr(666 * time.Minute), 56 Config: config, 57 }) 58 name, nextTime := state.GetSecretBackendNextRotateInfo(c, s.State, id) 59 c.Assert(name, gc.Equals, "myvault") 60 c.Assert(nextTime, gc.Equals, next) 61 62 _, err = s.storage.CreateSecretBackend(p) 63 c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) 64 65 p.Name = "another" 66 p.ID = id 67 _, err = s.storage.CreateSecretBackend(p) 68 c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) 69 } 70 71 func (s *SecretBackendsSuite) TestGetNotFound(c *gc.C) { 72 _, err := s.storage.GetSecretBackend("myvault") 73 c.Check(err, jc.Satisfies, errors.IsNotFound) 74 } 75 76 func (s *SecretBackendsSuite) TestList(c *gc.C) { 77 now := s.Clock.Now().Round(time.Second).UTC() 78 next := now.Add(time.Minute).Round(time.Second).UTC() 79 config := map[string]interface{}{"foo.key": "bar"} 80 p := state.CreateSecretBackendParams{ 81 Name: "myvault", 82 BackendType: "vault", 83 TokenRotateInterval: ptr(666 * time.Minute), 84 NextRotateTime: ptr(next), 85 Config: config, 86 } 87 _, err := s.storage.CreateSecretBackend(p) 88 c.Assert(err, jc.ErrorIsNil) 89 p2 := state.CreateSecretBackendParams{ 90 Name: "myk8s", 91 BackendType: "kubernetes", 92 Config: config, 93 } 94 _, err = s.storage.CreateSecretBackend(p2) 95 c.Assert(err, jc.ErrorIsNil) 96 backends, err := s.storage.ListSecretBackends() 97 c.Assert(err, jc.ErrorIsNil) 98 sort.Slice(backends, func(i, j int) bool { 99 return backends[i].Name < backends[j].Name 100 }) 101 102 mc := jc.NewMultiChecker() 103 mc.AddExpr(`_.ID`, gc.NotNil) 104 c.Assert(backends, mc, []*secrets.SecretBackend{{ 105 Name: "myk8s", 106 BackendType: "kubernetes", 107 Config: config, 108 }, { 109 Name: "myvault", 110 BackendType: "vault", 111 TokenRotateInterval: ptr(666 * time.Minute), 112 Config: config, 113 }}) 114 } 115 116 func (s *SecretBackendsSuite) TestRemove(c *gc.C) { 117 p := state.CreateSecretBackendParams{ 118 Name: "myvault", 119 BackendType: "vault", 120 } 121 _, err := s.storage.CreateSecretBackend(p) 122 c.Assert(err, jc.ErrorIsNil) 123 124 err = s.storage.DeleteSecretBackend("myvault", false) 125 c.Assert(err, jc.ErrorIsNil) 126 _, err = s.storage.GetSecretBackend("myvault") 127 c.Check(err, jc.Satisfies, errors.IsNotFound) 128 err = s.storage.DeleteSecretBackend("myvault", false) 129 c.Assert(err, jc.ErrorIsNil) 130 } 131 132 func (s *SecretBackendsSuite) TestRemoveWithRevisionsFails(c *gc.C) { 133 p := state.CreateSecretBackendParams{ 134 Name: "myvault", 135 BackendType: "vault", 136 } 137 _, err := s.storage.CreateSecretBackend(p) 138 c.Assert(err, jc.ErrorIsNil) 139 b, err := s.storage.GetSecretBackend("myvault") 140 c.Assert(err, jc.ErrorIsNil) 141 142 owner := s.Factory.MakeApplication(c, nil) 143 uri := secrets.NewURI() 144 sp := state.CreateSecretParams{ 145 Version: 1, 146 Owner: owner.Tag(), 147 UpdateSecretParams: state.UpdateSecretParams{ 148 LeaderToken: &fakeToken{}, 149 ValueRef: &secrets.ValueRef{ 150 BackendID: b.ID, 151 RevisionID: "rev-id", 152 }, 153 }, 154 } 155 secrets := state.NewSecrets(s.State) 156 _, err = secrets.CreateSecret(uri, sp) 157 c.Assert(err, jc.ErrorIsNil) 158 159 err = s.storage.DeleteSecretBackend("myvault", false) 160 c.Assert(err, jc.Satisfies, errors.IsNotSupported) 161 count, err := state.SecretBackendRefCount(s.State, b.ID) 162 c.Assert(err, jc.ErrorIsNil) 163 c.Assert(count, gc.Equals, 1) 164 } 165 166 func (s *SecretBackendsSuite) TestRemoveWithRevisionsForce(c *gc.C) { 167 p := state.CreateSecretBackendParams{ 168 Name: "myvault", 169 BackendType: "vault", 170 } 171 _, err := s.storage.CreateSecretBackend(p) 172 c.Assert(err, jc.ErrorIsNil) 173 b, err := s.storage.GetSecretBackend("myvault") 174 c.Assert(err, jc.ErrorIsNil) 175 176 owner := s.Factory.MakeApplication(c, nil) 177 uri := secrets.NewURI() 178 sp := state.CreateSecretParams{ 179 Version: 1, 180 Owner: owner.Tag(), 181 UpdateSecretParams: state.UpdateSecretParams{ 182 LeaderToken: &fakeToken{}, 183 ValueRef: &secrets.ValueRef{ 184 BackendID: b.ID, 185 RevisionID: "rev-id", 186 }, 187 }, 188 } 189 secrets := state.NewSecrets(s.State) 190 _, err = secrets.CreateSecret(uri, sp) 191 c.Assert(err, jc.ErrorIsNil) 192 193 count, err := state.SecretBackendRefCount(s.State, b.ID) 194 c.Assert(err, jc.ErrorIsNil) 195 c.Assert(count, gc.Equals, 1) 196 197 err = s.storage.DeleteSecretBackend("myvault", true) 198 c.Assert(err, jc.ErrorIsNil) 199 _, err = state.SecretBackendRefCount(s.State, b.ID) 200 c.Assert(err, jc.Satisfies, errors.IsNotFound) 201 _, err = s.storage.GetSecretBackend("myvault") 202 c.Check(err, jc.Satisfies, errors.IsNotFound) 203 } 204 205 func (s *SecretBackendsSuite) TestDeleteSecretUpdatesRefCount(c *gc.C) { 206 p := state.CreateSecretBackendParams{ 207 Name: "myvault", 208 BackendType: "vault", 209 } 210 _, err := s.storage.CreateSecretBackend(p) 211 c.Assert(err, jc.ErrorIsNil) 212 b, err := s.storage.GetSecretBackend("myvault") 213 c.Assert(err, jc.ErrorIsNil) 214 215 owner := s.Factory.MakeApplication(c, nil) 216 uri := secrets.NewURI() 217 cp := state.CreateSecretParams{ 218 Version: 1, 219 Owner: owner.Tag(), 220 UpdateSecretParams: state.UpdateSecretParams{ 221 LeaderToken: &fakeToken{}, 222 ValueRef: &secrets.ValueRef{ 223 BackendID: b.ID, 224 RevisionID: "rev-id", 225 }, 226 }, 227 } 228 secretStore := state.NewSecrets(s.State) 229 _, err = secretStore.CreateSecret(uri, cp) 230 c.Assert(err, jc.ErrorIsNil) 231 _, err = secretStore.UpdateSecret(uri, state.UpdateSecretParams{ 232 LeaderToken: &fakeToken{}, 233 ValueRef: &secrets.ValueRef{ 234 BackendID: b.ID, 235 RevisionID: "rev-id2", 236 }, 237 }) 238 c.Assert(err, jc.ErrorIsNil) 239 count, err := state.SecretBackendRefCount(s.State, b.ID) 240 c.Assert(err, jc.ErrorIsNil) 241 c.Assert(count, gc.Equals, 2) 242 243 _, err = secretStore.DeleteSecret(uri) 244 c.Assert(err, jc.ErrorIsNil) 245 246 count, err = state.SecretBackendRefCount(s.State, b.ID) 247 c.Assert(err, jc.ErrorIsNil) 248 c.Assert(count, gc.Equals, 0) 249 250 err = s.storage.DeleteSecretBackend("myvault", false) 251 c.Assert(err, jc.ErrorIsNil) 252 } 253 254 func (s *SecretBackendsSuite) TestDeleteRevisionsUpdatesRefCount(c *gc.C) { 255 p := state.CreateSecretBackendParams{ 256 Name: "myvault", 257 BackendType: "vault", 258 } 259 _, err := s.storage.CreateSecretBackend(p) 260 c.Assert(err, jc.ErrorIsNil) 261 b, err := s.storage.GetSecretBackend("myvault") 262 c.Assert(err, jc.ErrorIsNil) 263 264 owner := s.Factory.MakeApplication(c, nil) 265 uri := secrets.NewURI() 266 cp := state.CreateSecretParams{ 267 Version: 1, 268 Owner: owner.Tag(), 269 UpdateSecretParams: state.UpdateSecretParams{ 270 LeaderToken: &fakeToken{}, 271 ValueRef: &secrets.ValueRef{ 272 BackendID: b.ID, 273 RevisionID: "rev-id", 274 }, 275 }, 276 } 277 secretStore := state.NewSecrets(s.State) 278 _, err = secretStore.CreateSecret(uri, cp) 279 c.Assert(err, jc.ErrorIsNil) 280 _, err = secretStore.UpdateSecret(uri, state.UpdateSecretParams{ 281 LeaderToken: &fakeToken{}, 282 ValueRef: &secrets.ValueRef{ 283 BackendID: b.ID, 284 RevisionID: "rev-id2", 285 }, 286 }) 287 c.Assert(err, jc.ErrorIsNil) 288 count, err := state.SecretBackendRefCount(s.State, b.ID) 289 c.Assert(err, jc.ErrorIsNil) 290 c.Assert(count, gc.Equals, 2) 291 292 _, err = secretStore.DeleteSecret(uri, 1) 293 c.Assert(err, jc.ErrorIsNil) 294 295 count, err = state.SecretBackendRefCount(s.State, b.ID) 296 c.Assert(err, jc.ErrorIsNil) 297 c.Assert(count, gc.Equals, 1) 298 299 _, err = secretStore.DeleteSecret(uri, 2) 300 c.Assert(err, jc.ErrorIsNil) 301 302 count, err = state.SecretBackendRefCount(s.State, b.ID) 303 c.Assert(err, jc.ErrorIsNil) 304 c.Assert(count, gc.Equals, 0) 305 306 err = s.storage.DeleteSecretBackend("myvault", false) 307 c.Assert(err, jc.ErrorIsNil) 308 } 309 310 func (s *SecretBackendsSuite) TestUpdate(c *gc.C) { 311 p := state.CreateSecretBackendParams{ 312 Name: "myvault", 313 BackendType: "vault", 314 Config: map[string]interface{}{"foo.key": "bar"}, 315 } 316 _, err := s.storage.CreateSecretBackend(p) 317 c.Assert(err, jc.ErrorIsNil) 318 b, err := s.storage.GetSecretBackend("myvault") 319 c.Assert(err, jc.ErrorIsNil) 320 321 now := s.Clock.Now().Round(time.Second).UTC() 322 next := now.Add(time.Minute).Round(time.Second).UTC() 323 u := state.UpdateSecretBackendParams{ 324 ID: b.ID, 325 TokenRotateInterval: ptr(666 * time.Second), 326 NextRotateTime: ptr(next), 327 Config: map[string]interface{}{"foo": "bar2"}, 328 } 329 err = s.storage.UpdateSecretBackend(u) 330 c.Assert(err, jc.ErrorIsNil) 331 b, err = s.storage.GetSecretBackend("myvault") 332 c.Assert(err, jc.ErrorIsNil) 333 c.Assert(b, jc.DeepEquals, &secrets.SecretBackend{ 334 ID: b.ID, 335 Name: "myvault", 336 BackendType: "vault", 337 TokenRotateInterval: ptr(666 * time.Second), 338 Config: map[string]interface{}{"foo": "bar2"}, 339 }) 340 name, nextTime := state.GetSecretBackendNextRotateInfo(c, s.State, b.ID) 341 c.Assert(name, gc.Equals, "myvault") 342 c.Assert(nextTime, gc.Equals, next) 343 } 344 345 func (s *SecretBackendsSuite) TestUpdateName(c *gc.C) { 346 now := s.Clock.Now().Round(time.Second).UTC() 347 next := now.Add(time.Minute).Round(time.Second).UTC() 348 p := state.CreateSecretBackendParams{ 349 Name: "myvault", 350 BackendType: "vault", 351 TokenRotateInterval: ptr(666 * time.Second), 352 NextRotateTime: ptr(next), 353 Config: map[string]interface{}{"foo.key": "bar"}, 354 } 355 _, err := s.storage.CreateSecretBackend(p) 356 c.Assert(err, jc.ErrorIsNil) 357 b, err := s.storage.GetSecretBackend("myvault") 358 c.Assert(err, jc.ErrorIsNil) 359 360 u := state.UpdateSecretBackendParams{ 361 ID: b.ID, 362 NameChange: ptr("myvault2"), 363 Config: map[string]interface{}{"foo": "bar2"}, 364 } 365 err = s.storage.UpdateSecretBackend(u) 366 c.Assert(err, jc.ErrorIsNil) 367 b, err = s.storage.GetSecretBackend("myvault2") 368 c.Assert(err, jc.ErrorIsNil) 369 c.Assert(b, jc.DeepEquals, &secrets.SecretBackend{ 370 ID: b.ID, 371 Name: "myvault2", 372 BackendType: "vault", 373 TokenRotateInterval: ptr(666 * time.Second), 374 Config: map[string]interface{}{"foo": "bar2"}, 375 }) 376 name, nextTime := state.GetSecretBackendNextRotateInfo(c, s.State, b.ID) 377 c.Assert(name, gc.Equals, "myvault2") 378 c.Assert(nextTime, gc.Equals, next) 379 } 380 381 func (s *SecretBackendsSuite) TestUpdateNameForInUseBackend(c *gc.C) { 382 now := s.Clock.Now().Round(time.Second).UTC() 383 next := now.Add(time.Minute).Round(time.Second).UTC() 384 p := state.CreateSecretBackendParams{ 385 Name: "myvault", 386 BackendType: "vault", 387 TokenRotateInterval: ptr(666 * time.Second), 388 NextRotateTime: ptr(next), 389 Config: map[string]interface{}{"foo.key": "bar"}, 390 } 391 _, err := s.storage.CreateSecretBackend(p) 392 c.Assert(err, jc.ErrorIsNil) 393 b, err := s.storage.GetSecretBackend("myvault") 394 c.Assert(err, jc.ErrorIsNil) 395 396 owner := s.Factory.MakeApplication(c, nil) 397 uri := secrets.NewURI() 398 cp := state.CreateSecretParams{ 399 Version: 1, 400 Owner: owner.Tag(), 401 UpdateSecretParams: state.UpdateSecretParams{ 402 LeaderToken: &fakeToken{}, 403 ValueRef: &secrets.ValueRef{BackendID: b.ID}, 404 }, 405 } 406 _, err = s.store.CreateSecret(uri, cp) 407 c.Assert(err, jc.ErrorIsNil) 408 409 u := state.UpdateSecretBackendParams{ 410 ID: b.ID, 411 NameChange: ptr("myvault2"), 412 Config: map[string]interface{}{"foo": "bar2"}, 413 } 414 err = s.storage.UpdateSecretBackend(u) 415 c.Assert(err, gc.ErrorMatches, `cannot rename a secret backend that is in use`) 416 } 417 418 func (s *SecretBackendsSuite) TestUpdateNameDuplicate(c *gc.C) { 419 p := state.CreateSecretBackendParams{ 420 Name: "myvault", 421 BackendType: "vault", 422 Config: map[string]interface{}{"foo.key": "bar"}, 423 } 424 _, err := s.storage.CreateSecretBackend(p) 425 c.Assert(err, jc.ErrorIsNil) 426 p.Name = "myvault2" 427 _, err = s.storage.CreateSecretBackend(p) 428 c.Assert(err, jc.ErrorIsNil) 429 430 b, err := s.storage.GetSecretBackend("myvault") 431 c.Assert(err, jc.ErrorIsNil) 432 433 u := state.UpdateSecretBackendParams{ 434 ID: b.ID, 435 NameChange: ptr("myvault2"), 436 Config: map[string]interface{}{"foo": "bar2"}, 437 } 438 err = s.storage.UpdateSecretBackend(u) 439 c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) 440 } 441 442 func (s *SecretBackendsSuite) TestUpdateResetRotationInterval(c *gc.C) { 443 now := s.Clock.Now().Round(time.Second).UTC() 444 next := now.Add(time.Minute).Round(time.Second).UTC() 445 p := state.CreateSecretBackendParams{ 446 Name: "myvault", 447 BackendType: "vault", 448 TokenRotateInterval: ptr(666 * time.Second), 449 NextRotateTime: ptr(next), 450 Config: map[string]interface{}{"foo.key": "bar"}, 451 } 452 _, err := s.storage.CreateSecretBackend(p) 453 c.Assert(err, jc.ErrorIsNil) 454 b, err := s.storage.GetSecretBackend("myvault") 455 c.Assert(err, jc.ErrorIsNil) 456 457 u := state.UpdateSecretBackendParams{ 458 ID: b.ID, 459 TokenRotateInterval: ptr(0 * time.Second), 460 Config: map[string]interface{}{"foo": "bar2"}, 461 } 462 err = s.storage.UpdateSecretBackend(u) 463 c.Assert(err, jc.ErrorIsNil) 464 b, err = s.storage.GetSecretBackend("myvault") 465 c.Assert(err, jc.ErrorIsNil) 466 c.Assert(b, jc.DeepEquals, &secrets.SecretBackend{ 467 ID: b.ID, 468 Name: "myvault", 469 BackendType: "vault", 470 Config: map[string]interface{}{"foo": "bar2"}, 471 }) 472 } 473 474 func (s *SecretBackendsSuite) TestSecretBackendRotated(c *gc.C) { 475 config := map[string]interface{}{"foo.key": "bar"} 476 now := s.Clock.Now().Round(time.Second).UTC() 477 next := now.Add(time.Minute).Round(time.Second).UTC() 478 cp := state.CreateSecretBackendParams{ 479 Name: "myvault", 480 BackendType: "vault", 481 TokenRotateInterval: ptr(666 * time.Minute), 482 NextRotateTime: ptr(next), 483 Config: config, 484 } 485 id, err := s.storage.CreateSecretBackend(cp) 486 c.Assert(err, jc.ErrorIsNil) 487 next2 := now.Add(time.Hour).Round(time.Second).UTC() 488 err = s.storage.SecretBackendRotated(id, next2) 489 c.Assert(err, jc.ErrorIsNil) 490 491 _, nextTime := state.GetSecretBackendNextRotateInfo(c, s.State, id) 492 c.Assert(nextTime, gc.Equals, next2) 493 } 494 495 func (s *SecretBackendsSuite) TestSecretBackendRotatedConcurrent(c *gc.C) { 496 config := map[string]interface{}{"foo.key": "bar"} 497 now := s.Clock.Now().Round(time.Second).UTC() 498 next := now.Add(time.Minute).Round(time.Second).UTC() 499 cp := state.CreateSecretBackendParams{ 500 Name: "myvault", 501 BackendType: "vault", 502 TokenRotateInterval: ptr(666 * time.Minute), 503 NextRotateTime: ptr(next), 504 Config: config, 505 } 506 id, err := s.storage.CreateSecretBackend(cp) 507 c.Assert(err, jc.ErrorIsNil) 508 509 later := now.Add(time.Hour).Round(time.Second).UTC() 510 later2 := now.Add(2 * time.Hour).Round(time.Second).UTC() 511 state.SetBeforeHooks(c, s.State, func() { 512 err := s.storage.SecretBackendRotated(id, later) 513 c.Assert(err, jc.ErrorIsNil) 514 }) 515 516 err = s.storage.SecretBackendRotated(id, later2) 517 c.Assert(err, jc.ErrorIsNil) 518 519 _, nextTime := state.GetSecretBackendNextRotateInfo(c, s.State, id) 520 c.Assert(nextTime, gc.Equals, later) 521 } 522 523 type SecretBackendWatcherSuite struct { 524 testing.StateSuite 525 storage state.SecretBackendsStorage 526 } 527 528 var _ = gc.Suite(&SecretBackendWatcherSuite{}) 529 530 func (s *SecretBackendWatcherSuite) SetUpTest(c *gc.C) { 531 s.StateSuite.SetUpTest(c) 532 s.storage = state.NewSecretBackends(s.State) 533 } 534 535 func (s *SecretBackendWatcherSuite) setupWatcher(c *gc.C) (state.SecretBackendRotateWatcher, string) { 536 now := s.Clock.Now().Round(time.Second).UTC() 537 next := now.Add(time.Minute).Round(time.Second).UTC() 538 cp := state.CreateSecretBackendParams{ 539 Name: "myvault", 540 BackendType: "vault", 541 TokenRotateInterval: ptr(666 * time.Minute), 542 NextRotateTime: ptr(next), 543 Config: map[string]interface{}{"foo.key": "bar"}, 544 } 545 id, err := s.storage.CreateSecretBackend(cp) 546 c.Assert(err, jc.ErrorIsNil) 547 w, err := s.State.WatchSecretBackendRotationChanges() 548 c.Assert(err, jc.ErrorIsNil) 549 550 wc := testing.NewSecretBackendRotateWatcherC(c, w) 551 wc.AssertChange(watcher.SecretBackendRotateChange{ 552 ID: id, 553 Name: "myvault", 554 NextTriggerTime: next, 555 }) 556 wc.AssertNoChange() 557 return w, id 558 } 559 560 func (s *SecretBackendWatcherSuite) TestWatchInitialEvent(c *gc.C) { 561 w, _ := s.setupWatcher(c) 562 testing.AssertStop(c, w) 563 } 564 565 func (s *SecretBackendWatcherSuite) TestWatchSingleUpdate(c *gc.C) { 566 w, id := s.setupWatcher(c) 567 wc := testing.NewSecretBackendRotateWatcherC(c, w) 568 defer testing.AssertStop(c, w) 569 570 now := s.Clock.Now().Round(time.Second).UTC() 571 next := now.Add(2 * time.Hour).Round(time.Second).UTC() 572 err := s.storage.SecretBackendRotated(id, next) 573 c.Assert(err, jc.ErrorIsNil) 574 575 wc.AssertChange(watcher.SecretBackendRotateChange{ 576 ID: id, 577 Name: "myvault", 578 NextTriggerTime: next, 579 }) 580 wc.AssertNoChange() 581 } 582 583 func (s *SecretBackendWatcherSuite) TestWatchDelete(c *gc.C) { 584 w, id := s.setupWatcher(c) 585 wc := testing.NewSecretBackendRotateWatcherC(c, w) 586 defer testing.AssertStop(c, w) 587 588 err := s.storage.UpdateSecretBackend(state.UpdateSecretBackendParams{ 589 ID: id, 590 TokenRotateInterval: ptr(0 * time.Second), 591 }) 592 c.Assert(err, jc.ErrorIsNil) 593 594 wc.AssertChange(watcher.SecretBackendRotateChange{ 595 ID: id, 596 Name: "myvault", 597 }) 598 wc.AssertNoChange() 599 } 600 601 func (s *SecretBackendWatcherSuite) TestWatchMultipleUpdatesSameBackend(c *gc.C) { 602 w, id := s.setupWatcher(c) 603 wc := testing.NewSecretBackendRotateWatcherC(c, w) 604 defer testing.AssertStop(c, w) 605 606 // TODO(quiescence): these two changes should be one event. 607 now := s.Clock.Now().Round(time.Second).UTC() 608 next := now.Add(time.Minute).Round(time.Second).UTC() 609 err := s.storage.SecretBackendRotated(id, next) 610 c.Assert(err, jc.ErrorIsNil) 611 wc.AssertChange(watcher.SecretBackendRotateChange{ 612 ID: id, 613 Name: "myvault", 614 NextTriggerTime: next, 615 }) 616 next2 := now.Add(time.Hour).Round(time.Second).UTC() 617 err = s.storage.SecretBackendRotated(id, next2) 618 c.Assert(err, jc.ErrorIsNil) 619 620 wc.AssertChange(watcher.SecretBackendRotateChange{ 621 ID: id, 622 Name: "myvault", 623 NextTriggerTime: next2, 624 }) 625 wc.AssertNoChange() 626 } 627 628 func (s *SecretBackendWatcherSuite) TestWatchMultipleUpdatesSameBackendDeleted(c *gc.C) { 629 w, id := s.setupWatcher(c) 630 wc := testing.NewSecretBackendRotateWatcherC(c, w) 631 defer testing.AssertStop(c, w) 632 633 // TODO(quiescence): these two changes should be one event. 634 now := s.Clock.Now().Round(time.Second).UTC() 635 next := now.Add(time.Hour).Round(time.Second).UTC() 636 err := s.storage.SecretBackendRotated(id, next) 637 c.Assert(err, jc.ErrorIsNil) 638 wc.AssertChange(watcher.SecretBackendRotateChange{ 639 ID: id, 640 Name: "myvault", 641 NextTriggerTime: next, 642 }) 643 err = s.storage.UpdateSecretBackend(state.UpdateSecretBackendParams{ 644 ID: id, 645 TokenRotateInterval: ptr(time.Duration(0)), 646 }) 647 c.Assert(err, jc.ErrorIsNil) 648 649 wc.AssertChange(watcher.SecretBackendRotateChange{ 650 ID: id, 651 Name: "myvault", 652 }) 653 wc.AssertNoChange() 654 } 655 656 func (s *SecretBackendWatcherSuite) TestWatchMultipleUpdates(c *gc.C) { 657 w, id := s.setupWatcher(c) 658 wc := testing.NewSecretBackendRotateWatcherC(c, w) 659 defer testing.AssertStop(c, w) 660 661 // TODO(quiescence): these two changes should be one event. 662 now := s.Clock.Now().Round(time.Second).UTC() 663 next := now.Add(time.Hour).Round(time.Second).UTC() 664 err := s.storage.SecretBackendRotated(id, next) 665 c.Assert(err, jc.ErrorIsNil) 666 wc.AssertChange(watcher.SecretBackendRotateChange{ 667 ID: id, 668 Name: "myvault", 669 NextTriggerTime: next, 670 }) 671 672 next2 := now.Add(time.Minute).Round(time.Second).UTC() 673 id2, err := s.storage.CreateSecretBackend(state.CreateSecretBackendParams{ 674 Name: "myvault2", 675 BackendType: "vault", 676 TokenRotateInterval: ptr(666 * time.Minute), 677 NextRotateTime: ptr(next2), 678 Config: map[string]interface{}{"foo.key": "bar"}, 679 }) 680 c.Assert(err, jc.ErrorIsNil) 681 wc.AssertChange(watcher.SecretBackendRotateChange{ 682 ID: id2, 683 Name: "myvault2", 684 NextTriggerTime: next2, 685 }) 686 687 err = s.storage.UpdateSecretBackend(state.UpdateSecretBackendParams{ 688 ID: id, 689 TokenRotateInterval: ptr(time.Duration(0)), 690 }) 691 c.Assert(err, jc.ErrorIsNil) 692 693 wc.AssertChange(watcher.SecretBackendRotateChange{ 694 ID: id, 695 Name: "myvault", 696 }) 697 wc.AssertNoChange() 698 }