github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 "github.com/juju/utils/clock" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/core/migration" 18 "github.com/juju/juju/state" 19 statetesting "github.com/juju/juju/state/testing" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type ModelMigrationSuite struct { 24 ConnSuite 25 State2 *state.State 26 clock *coretesting.Clock 27 stdSpec state.ModelMigrationSpec 28 } 29 30 var _ = gc.Suite(new(ModelMigrationSuite)) 31 32 func (s *ModelMigrationSuite) SetUpTest(c *gc.C) { 33 s.ConnSuite.SetUpTest(c) 34 s.clock = coretesting.NewClock(time.Now().Truncate(time.Second)) 35 s.PatchValue(&state.GetClock, func() clock.Clock { 36 return s.clock 37 }) 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.NewModelTag(utils.MustNewUUID().String()) 44 45 // Plausible migration arguments to test with. 46 s.stdSpec = state.ModelMigrationSpec{ 47 InitiatedBy: names.NewUserTag("admin"), 48 TargetInfo: migration.TargetInfo{ 49 ControllerTag: targetControllerTag, 50 Addrs: []string{"1.2.3.4:5555", "4.3.2.1:6666"}, 51 CACert: "cert", 52 AuthTag: names.NewUserTag("user"), 53 Password: "password", 54 }, 55 } 56 } 57 58 func (s *ModelMigrationSuite) TestCreate(c *gc.C) { 59 mig, err := s.State2.CreateModelMigration(s.stdSpec) 60 c.Assert(err, jc.ErrorIsNil) 61 62 c.Check(mig.ModelUUID(), gc.Equals, s.State2.ModelUUID()) 63 checkIdAndAttempt(c, mig, 0) 64 65 c.Check(mig.StartTime(), gc.Equals, s.clock.Now()) 66 67 c.Check(mig.SuccessTime().IsZero(), jc.IsTrue) 68 c.Check(mig.EndTime().IsZero(), jc.IsTrue) 69 c.Check(mig.StatusMessage(), gc.Equals, "") 70 c.Check(mig.InitiatedBy(), gc.Equals, "admin") 71 72 info, err := mig.TargetInfo() 73 c.Assert(err, jc.ErrorIsNil) 74 c.Check(*info, jc.DeepEquals, s.stdSpec.TargetInfo) 75 76 assertPhase(c, mig, migration.QUIESCE) 77 c.Check(mig.PhaseChangedTime(), gc.Equals, mig.StartTime()) 78 79 assertMigrationActive(c, s.State2) 80 } 81 82 func (s *ModelMigrationSuite) TestIdSequencesAreIndependent(c *gc.C) { 83 st2 := s.State2 84 st3 := s.Factory.MakeModel(c, nil) 85 s.AddCleanup(func(*gc.C) { st3.Close() }) 86 87 mig2, err := st2.CreateModelMigration(s.stdSpec) 88 c.Assert(err, jc.ErrorIsNil) 89 checkIdAndAttempt(c, mig2, 0) 90 91 mig3, err := st3.CreateModelMigration(s.stdSpec) 92 c.Assert(err, jc.ErrorIsNil) 93 checkIdAndAttempt(c, mig3, 0) 94 } 95 96 func (s *ModelMigrationSuite) TestIdSequencesIncrement(c *gc.C) { 97 for attempt := 0; attempt < 3; attempt++ { 98 mig, err := s.State2.CreateModelMigration(s.stdSpec) 99 c.Assert(err, jc.ErrorIsNil) 100 checkIdAndAttempt(c, mig, attempt) 101 c.Check(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 102 c.Check(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 103 } 104 } 105 106 func (s *ModelMigrationSuite) TestIdSequencesIncrementOnlyWhenNecessary(c *gc.C) { 107 // Ensure that sequence numbers aren't "used up" unnecessarily 108 // when the create txn is going to fail. 109 110 mig, err := s.State2.CreateModelMigration(s.stdSpec) 111 c.Assert(err, jc.ErrorIsNil) 112 checkIdAndAttempt(c, mig, 0) 113 114 // This attempt will fail because a migration is already in 115 // progress. 116 _, err = s.State2.CreateModelMigration(s.stdSpec) 117 c.Assert(err, gc.ErrorMatches, ".+already in progress") 118 119 // Now abort the migration and create another. The Id sequence 120 // should have only incremented by 1. 121 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 122 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 123 124 mig, err = s.State2.CreateModelMigration(s.stdSpec) 125 c.Assert(err, jc.ErrorIsNil) 126 checkIdAndAttempt(c, mig, 1) 127 } 128 129 func (s *ModelMigrationSuite) TestSpecValidation(c *gc.C) { 130 tests := []struct { 131 label string 132 tweakSpec func(*state.ModelMigrationSpec) 133 errorPattern string 134 }{{ 135 "invalid InitiatedBy", 136 func(spec *state.ModelMigrationSpec) { 137 spec.InitiatedBy = names.UserTag{} 138 }, 139 "InitiatedBy not valid", 140 }, { 141 "TargetInfo is validated", 142 func(spec *state.ModelMigrationSpec) { 143 spec.TargetInfo.Password = "" 144 }, 145 "empty Password not valid", 146 }} 147 for _, test := range tests { 148 c.Logf("---- %s -----------", test.label) 149 150 // Set up spec. 151 spec := s.stdSpec 152 test.tweakSpec(&spec) 153 154 // Check Validate directly. 155 err := spec.Validate() 156 c.Check(errors.IsNotValid(err), jc.IsTrue) 157 c.Check(err, gc.ErrorMatches, test.errorPattern) 158 159 // Ensure that CreateModelMigration rejects the bad spec too. 160 mig, err := s.State2.CreateModelMigration(spec) 161 c.Check(mig, gc.IsNil) 162 c.Check(errors.IsNotValid(err), jc.IsTrue) 163 c.Check(err, gc.ErrorMatches, test.errorPattern) 164 } 165 } 166 167 func (s *ModelMigrationSuite) TestCreateWithControllerModel(c *gc.C) { 168 // This is the State for the controller 169 mig, err := s.State.CreateModelMigration(s.stdSpec) 170 c.Check(mig, gc.IsNil) 171 c.Check(err, gc.ErrorMatches, "controllers can't be migrated") 172 } 173 174 func (s *ModelMigrationSuite) TestCreateMigrationInProgress(c *gc.C) { 175 mig, err := s.State2.CreateModelMigration(s.stdSpec) 176 c.Assert(mig, gc.Not(gc.IsNil)) 177 c.Assert(err, jc.ErrorIsNil) 178 179 mig2, err := s.State2.CreateModelMigration(s.stdSpec) 180 c.Check(mig2, gc.IsNil) 181 c.Check(err, gc.ErrorMatches, "failed to create migration: already in progress") 182 } 183 184 func (s *ModelMigrationSuite) TestCreateMigrationRace(c *gc.C) { 185 defer state.SetBeforeHooks(c, s.State2, func() { 186 mig, err := s.State2.CreateModelMigration(s.stdSpec) 187 c.Assert(mig, gc.Not(gc.IsNil)) 188 c.Assert(err, jc.ErrorIsNil) 189 }).Check() 190 191 mig, err := s.State2.CreateModelMigration(s.stdSpec) 192 c.Check(mig, gc.IsNil) 193 c.Check(err, gc.ErrorMatches, "failed to create migration: already in progress") 194 } 195 196 func (s *ModelMigrationSuite) TestCreateMigrationWhenModelNotAlive(c *gc.C) { 197 // Set the hosted model to Dying. 198 model, err := s.State2.Model() 199 c.Assert(err, jc.ErrorIsNil) 200 c.Assert(model.Destroy(), jc.ErrorIsNil) 201 202 mig, err := s.State2.CreateModelMigration(s.stdSpec) 203 c.Check(mig, gc.IsNil) 204 c.Check(err, gc.ErrorMatches, "failed to create migration: model is not alive") 205 } 206 207 func (s *ModelMigrationSuite) TestMigrationToSameController(c *gc.C) { 208 spec := s.stdSpec 209 spec.TargetInfo.ControllerTag = s.State.ModelTag() 210 211 mig, err := s.State2.CreateModelMigration(spec) 212 c.Check(mig, gc.IsNil) 213 c.Check(err, gc.ErrorMatches, "model already attached to target controller") 214 } 215 216 func (s *ModelMigrationSuite) TestGet(c *gc.C) { 217 mig1, err := s.State2.CreateModelMigration(s.stdSpec) 218 c.Assert(err, jc.ErrorIsNil) 219 220 mig2, err := s.State2.GetModelMigration() 221 c.Assert(err, jc.ErrorIsNil) 222 223 c.Assert(mig1.Id(), gc.Equals, mig2.Id()) 224 } 225 226 func (s *ModelMigrationSuite) TestGetNotExist(c *gc.C) { 227 mig, err := s.State.GetModelMigration() 228 c.Check(mig, gc.IsNil) 229 c.Check(errors.IsNotFound(err), jc.IsTrue) 230 } 231 232 func (s *ModelMigrationSuite) TestGetsLatestAttempt(c *gc.C) { 233 modelUUID := s.State2.ModelUUID() 234 235 for i := 0; i < 10; i++ { 236 c.Logf("loop %d", i) 237 _, err := s.State2.CreateModelMigration(s.stdSpec) 238 c.Assert(err, jc.ErrorIsNil) 239 240 mig, err := s.State2.GetModelMigration() 241 c.Check(mig.Id(), gc.Equals, fmt.Sprintf("%s:%d", modelUUID, i)) 242 243 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 244 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 245 } 246 } 247 248 func (s *ModelMigrationSuite) TestRefresh(c *gc.C) { 249 mig1, err := s.State2.CreateModelMigration(s.stdSpec) 250 c.Assert(err, jc.ErrorIsNil) 251 252 mig2, err := s.State2.GetModelMigration() 253 c.Assert(err, jc.ErrorIsNil) 254 255 err = mig1.SetPhase(migration.READONLY) 256 c.Assert(err, jc.ErrorIsNil) 257 258 assertPhase(c, mig2, migration.QUIESCE) 259 err = mig2.Refresh() 260 c.Assert(err, jc.ErrorIsNil) 261 assertPhase(c, mig2, migration.READONLY) 262 } 263 264 func (s *ModelMigrationSuite) TestSuccessfulPhaseTransitions(c *gc.C) { 265 st := s.State2 266 267 mig, err := st.CreateModelMigration(s.stdSpec) 268 c.Assert(err, jc.ErrorIsNil) 269 c.Assert(mig, gc.NotNil) 270 271 mig2, err := st.GetModelMigration() 272 c.Assert(err, jc.ErrorIsNil) 273 274 phases := []migration.Phase{ 275 migration.READONLY, 276 migration.PRECHECK, 277 migration.IMPORT, 278 migration.VALIDATION, 279 migration.SUCCESS, 280 migration.LOGTRANSFER, 281 migration.REAP, 282 migration.DONE, 283 } 284 285 var successTime time.Time 286 for _, phase := range phases[:len(phases)-1] { 287 err := mig.SetPhase(phase) 288 c.Assert(err, jc.ErrorIsNil) 289 290 assertPhase(c, mig, phase) 291 c.Assert(mig.PhaseChangedTime(), gc.Equals, s.clock.Now()) 292 293 // Check success timestamp is set only when SUCCESS is 294 // reached. 295 if phase < migration.SUCCESS { 296 c.Assert(mig.SuccessTime().IsZero(), jc.IsTrue) 297 } else { 298 if phase == migration.SUCCESS { 299 successTime = s.clock.Now() 300 } 301 c.Assert(mig.SuccessTime(), gc.Equals, successTime) 302 } 303 304 // Check still marked as active. 305 assertMigrationActive(c, s.State2) 306 c.Assert(mig.EndTime().IsZero(), jc.IsTrue) 307 308 // Ensure change was peristed. 309 c.Assert(mig2.Refresh(), jc.ErrorIsNil) 310 assertPhase(c, mig2, phase) 311 312 s.clock.Advance(time.Millisecond) 313 } 314 315 // Now move to the final phase (DONE) and ensure fields are set as 316 // expected. 317 err = mig.SetPhase(migration.DONE) 318 c.Assert(err, jc.ErrorIsNil) 319 assertPhase(c, mig, migration.DONE) 320 s.assertMigrationCleanedUp(c, mig) 321 } 322 323 func (s *ModelMigrationSuite) TestABORTCleanup(c *gc.C) { 324 mig, err := s.State2.CreateModelMigration(s.stdSpec) 325 c.Assert(err, jc.ErrorIsNil) 326 327 s.clock.Advance(time.Millisecond) 328 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 329 s.clock.Advance(time.Millisecond) 330 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 331 332 s.assertMigrationCleanedUp(c, mig) 333 } 334 335 func (s *ModelMigrationSuite) TestREAPFAILEDCleanup(c *gc.C) { 336 mig, err := s.State2.CreateModelMigration(s.stdSpec) 337 c.Assert(err, jc.ErrorIsNil) 338 339 // Advance the migration to REAPFAILED. 340 phases := []migration.Phase{ 341 migration.READONLY, 342 migration.PRECHECK, 343 migration.IMPORT, 344 migration.VALIDATION, 345 migration.SUCCESS, 346 migration.LOGTRANSFER, 347 migration.REAP, 348 migration.REAPFAILED, 349 } 350 for _, phase := range phases { 351 s.clock.Advance(time.Millisecond) 352 c.Assert(mig.SetPhase(phase), jc.ErrorIsNil) 353 } 354 355 s.assertMigrationCleanedUp(c, mig) 356 } 357 358 func (s *ModelMigrationSuite) assertMigrationCleanedUp(c *gc.C, mig state.ModelMigration) { 359 c.Assert(mig.PhaseChangedTime(), gc.Equals, s.clock.Now()) 360 c.Assert(mig.EndTime(), gc.Equals, s.clock.Now()) 361 assertMigrationNotActive(c, s.State2) 362 } 363 364 func (s *ModelMigrationSuite) TestIllegalPhaseTransition(c *gc.C) { 365 mig, err := s.State2.CreateModelMigration(s.stdSpec) 366 c.Assert(err, jc.ErrorIsNil) 367 368 err = mig.SetPhase(migration.SUCCESS) 369 c.Check(err, gc.ErrorMatches, "illegal phase change: QUIESCE -> SUCCESS") 370 } 371 372 func (s *ModelMigrationSuite) TestPhaseChangeRace(c *gc.C) { 373 mig, err := s.State2.CreateModelMigration(s.stdSpec) 374 c.Assert(mig, gc.Not(gc.IsNil)) 375 376 defer state.SetBeforeHooks(c, s.State2, func() { 377 mig, err := s.State2.GetModelMigration() 378 c.Assert(err, jc.ErrorIsNil) 379 c.Assert(mig.SetPhase(migration.READONLY), jc.ErrorIsNil) 380 }).Check() 381 382 err = mig.SetPhase(migration.READONLY) 383 c.Assert(err, gc.ErrorMatches, "phase already changed") 384 assertPhase(c, mig, migration.QUIESCE) 385 386 // After a refresh it the phase change should be ok. 387 c.Assert(mig.Refresh(), jc.ErrorIsNil) 388 err = mig.SetPhase(migration.READONLY) 389 c.Assert(err, jc.ErrorIsNil) 390 assertPhase(c, mig, migration.READONLY) 391 } 392 393 func (s *ModelMigrationSuite) TestStatusMessage(c *gc.C) { 394 mig, err := s.State2.CreateModelMigration(s.stdSpec) 395 c.Assert(mig, gc.Not(gc.IsNil)) 396 397 mig2, err := s.State2.GetModelMigration() 398 c.Assert(err, jc.ErrorIsNil) 399 400 c.Check(mig.StatusMessage(), gc.Equals, "") 401 c.Check(mig2.StatusMessage(), gc.Equals, "") 402 403 err = mig.SetStatusMessage("foo bar") 404 c.Assert(err, jc.ErrorIsNil) 405 406 c.Check(mig.StatusMessage(), gc.Equals, "foo bar") 407 408 c.Assert(mig2.Refresh(), jc.ErrorIsNil) 409 c.Check(mig2.StatusMessage(), gc.Equals, "foo bar") 410 } 411 412 func (s *ModelMigrationSuite) TestWatchForModelMigration(c *gc.C) { 413 // Start watching for migration. 414 w, wc := s.createWatcher(c, s.State2) 415 wc.AssertNoChange() 416 417 // Create the migration - should be reported. 418 mig, err := s.State2.CreateModelMigration(s.stdSpec) 419 c.Assert(err, jc.ErrorIsNil) 420 wc.AssertOneChange() 421 422 // Ending the migration should not be reported. 423 c.Check(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 424 wc.AssertNoChange() 425 426 statetesting.AssertStop(c, w) 427 wc.AssertClosed() 428 } 429 430 func (s *ModelMigrationSuite) TestWatchForModelMigrationInProgress(c *gc.C) { 431 // Create a migration. 432 _, err := s.State2.CreateModelMigration(s.stdSpec) 433 c.Assert(err, jc.ErrorIsNil) 434 435 // Start watching for a migration - the in progress one should be reported. 436 _, wc := s.createWatcher(c, s.State2) 437 wc.AssertOneChange() 438 } 439 440 func (s *ModelMigrationSuite) TestWatchForModelMigrationMultiModel(c *gc.C) { 441 _, wc2 := s.createWatcher(c, s.State2) 442 wc2.AssertNoChange() 443 444 // Create another hosted model to migrate and watch for 445 // migrations. 446 State3 := s.Factory.MakeModel(c, nil) 447 s.AddCleanup(func(*gc.C) { State3.Close() }) 448 _, wc3 := s.createWatcher(c, State3) 449 wc3.AssertNoChange() 450 451 // Create a migration for 2. 452 _, err := s.State2.CreateModelMigration(s.stdSpec) 453 c.Assert(err, jc.ErrorIsNil) 454 wc2.AssertOneChange() 455 wc3.AssertNoChange() 456 457 // Create a migration for 3. 458 _, err = State3.CreateModelMigration(s.stdSpec) 459 c.Assert(err, jc.ErrorIsNil) 460 wc2.AssertNoChange() 461 wc3.AssertOneChange() 462 } 463 464 func (s *ModelMigrationSuite) createWatcher(c *gc.C, st *state.State) ( 465 state.NotifyWatcher, statetesting.NotifyWatcherC, 466 ) { 467 w, err := st.WatchForModelMigration() 468 c.Assert(err, jc.ErrorIsNil) 469 s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) }) 470 return w, statetesting.NewNotifyWatcherC(c, st, w) 471 } 472 473 func (s *ModelMigrationSuite) TestWatchMigrationStatus(c *gc.C) { 474 w, wc := s.createStatusWatcher(c, s.State2) 475 wc.AssertOneChange() // Initial event. 476 477 // Create a migration. 478 mig, err := s.State2.CreateModelMigration(s.stdSpec) 479 c.Assert(err, jc.ErrorIsNil) 480 wc.AssertOneChange() 481 482 // End it. 483 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 484 wc.AssertOneChange() 485 c.Assert(mig.SetPhase(migration.ABORTDONE), jc.ErrorIsNil) 486 wc.AssertOneChange() 487 488 // Start another. 489 mig2, err := s.State2.CreateModelMigration(s.stdSpec) 490 c.Assert(err, jc.ErrorIsNil) 491 wc.AssertOneChange() 492 493 // Change phase. 494 c.Assert(mig2.SetPhase(migration.READONLY), jc.ErrorIsNil) 495 wc.AssertOneChange() 496 497 // End it. 498 c.Assert(mig2.SetPhase(migration.ABORT), jc.ErrorIsNil) 499 wc.AssertOneChange() 500 501 statetesting.AssertStop(c, w) 502 wc.AssertClosed() 503 } 504 505 func (s *ModelMigrationSuite) TestWatchMigrationStatusPreexisting(c *gc.C) { 506 // Create an aborted migration. 507 mig, err := s.State2.CreateModelMigration(s.stdSpec) 508 c.Assert(err, jc.ErrorIsNil) 509 c.Assert(mig.SetPhase(migration.ABORT), jc.ErrorIsNil) 510 511 _, wc := s.createStatusWatcher(c, s.State2) 512 wc.AssertOneChange() 513 } 514 515 func (s *ModelMigrationSuite) TestWatchMigrationStatusMultiModel(c *gc.C) { 516 _, wc2 := s.createStatusWatcher(c, s.State2) 517 wc2.AssertOneChange() 518 519 // Create another hosted model to migrate and watch for 520 // migrations. 521 State3 := s.Factory.MakeModel(c, nil) 522 s.AddCleanup(func(*gc.C) { State3.Close() }) 523 _, wc3 := s.createStatusWatcher(c, State3) 524 wc3.AssertOneChange() 525 526 // Create a migration for 2. 527 mig, err := s.State2.CreateModelMigration(s.stdSpec) 528 c.Assert(err, jc.ErrorIsNil) 529 wc2.AssertOneChange() 530 wc3.AssertNoChange() 531 532 // Create a migration for 3. 533 _, err = State3.CreateModelMigration(s.stdSpec) 534 c.Assert(err, jc.ErrorIsNil) 535 wc2.AssertNoChange() 536 wc3.AssertOneChange() 537 538 // Update the migration for 2. 539 err = mig.SetPhase(migration.ABORT) 540 c.Assert(err, jc.ErrorIsNil) 541 wc2.AssertOneChange() 542 wc3.AssertNoChange() 543 } 544 545 func (s *ModelMigrationSuite) createStatusWatcher(c *gc.C, st *state.State) ( 546 state.NotifyWatcher, statetesting.NotifyWatcherC, 547 ) { 548 w, err := st.WatchMigrationStatus() 549 c.Assert(err, jc.ErrorIsNil) 550 s.AddCleanup(func(c *gc.C) { statetesting.AssertStop(c, w) }) 551 return w, statetesting.NewNotifyWatcherC(c, st, w) 552 } 553 554 func assertPhase(c *gc.C, mig state.ModelMigration, phase migration.Phase) { 555 actualPhase, err := mig.Phase() 556 c.Assert(err, jc.ErrorIsNil) 557 c.Check(actualPhase, gc.Equals, phase) 558 } 559 560 func assertMigrationActive(c *gc.C, st *state.State) { 561 c.Check(isMigrationActive(c, st), jc.IsTrue) 562 } 563 564 func assertMigrationNotActive(c *gc.C, st *state.State) { 565 c.Check(isMigrationActive(c, st), jc.IsFalse) 566 } 567 568 func isMigrationActive(c *gc.C, st *state.State) bool { 569 isActive, err := st.IsModelMigrationActive() 570 c.Assert(err, jc.ErrorIsNil) 571 return isActive 572 } 573 574 func checkIdAndAttempt(c *gc.C, mig state.ModelMigration, expected int) { 575 c.Check(mig.Id(), gc.Equals, fmt.Sprintf("%s:%d", mig.ModelUUID(), expected)) 576 attempt, err := mig.Attempt() 577 c.Assert(err, jc.ErrorIsNil) 578 c.Check(attempt, gc.Equals, expected) 579 }