github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/modelmigration_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 jujutesting "github.com/juju/testing" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/names.v2" 16 "gopkg.in/macaroon.v1" 17 18 "github.com/juju/juju/core/migration" 19 "github.com/juju/juju/state" 20 statetesting "github.com/juju/juju/state/testing" 21 "github.com/juju/juju/testing/factory" 22 ) 23 24 type MigrationSuite struct { 25 ConnSuite 26 State2 *state.State 27 clock *jujutesting.Clock 28 stdSpec state.MigrationSpec 29 } 30 31 var _ = gc.Suite(new(MigrationSuite)) 32 33 func (s *MigrationSuite) SetUpTest(c *gc.C) { 34 s.ConnSuite.SetUpTest(c) 35 s.clock = jujutesting.NewClock(time.Now().Truncate(time.Second)) 36 err := s.State.SetClockForTesting(s.clock) 37 c.Assert(err, jc.ErrorIsNil) 38 39 // Create a hosted model to migrate. 40 s.State2 = s.Factory.MakeModel(c, nil) 41 s.AddCleanup(func(*gc.C) { s.State2.Close() }) 42 43 targetControllerTag := names.NewControllerTag(utils.MustNewUUID().String()) 44 45 mac, err := macaroon.New([]byte("secret"), "id", "location") 46 c.Assert(err, jc.ErrorIsNil) 47 48 // Plausible migration arguments to test with. 49 s.stdSpec = state.MigrationSpec{ 50 InitiatedBy: names.NewUserTag("admin"), 51 TargetInfo: migration.TargetInfo{ 52 ControllerTag: targetControllerTag, 53 Addrs: []string{"1.2.3.4:5555", "4.3.2.1:6666"}, 54 CACert: "cert", 55 AuthTag: names.NewUserTag("user"), 56 Password: "password", 57 Macaroons: []macaroon.Slice{{mac}}, 58 }, 59 } 60 } 61 62 func (s *MigrationSuite) TestCreate(c *gc.C) { 63 model, err := s.State2.Model() 64 c.Assert(err, jc.ErrorIsNil) 65 c.Assert(model.MigrationMode(), gc.Equals, state.MigrationModeNone) 66 67 mig, err := s.State2.CreateMigration(s.stdSpec) 68 c.Assert(err, jc.ErrorIsNil) 69 70 c.Check(mig.ModelUUID(), gc.Equals, s.State2.ModelUUID()) 71 checkIdAndAttempt(c, mig, 0) 72 73 c.Check(mig.StartTime(), gc.Equals, s.clock.Now()) 74 c.Check(mig.SuccessTime().IsZero(), jc.IsTrue) 75 c.Check(mig.EndTime().IsZero(), jc.IsTrue) 76 c.Check(mig.StatusMessage(), gc.Equals, "starting") 77 c.Check(mig.InitiatedBy(), gc.Equals, "admin") 78 c.Check(mig.ExternalControl(), jc.IsFalse) 79 80 info, err := mig.TargetInfo() 81 c.Assert(err, jc.ErrorIsNil) 82 c.Check(*info, jc.DeepEquals, s.stdSpec.TargetInfo) 83 84 assertPhase(c, mig, migration.QUIESCE) 85 c.Check(mig.PhaseChangedTime(), gc.Equals, mig.StartTime()) 86 87 assertMigrationActive(c, s.State2) 88 89 c.Assert(model.Refresh(), jc.ErrorIsNil) 90 c.Check(model.MigrationMode(), gc.Equals, state.MigrationModeExporting) 91 } 92 93 func (s *MigrationSuite) TestCreateExternalControl(c *gc.C) { 94 spec := s.stdSpec 95 spec.ExternalControl = true 96 mig, err := s.State2.CreateMigration(spec) 97 c.Assert(err, jc.ErrorIsNil) 98 c.Check(mig.ModelUUID(), gc.Equals, s.State2.ModelUUID()) 99 c.Check(mig.ExternalControl(), jc.IsTrue) 100 } 101 102 func (s *MigrationSuite) TestIsMigrationActive(c *gc.C) { 103 check := func(expected bool) { 104 isActive, err := s.State2.IsMigrationActive() 105 c.Assert(err, jc.ErrorIsNil) 106 c.Check(isActive, gc.Equals, expected) 107 108 isActive2, err := state.IsMigrationActive(s.State, s.State2.ModelUUID()) 109 c.Assert(err, jc.ErrorIsNil) 110 c.Check(isActive2, gc.Equals, expected) 111 } 112 113 check(false) 114 115 _, err := s.State2.CreateMigration(s.stdSpec) 116 c.Assert(err, jc.ErrorIsNil) 117 118 check(true) 119 } 120 121 func (s *MigrationSuite) TestIdSequencesAreIndependent(c *gc.C) { 122 st2 := s.State2 123 st3 := s.Factory.MakeModel(c, nil) 124 s.AddCleanup(func(*gc.C) { st3.Close() }) 125 126 mig2, err := st2.CreateMigration(s.stdSpec) 127 c.Assert(err, jc.ErrorIsNil) 128 checkIdAndAttempt(c, mig2, 0) 129 130 mig3, err := st3.CreateMigration(s.stdSpec) 131 c.Assert(err, jc.ErrorIsNil) 132 checkIdAndAttempt(c, mig3, 0) 133 } 134 135 func (s *MigrationSuite) TestIdSequencesIncrement(c *gc.C) { 136 for attempt := 0; attempt < 3; attempt++ { 137 mig, err := s.State2.CreateMigration(s.stdSpec) 138 c.Assert(err, jc.ErrorIsNil) 139 checkIdAndAttempt(c, mig, attempt) 140 c.Check(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 141 c.Check(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 142 } 143 } 144 145 func (s *MigrationSuite) TestIdSequencesIncrementOnlyWhenNecessary(c *gc.C) { 146 // Ensure that sequence numbers aren't "used up" unnecessarily 147 // when the create txn is going to fail. 148 149 mig, err := s.State2.CreateMigration(s.stdSpec) 150 c.Assert(err, jc.ErrorIsNil) 151 checkIdAndAttempt(c, mig, 0) 152 153 // This attempt will fail because a migration is already in 154 // progress. 155 _, err = s.State2.CreateMigration(s.stdSpec) 156 c.Assert(err, gc.ErrorMatches, ".+already in progress") 157 158 // Now abort the migration and create another. The Id sequence 159 // should have only incremented by 1. 160 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 161 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 162 163 mig, err = s.State2.CreateMigration(s.stdSpec) 164 c.Assert(err, jc.ErrorIsNil) 165 checkIdAndAttempt(c, mig, 1) 166 } 167 168 func (s *MigrationSuite) TestSpecValidation(c *gc.C) { 169 tests := []struct { 170 label string 171 tweakSpec func(*state.MigrationSpec) 172 errorPattern string 173 }{{ 174 "invalid InitiatedBy", 175 func(spec *state.MigrationSpec) { 176 spec.InitiatedBy = names.UserTag{} 177 }, 178 "InitiatedBy not valid", 179 }, { 180 "TargetInfo is validated", 181 func(spec *state.MigrationSpec) { 182 spec.TargetInfo.CACert = "" 183 }, 184 "empty CACert not valid", 185 }} 186 for _, test := range tests { 187 c.Logf("---- %s -----------", test.label) 188 189 // Set up spec. 190 spec := s.stdSpec 191 test.tweakSpec(&spec) 192 193 // Check Validate directly. 194 err := spec.Validate() 195 c.Check(errors.IsNotValid(err), jc.IsTrue) 196 c.Check(err, gc.ErrorMatches, test.errorPattern) 197 198 // Ensure that CreateMigration rejects the bad spec too. 199 mig, err := s.State2.CreateMigration(spec) 200 c.Check(mig, gc.IsNil) 201 c.Check(errors.IsNotValid(err), jc.IsTrue) 202 c.Check(err, gc.ErrorMatches, test.errorPattern) 203 } 204 } 205 206 func (s *MigrationSuite) TestCreateWithControllerModel(c *gc.C) { 207 // This is the State for the controller 208 mig, err := s.State.CreateMigration(s.stdSpec) 209 c.Check(mig, gc.IsNil) 210 c.Check(err, gc.ErrorMatches, "controllers can't be migrated") 211 } 212 213 func (s *MigrationSuite) TestCreateMigrationInProgress(c *gc.C) { 214 mig, err := s.State2.CreateMigration(s.stdSpec) 215 c.Assert(mig, gc.Not(gc.IsNil)) 216 c.Assert(err, jc.ErrorIsNil) 217 218 mig2, err := s.State2.CreateMigration(s.stdSpec) 219 c.Check(mig2, gc.IsNil) 220 c.Check(err, gc.ErrorMatches, "failed to create migration: already in progress") 221 } 222 223 func (s *MigrationSuite) TestCreateMigrationRace(c *gc.C) { 224 defer state.SetBeforeHooks(c, s.State2, func() { 225 mig, err := s.State2.CreateMigration(s.stdSpec) 226 c.Assert(mig, gc.Not(gc.IsNil)) 227 c.Assert(err, jc.ErrorIsNil) 228 }).Check() 229 230 mig, err := s.State2.CreateMigration(s.stdSpec) 231 c.Check(mig, gc.IsNil) 232 c.Check(err, gc.ErrorMatches, "failed to create migration: already in progress") 233 } 234 235 func (s *MigrationSuite) TestCreateMigrationWhenModelNotAlive(c *gc.C) { 236 // Set the hosted model to Dying. 237 model, err := s.State2.Model() 238 c.Assert(err, jc.ErrorIsNil) 239 c.Assert(model.Destroy(), jc.ErrorIsNil) 240 241 mig, err := s.State2.CreateMigration(s.stdSpec) 242 c.Check(mig, gc.IsNil) 243 c.Check(err, gc.ErrorMatches, "failed to create migration: model is not alive") 244 } 245 246 func (s *MigrationSuite) TestMigrationToSameController(c *gc.C) { 247 spec := s.stdSpec 248 spec.TargetInfo.ControllerTag = s.State.ControllerTag() 249 250 mig, err := s.State2.CreateMigration(spec) 251 c.Check(mig, gc.IsNil) 252 c.Check(err, gc.ErrorMatches, "model already attached to target controller") 253 } 254 255 func (s *MigrationSuite) TestLatestMigration(c *gc.C) { 256 mig1, err := s.State2.CreateMigration(s.stdSpec) 257 c.Assert(err, jc.ErrorIsNil) 258 259 mig2, err := s.State2.LatestMigration() 260 c.Assert(err, jc.ErrorIsNil) 261 262 c.Assert(mig1.Id(), gc.Equals, mig2.Id()) 263 } 264 265 func (s *MigrationSuite) TestLatestMigrationNotExist(c *gc.C) { 266 mig, err := s.State.LatestMigration() 267 c.Check(mig, gc.IsNil) 268 c.Check(errors.IsNotFound(err), jc.IsTrue) 269 } 270 271 func (s *MigrationSuite) TestGetsLatestAttempt(c *gc.C) { 272 modelUUID := s.State2.ModelUUID() 273 274 for i := 0; i < 10; i++ { 275 c.Logf("loop %d", i) 276 _, err := s.State2.CreateMigration(s.stdSpec) 277 c.Assert(err, jc.ErrorIsNil) 278 279 mig, err := s.State2.LatestMigration() 280 c.Check(mig.Id(), gc.Equals, fmt.Sprintf("%s:%d", modelUUID, i)) 281 282 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 283 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 284 } 285 } 286 287 func (s *MigrationSuite) TestLatestMigrationPreviousMigration(c *gc.C) { 288 // Check the scenario of a model having been migrated away and 289 // then migrated back. The previous migration shouldn't be 290 // reported by LatestMigration. 291 292 // Make it appear as if the model has been successfully 293 // migrated. Don't actually remove model documents to simulate it 294 // having been migrated back to the controller. 295 phases := []migration.Phase{ 296 migration.IMPORT, 297 migration.VALIDATION, 298 migration.SUCCESS, 299 migration.LOGTRANSFER, 300 migration.REAP, 301 migration.DONE, 302 } 303 mig, err := s.State2.CreateMigration(s.stdSpec) 304 c.Assert(err, jc.ErrorIsNil) 305 for _, phase := range phases { 306 c.Assert(mig.SetPhase(phase), jc.ErrorIsNil) 307 } 308 state.ResetMigrationMode(c, s.State2) 309 310 // Previous migration shouldn't be reported. 311 _, err = s.State2.LatestMigration() 312 c.Check(errors.IsNotFound(err), jc.IsTrue) 313 314 // Start a new migration attempt, which should be reported. 315 mig2, err := s.State2.CreateMigration(s.stdSpec) 316 c.Assert(err, jc.ErrorIsNil) 317 318 mig2b, err := s.State2.LatestMigration() 319 c.Check(err, jc.ErrorIsNil) 320 c.Check(mig2b.Id(), gc.Equals, mig2.Id()) 321 } 322 323 func (s *MigrationSuite) TestMigration(c *gc.C) { 324 mig1, err := s.State2.CreateMigration(s.stdSpec) 325 c.Assert(err, jc.ErrorIsNil) 326 327 mig2, err := s.State2.Migration(mig1.Id()) 328 c.Check(err, jc.ErrorIsNil) 329 c.Check(mig1.Id(), gc.Equals, mig2.Id()) 330 c.Check(mig2.StartTime(), gc.Equals, s.clock.Now()) 331 } 332 333 func (s *MigrationSuite) TestMigrationNotFound(c *gc.C) { 334 _, err := s.State2.Migration("does not exist") 335 c.Check(err, jc.Satisfies, errors.IsNotFound) 336 c.Check(err, gc.ErrorMatches, "migration not found") 337 } 338 339 func (s *MigrationSuite) TestRefresh(c *gc.C) { 340 mig1, err := s.State2.CreateMigration(s.stdSpec) 341 c.Assert(err, jc.ErrorIsNil) 342 343 mig2, err := s.State2.LatestMigration() 344 c.Assert(err, jc.ErrorIsNil) 345 346 err = mig1.SetPhase(migration.IMPORT) 347 c.Assert(err, jc.ErrorIsNil) 348 349 assertPhase(c, mig2, migration.QUIESCE) 350 err = mig2.Refresh() 351 c.Assert(err, jc.ErrorIsNil) 352 assertPhase(c, mig2, migration.IMPORT) 353 } 354 355 func (s *MigrationSuite) TestSuccessfulPhaseTransitions(c *gc.C) { 356 st := s.State2 357 358 mig, err := st.CreateMigration(s.stdSpec) 359 c.Assert(err, jc.ErrorIsNil) 360 c.Assert(mig, gc.NotNil) 361 362 mig2, err := st.LatestMigration() 363 c.Assert(err, jc.ErrorIsNil) 364 365 phases := []migration.Phase{ 366 migration.IMPORT, 367 migration.VALIDATION, 368 migration.SUCCESS, 369 migration.LOGTRANSFER, 370 migration.REAP, 371 migration.DONE, 372 } 373 374 var successTime time.Time 375 for _, phase := range phases[:len(phases)-1] { 376 err := mig.SetPhase(phase) 377 c.Assert(err, jc.ErrorIsNil) 378 379 assertPhase(c, mig, phase) 380 c.Assert(mig.PhaseChangedTime(), gc.Equals, s.clock.Now()) 381 382 // Check success timestamp is set only when SUCCESS is 383 // reached. 384 if phase < migration.SUCCESS { 385 c.Assert(mig.SuccessTime().IsZero(), jc.IsTrue) 386 } else { 387 if phase == migration.SUCCESS { 388 successTime = s.clock.Now() 389 } 390 c.Assert(mig.SuccessTime(), gc.Equals, successTime) 391 } 392 393 // Check still marked as active. 394 assertMigrationActive(c, s.State2) 395 c.Assert(mig.EndTime().IsZero(), jc.IsTrue) 396 397 // Ensure change was peristed. 398 c.Assert(mig2.Refresh(), jc.ErrorIsNil) 399 assertPhase(c, mig2, phase) 400 401 s.clock.Advance(time.Millisecond) 402 } 403 404 // Now move to the final phase (DONE) and ensure fields are set as 405 // expected. 406 err = mig.SetPhase(migration.DONE) 407 c.Assert(err, jc.ErrorIsNil) 408 assertPhase(c, mig, migration.DONE) 409 s.assertMigrationCleanedUp(c, mig) 410 } 411 412 func (s *MigrationSuite) TestABORTCleanup(c *gc.C) { 413 mig, err := s.State2.CreateMigration(s.stdSpec) 414 c.Assert(err, jc.ErrorIsNil) 415 416 s.clock.Advance(time.Millisecond) 417 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 418 s.clock.Advance(time.Millisecond) 419 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 420 421 s.assertMigrationCleanedUp(c, mig) 422 423 // Model should be set back to active. 424 model, err := s.State2.Model() 425 c.Assert(err, jc.ErrorIsNil) 426 c.Assert(model.MigrationMode(), gc.Equals, state.MigrationModeNone) 427 } 428 429 func (s *MigrationSuite) TestREAPFAILEDCleanup(c *gc.C) { 430 mig, err := s.State2.CreateMigration(s.stdSpec) 431 c.Assert(err, jc.ErrorIsNil) 432 433 // Advance the migration to REAPFAILED. 434 phases := []migration.Phase{ 435 migration.IMPORT, 436 migration.VALIDATION, 437 migration.SUCCESS, 438 migration.LOGTRANSFER, 439 migration.REAP, 440 migration.REAPFAILED, 441 } 442 for _, phase := range phases { 443 s.clock.Advance(time.Millisecond) 444 c.Assert(mig.SetPhase(phase), jc.ErrorIsNil) 445 } 446 447 s.assertMigrationCleanedUp(c, mig) 448 } 449 450 func (s *MigrationSuite) assertMigrationCleanedUp(c *gc.C, mig state.ModelMigration) { 451 c.Assert(mig.PhaseChangedTime(), gc.Equals, s.clock.Now()) 452 c.Assert(mig.EndTime(), gc.Equals, s.clock.Now()) 453 assertMigrationNotActive(c, s.State2) 454 } 455 456 func (s *MigrationSuite) TestIllegalPhaseTransition(c *gc.C) { 457 mig, err := s.State2.CreateMigration(s.stdSpec) 458 c.Assert(err, jc.ErrorIsNil) 459 460 err = mig.SetPhase(migration.SUCCESS) 461 c.Check(err, gc.ErrorMatches, "illegal phase change: QUIESCE -> SUCCESS") 462 } 463 464 func (s *MigrationSuite) TestPhaseChangeRace(c *gc.C) { 465 mig, err := s.State2.CreateMigration(s.stdSpec) 466 c.Assert(mig, gc.Not(gc.IsNil)) 467 468 defer state.SetBeforeHooks(c, s.State2, func() { 469 mig, err := s.State2.LatestMigration() 470 c.Assert(err, jc.ErrorIsNil) 471 c.Assert(mig.SetPhase(migration.IMPORT), jc.ErrorIsNil) 472 }).Check() 473 474 err = mig.SetPhase(migration.IMPORT) 475 c.Assert(err, gc.ErrorMatches, "phase already changed") 476 assertPhase(c, mig, migration.QUIESCE) 477 478 // After a refresh it the phase change should be ok. 479 c.Assert(mig.Refresh(), jc.ErrorIsNil) 480 err = mig.SetPhase(migration.IMPORT) 481 c.Assert(err, jc.ErrorIsNil) 482 assertPhase(c, mig, migration.IMPORT) 483 } 484 485 func (s *MigrationSuite) TestStatusMessage(c *gc.C) { 486 mig, err := s.State2.CreateMigration(s.stdSpec) 487 c.Assert(mig, gc.Not(gc.IsNil)) 488 489 mig2, err := s.State2.LatestMigration() 490 c.Assert(err, jc.ErrorIsNil) 491 492 c.Check(mig.StatusMessage(), gc.Equals, "starting") 493 c.Check(mig2.StatusMessage(), gc.Equals, "starting") 494 495 err = mig.SetStatusMessage("foo bar") 496 c.Assert(err, jc.ErrorIsNil) 497 498 c.Check(mig.StatusMessage(), gc.Equals, "foo bar") 499 500 c.Assert(mig2.Refresh(), jc.ErrorIsNil) 501 c.Check(mig2.StatusMessage(), gc.Equals, "foo bar") 502 } 503 504 func (s *MigrationSuite) TestWatchForMigration(c *gc.C) { 505 // Start watching for migration. 506 w, wc := s.createMigrationWatcher(c, s.State2) 507 wc.AssertOneChange() 508 509 // Create the migration - should be reported. 510 mig, err := s.State2.CreateMigration(s.stdSpec) 511 c.Assert(err, jc.ErrorIsNil) 512 wc.AssertOneChange() 513 514 // Mere phase changes should not be reported. 515 c.Check(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 516 wc.AssertNoChange() 517 518 // Ending the migration should be reported. 519 c.Check(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 520 wc.AssertOneChange() 521 522 statetesting.AssertStop(c, w) 523 wc.AssertClosed() 524 } 525 526 func (s *MigrationSuite) TestWatchForMigrationInProgress(c *gc.C) { 527 // Create a migration. 528 _, err := s.State2.CreateMigration(s.stdSpec) 529 c.Assert(err, jc.ErrorIsNil) 530 531 // Start watching for a migration - the in progress one should be reported. 532 _, wc := s.createMigrationWatcher(c, s.State2) 533 wc.AssertOneChange() 534 } 535 536 func (s *MigrationSuite) TestWatchForMigrationMultiModel(c *gc.C) { 537 _, wc2 := s.createMigrationWatcher(c, s.State2) 538 wc2.AssertOneChange() 539 540 // Create another hosted model to migrate and watch for 541 // migrations. 542 State3 := s.Factory.MakeModel(c, nil) 543 s.AddCleanup(func(*gc.C) { State3.Close() }) 544 _, wc3 := s.createMigrationWatcher(c, State3) 545 wc3.AssertOneChange() 546 547 // Create a migration for 2. 548 _, err := s.State2.CreateMigration(s.stdSpec) 549 c.Assert(err, jc.ErrorIsNil) 550 wc2.AssertOneChange() 551 wc3.AssertNoChange() 552 553 // Create a migration for 3. 554 _, err = State3.CreateMigration(s.stdSpec) 555 c.Assert(err, jc.ErrorIsNil) 556 wc2.AssertNoChange() 557 wc3.AssertOneChange() 558 } 559 560 func (s *MigrationSuite) createMigrationWatcher(c *gc.C, st *state.State) ( 561 state.NotifyWatcher, statetesting.NotifyWatcherC, 562 ) { 563 w := st.WatchForMigration() 564 s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) }) 565 return w, statetesting.NewNotifyWatcherC(c, st, w) 566 } 567 568 func (s *MigrationSuite) TestWatchMigrationStatus(c *gc.C) { 569 w, wc := s.createStatusWatcher(c, s.State2) 570 wc.AssertOneChange() // Initial event. 571 572 // Create a migration. 573 mig, err := s.State2.CreateMigration(s.stdSpec) 574 c.Assert(err, jc.ErrorIsNil) 575 wc.AssertOneChange() 576 577 // End it. 578 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 579 wc.AssertOneChange() 580 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 581 wc.AssertOneChange() 582 583 // Start another. 584 mig2, err := s.State2.CreateMigration(s.stdSpec) 585 c.Assert(err, jc.ErrorIsNil) 586 wc.AssertOneChange() 587 588 // Change phase. 589 c.Assert(mig2.SetPhase(migration.IMPORT), jc.ErrorIsNil) 590 wc.AssertOneChange() 591 592 // End it. 593 c.Assert(mig2.SetPhase(migration.ABORT), jc.ErrorIsNil) 594 wc.AssertOneChange() 595 596 statetesting.AssertStop(c, w) 597 wc.AssertClosed() 598 } 599 600 func (s *MigrationSuite) TestWatchMigrationStatusPreexisting(c *gc.C) { 601 // Create an aborted migration. 602 mig, err := s.State2.CreateMigration(s.stdSpec) 603 c.Assert(err, jc.ErrorIsNil) 604 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 605 606 _, wc := s.createStatusWatcher(c, s.State2) 607 wc.AssertOneChange() 608 } 609 610 func (s *MigrationSuite) TestWatchMigrationStatusMultiModel(c *gc.C) { 611 _, wc2 := s.createStatusWatcher(c, s.State2) 612 wc2.AssertOneChange() // initial event 613 614 // Create another hosted model to migrate and watch for 615 // migrations. 616 State3 := s.Factory.MakeModel(c, nil) 617 s.AddCleanup(func(*gc.C) { State3.Close() }) 618 _, wc3 := s.createStatusWatcher(c, State3) 619 wc3.AssertOneChange() // initial event 620 621 // Create a migration for 2. 622 mig, err := s.State2.CreateMigration(s.stdSpec) 623 c.Assert(err, jc.ErrorIsNil) 624 wc2.AssertOneChange() 625 wc3.AssertNoChange() 626 627 // Create a migration for 3. 628 _, err = State3.CreateMigration(s.stdSpec) 629 c.Assert(err, jc.ErrorIsNil) 630 wc2.AssertNoChange() 631 wc3.AssertOneChange() 632 633 // Update the migration for 2. 634 err = mig.SetPhase(migration.ABORT) 635 c.Assert(err, jc.ErrorIsNil) 636 wc2.AssertOneChange() 637 wc3.AssertNoChange() 638 } 639 640 func (s *MigrationSuite) TestMinionReports(c *gc.C) { 641 // Create some machines and units to report with. 642 factory2 := factory.NewFactory(s.State2) 643 m0 := factory2.MakeMachine(c, nil) 644 u0 := factory2.MakeUnit(c, &factory.UnitParams{Machine: m0}) 645 m1 := factory2.MakeMachine(c, nil) 646 m2 := factory2.MakeMachine(c, nil) 647 648 mig, err := s.State2.CreateMigration(s.stdSpec) 649 c.Assert(err, jc.ErrorIsNil) 650 651 const phase = migration.QUIESCE 652 c.Assert(mig.SubmitMinionReport(m0.Tag(), phase, true), jc.ErrorIsNil) 653 c.Assert(mig.SubmitMinionReport(m1.Tag(), phase, false), jc.ErrorIsNil) 654 c.Assert(mig.SubmitMinionReport(u0.Tag(), phase, true), jc.ErrorIsNil) 655 656 reports, err := mig.MinionReports() 657 c.Assert(err, jc.ErrorIsNil) 658 c.Check(reports.Succeeded, jc.SameContents, []names.Tag{m0.Tag(), u0.Tag()}) 659 c.Check(reports.Failed, jc.SameContents, []names.Tag{m1.Tag()}) 660 c.Check(reports.Unknown, jc.SameContents, []names.Tag{m2.Tag()}) 661 } 662 663 func (s *MigrationSuite) TestDuplicateMinionReportsSameSuccess(c *gc.C) { 664 // It should be OK for a minion report to arrive more than once 665 // for the same migration, agent and phase as long as the value of 666 // "success" is the same. 667 mig, err := s.State2.CreateMigration(s.stdSpec) 668 c.Assert(err, jc.ErrorIsNil) 669 tag := names.NewMachineTag("42") 670 c.Check(mig.SubmitMinionReport(tag, migration.QUIESCE, true), jc.ErrorIsNil) 671 c.Check(mig.SubmitMinionReport(tag, migration.QUIESCE, true), jc.ErrorIsNil) 672 } 673 674 func (s *MigrationSuite) TestDuplicateMinionReportsDifferingSuccess(c *gc.C) { 675 // It is not OK for a minion report to arrive more than once for 676 // the same migration, agent and phase when the "success" value 677 // changes. 678 mig, err := s.State2.CreateMigration(s.stdSpec) 679 c.Assert(err, jc.ErrorIsNil) 680 tag := names.NewMachineTag("42") 681 c.Check(mig.SubmitMinionReport(tag, migration.QUIESCE, true), jc.ErrorIsNil) 682 err = mig.SubmitMinionReport(tag, migration.QUIESCE, false) 683 c.Check(err, gc.ErrorMatches, 684 fmt.Sprintf("conflicting reports received for %s/QUIESCE/machine-42", mig.Id())) 685 } 686 687 func (s *MigrationSuite) TestMinionReportWithOldPhase(c *gc.C) { 688 // It is OK for a report to arrive for even a migration has moved 689 // on. 690 mig, err := s.State2.CreateMigration(s.stdSpec) 691 c.Assert(err, jc.ErrorIsNil) 692 693 // Get another reference to the same migration. 694 migalt, err := s.State2.LatestMigration() 695 c.Assert(err, jc.ErrorIsNil) 696 697 // Confirm that there's no reports when starting. 698 reports, err := mig.MinionReports() 699 c.Assert(err, jc.ErrorIsNil) 700 c.Check(reports.Succeeded, gc.HasLen, 0) 701 702 // Advance the migration 703 c.Assert(mig.SetPhase(migration.IMPORT), jc.ErrorIsNil) 704 705 // Submit minion report for the old phase. 706 tag := names.NewMachineTag("42") 707 c.Assert(mig.SubmitMinionReport(tag, migration.QUIESCE, true), jc.ErrorIsNil) 708 709 // The report should still have been recorded. 710 reports, err = migalt.MinionReports() 711 c.Assert(err, jc.ErrorIsNil) 712 c.Check(reports.Succeeded, jc.SameContents, []names.Tag{tag}) 713 } 714 715 func (s *MigrationSuite) TestMinionReportWithInactiveMigration(c *gc.C) { 716 // Create a migration. 717 mig, err := s.State2.CreateMigration(s.stdSpec) 718 c.Assert(err, jc.ErrorIsNil) 719 720 // Get another reference to the same migration. 721 migalt, err := s.State2.LatestMigration() 722 c.Assert(err, jc.ErrorIsNil) 723 724 // Abort the migration. 725 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 726 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 727 728 // Confirm that there's no reports when starting. 729 reports, err := mig.MinionReports() 730 c.Assert(err, jc.ErrorIsNil) 731 c.Check(reports.Succeeded, gc.HasLen, 0) 732 733 // Submit a minion report for it. 734 tag := names.NewMachineTag("42") 735 c.Assert(mig.SubmitMinionReport(tag, migration.QUIESCE, true), jc.ErrorIsNil) 736 737 // The report should still have been recorded. 738 reports, err = migalt.MinionReports() 739 c.Assert(err, jc.ErrorIsNil) 740 c.Check(reports.Succeeded, jc.SameContents, []names.Tag{tag}) 741 } 742 743 func (s *MigrationSuite) TestWatchMinionReports(c *gc.C) { 744 mig, wc := s.createMigAndWatchReports(c, s.State2) 745 wc.AssertOneChange() // initial event 746 747 // A report should trigger the watcher. 748 c.Assert(mig.SubmitMinionReport(names.NewMachineTag("0"), migration.QUIESCE, true), jc.ErrorIsNil) 749 wc.AssertOneChange() 750 751 // A report for a different phase shouldn't trigger the watcher. 752 c.Assert(mig.SubmitMinionReport(names.NewMachineTag("1"), migration.IMPORT, true), jc.ErrorIsNil) 753 wc.AssertNoChange() 754 } 755 756 func (s *MigrationSuite) TestWatchMinionReportsMultiModel(c *gc.C) { 757 mig, wc := s.createMigAndWatchReports(c, s.State2) 758 wc.AssertOneChange() // initial event 759 760 State3 := s.Factory.MakeModel(c, nil) 761 s.AddCleanup(func(*gc.C) { State3.Close() }) 762 mig3, wc3 := s.createMigAndWatchReports(c, State3) 763 wc3.AssertOneChange() // initial event 764 765 // Ensure the correct watchers are triggered. 766 c.Assert(mig.SubmitMinionReport(names.NewMachineTag("0"), migration.QUIESCE, true), jc.ErrorIsNil) 767 wc.AssertOneChange() 768 wc3.AssertNoChange() 769 770 c.Assert(mig3.SubmitMinionReport(names.NewMachineTag("0"), migration.QUIESCE, true), jc.ErrorIsNil) 771 wc.AssertNoChange() 772 wc3.AssertOneChange() 773 } 774 775 func (s *MigrationSuite) createStatusWatcher(c *gc.C, st *state.State) ( 776 state.NotifyWatcher, statetesting.NotifyWatcherC, 777 ) { 778 w := st.WatchMigrationStatus() 779 s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) }) 780 return w, statetesting.NewNotifyWatcherC(c, st, w) 781 } 782 783 func (s *MigrationSuite) createMigAndWatchReports(c *gc.C, st *state.State) ( 784 state.ModelMigration, statetesting.NotifyWatcherC, 785 ) { 786 mig, err := st.CreateMigration(s.stdSpec) 787 c.Assert(err, jc.ErrorIsNil) 788 789 w, err := mig.WatchMinionReports() 790 c.Assert(err, jc.ErrorIsNil) 791 s.AddCleanup(func(*gc.C) { statetesting.AssertStop(c, w) }) 792 wc := statetesting.NewNotifyWatcherC(c, st, w) 793 794 return mig, wc 795 } 796 797 func assertPhase(c *gc.C, mig state.ModelMigration, phase migration.Phase) { 798 actualPhase, err := mig.Phase() 799 c.Assert(err, jc.ErrorIsNil) 800 c.Check(actualPhase, gc.Equals, phase) 801 } 802 803 func assertMigrationActive(c *gc.C, st *state.State) { 804 c.Check(isMigrationActive(c, st), jc.IsTrue) 805 } 806 807 func assertMigrationNotActive(c *gc.C, st *state.State) { 808 c.Check(isMigrationActive(c, st), jc.IsFalse) 809 } 810 811 func isMigrationActive(c *gc.C, st *state.State) bool { 812 isActive, err := st.IsMigrationActive() 813 c.Assert(err, jc.ErrorIsNil) 814 return isActive 815 } 816 817 func checkIdAndAttempt(c *gc.C, mig state.ModelMigration, expected int) { 818 c.Check(mig.Id(), gc.Equals, fmt.Sprintf("%s:%d", mig.ModelUUID(), expected)) 819 attempt, err := mig.Attempt() 820 c.Assert(err, jc.ErrorIsNil) 821 c.Check(attempt, gc.Equals, expected) 822 }