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  }