func (s *Suite) TestMigration(c *gc.C) { masterClient := newStubMasterClient(s.stub) w := migrationmaster.New(masterClient) // Trigger migration. masterClient.watcher.changes <- migration.TargetInfo{ ControllerTag: names.NewModelTag("uuid"), Addrs: []string{"1.2.3.4:5"}, CACert: "cert", AuthTag: names.NewUserTag("admin"), Password: "******", } // This error is temporary while migrationmaster is a WIP. runWorkerAndWait(c, w, "migration seen and aborted") // Observe that the migration was seen, the model exported, an API // connection to the target controller was made, the model was // imported and then the migration aborted. s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.Export", nil}, {"apiOpen", []interface{}{&api.Info{ Addrs: []string{"1.2.3.4:5"}, CACert: "cert", Tag: names.NewUserTag("admin"), Password: "******", }, api.DefaultDialOpts()}}, {"APICall:MigrationTarget.Import", []interface{}{params.SerializedModel{Bytes: fakeSerializedModel}}}, {"masterClient.SetPhase", []interface{}{migration.ABORT}}, {"Connection.Close", nil}, }) }
func (s *Suite) TestImportFailure(c *gc.C) { masterClient := newStubMasterClient(s.stub) worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) s.connection.importErr = errors.New("boom") s.triggerMigration(masterClient) err = workertest.CheckKilled(c, worker) c.Assert(err, gc.Equals, migrationmaster.ErrDoneForNow) s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, {"guard.Lockdown", nil}, {"masterClient.SetPhase", []interface{}{migration.READONLY}}, {"masterClient.SetPhase", []interface{}{migration.PRECHECK}}, {"masterClient.SetPhase", []interface{}{migration.IMPORT}}, {"masterClient.Export", nil}, apiOpenCall, importCall, connCloseCall, {"masterClient.SetPhase", []interface{}{migration.ABORT}}, apiOpenCall, abortCall, connCloseCall, {"masterClient.SetPhase", []interface{}{migration.ABORTDONE}}, }) }
func (s *Suite) TestSUCCESSMinionWaitTimeout(c *gc.C) { // The SUCCESS phase is special in that even if some minions fail // to report the migration should continue. There's no turning // back from SUCCESS. s.facade.queueStatus(s.makeStatus(coremigration.SUCCESS)) worker, err := migrationmaster.New(s.config) c.Assert(err, jc.ErrorIsNil) defer workertest.DirtyKill(c, worker) select { case <-s.clock.Alarms(): case <-time.After(coretesting.LongWait): c.Fatal("timed out waiting for clock.After call") } // Move time ahead in order to trigger timeout. s.clock.Advance(15 * time.Minute) err = workertest.CheckKilled(c, worker) c.Assert(err, gc.Equals, migrationmaster.ErrMigrated) s.stub.CheckCalls(c, joinCalls( watchStatusLockdownCalls, []jujutesting.StubCall{ {"facade.WatchMinionReports", nil}, {"facade.SetPhase", []interface{}{coremigration.LOGTRANSFER}}, {"facade.SetPhase", []interface{}{coremigration.REAP}}, {"facade.Reap", nil}, {"facade.SetPhase", []interface{}{coremigration.DONE}}, }, )) }
func (s *Suite) TestWatchFailure(c *gc.C) { masterClient := newStubMasterClient(s.stub) masterClient.watchErr = errors.New("boom") worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) err = workertest.CheckKilled(c, worker) c.Assert(err, gc.ErrorMatches, "watching for migration: boom") }
func checkNotValid(c *gc.C, config migrationmaster.Config, expect string) { check := func(err error) { c.Check(err, gc.ErrorMatches, expect) c.Check(err, jc.Satisfies, errors.IsNotValid) } err := config.Validate() check(err) worker, err := migrationmaster.New(config) c.Check(worker, gc.IsNil) check(err) }
func (s *Suite) TestPreviouslyAbortedMigration(c *gc.C) { s.facade.queueStatus(s.makeStatus(coremigration.ABORTDONE)) worker, err := migrationmaster.New(s.config) c.Assert(err, jc.ErrorIsNil) defer workertest.CleanKill(c, worker) s.waitForStubCalls(c, []string{ "facade.Watch", "facade.MigrationStatus", "guard.Unlock", }) }
func (s *Suite) TestPreviouslyAbortedMigration(c *gc.C) { masterClient := newStubMasterClient(s.stub) masterClient.status.Phase = migration.ABORTDONE s.triggerMigration(masterClient) worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) workertest.CheckAlive(c, worker) workertest.CleanKill(c, worker) // No reliable way to test stub calls in this case unfortunately. }
func (s *Suite) TestStatusNotFound(c *gc.C) { s.facade.statusErr = ¶ms.Error{Code: params.CodeNotFound} s.facade.triggerWatcher() worker, err := migrationmaster.New(s.config) c.Assert(err, jc.ErrorIsNil) defer workertest.CleanKill(c, worker) s.waitForStubCalls(c, []string{ "facade.Watch", "facade.MigrationStatus", "guard.Unlock", }) }
func (s *Suite) TestStatusError(c *gc.C) { masterClient := newStubMasterClient(s.stub) masterClient.statusErr = errors.New("splat") worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) s.triggerMigration(masterClient) err = workertest.CheckKilled(c, worker) s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, }) }
func (s *Suite) TestPreviouslyCompletedMigration(c *gc.C) { masterClient := newStubMasterClient(s.stub) masterClient.status.Phase = migration.DONE s.triggerMigration(masterClient) worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) err = workertest.CheckKilled(c, worker) c.Assert(errors.Cause(err), gc.Equals, dependency.ErrUninstall) s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, }) }
func (s *Suite) TestStatusNotFound(c *gc.C) { masterClient := newStubMasterClient(s.stub) masterClient.statusErr = ¶ms.Error{Code: params.CodeNotFound} worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) s.triggerMigration(masterClient) workertest.CheckAlive(c, worker) workertest.CleanKill(c, worker) s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, {"guard.Unlock", nil}, }) }
func (s *Suite) TestLockdownError(c *gc.C) { masterClient := newStubMasterClient(s.stub) guard := newStubGuard(s.stub) guard.lockdownErr = errors.New("biff") worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: guard, }) c.Assert(err, jc.ErrorIsNil) s.triggerMigration(masterClient) err = workertest.CheckKilled(c, worker) c.Check(err, gc.ErrorMatches, "biff") s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, {"guard.Lockdown", nil}, }) }
func (s *Suite) TestUnlockError(c *gc.C) { masterClient := newStubMasterClient(s.stub) masterClient.statusErr = ¶ms.Error{Code: params.CodeNotFound} guard := newStubGuard(s.stub) guard.unlockErr = errors.New("pow") worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: guard, }) c.Assert(err, jc.ErrorIsNil) s.triggerMigration(masterClient) err = workertest.CheckKilled(c, worker) c.Check(err, gc.ErrorMatches, "pow") s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, {"guard.Unlock", nil}, }) }
func (s *Suite) TestSuccessfulMigration(c *gc.C) { masterClient := newStubMasterClient(s.stub) worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) s.triggerMigration(masterClient) err = workertest.CheckKilled(c, worker) c.Assert(errors.Cause(err), gc.Equals, dependency.ErrUninstall) // Observe that the migration was seen, the model exported, an API // connection to the target controller was made, the model was // imported and then the migration completed. s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, {"guard.Lockdown", nil}, {"masterClient.SetPhase", []interface{}{migration.READONLY}}, {"masterClient.SetPhase", []interface{}{migration.PRECHECK}}, {"masterClient.SetPhase", []interface{}{migration.IMPORT}}, {"masterClient.Export", nil}, apiOpenCall, importCall, connCloseCall, {"masterClient.SetPhase", []interface{}{migration.VALIDATION}}, apiOpenCall, activateCall, connCloseCall, {"masterClient.SetPhase", []interface{}{migration.SUCCESS}}, {"masterClient.SetPhase", []interface{}{migration.LOGTRANSFER}}, {"masterClient.SetPhase", []interface{}{migration.REAP}}, {"masterClient.SetPhase", []interface{}{migration.DONE}}, }) }
func (s *Suite) TestMigrationResume(c *gc.C) { // Test that a partially complete migration can be resumed. masterClient := newStubMasterClient(s.stub) worker, err := migrationmaster.New(migrationmaster.Config{ Facade: masterClient, Guard: newStubGuard(s.stub), }) c.Assert(err, jc.ErrorIsNil) masterClient.status.Phase = migration.SUCCESS s.triggerMigration(masterClient) err = workertest.CheckKilled(c, worker) c.Assert(errors.Cause(err), gc.Equals, dependency.ErrUninstall) s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.GetMigrationStatus", nil}, {"guard.Lockdown", nil}, {"masterClient.SetPhase", []interface{}{migration.LOGTRANSFER}}, {"masterClient.SetPhase", []interface{}{migration.REAP}}, {"masterClient.SetPhase", []interface{}{migration.DONE}}, }) }
func (s *Suite) runWorker(c *gc.C) error { w, err := migrationmaster.New(s.config) c.Assert(err, jc.ErrorIsNil) defer workertest.DirtyKill(c, w) return workertest.CheckKilled(c, w) }
func (s *Suite) TestWatchFailure(c *gc.C) { client := newStubMasterClient(s.stub) client.watchErr = errors.New("boom") w := migrationmaster.New(client) runWorkerAndWait(c, w, "watching for migration: boom") }