github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/migrationtarget/migrationtarget_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package migrationtarget_test
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/juju/description/v5"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/names/v5"
    13  	"github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	"github.com/juju/utils/v3"
    16  	"github.com/juju/version/v2"
    17  	gc "gopkg.in/check.v1"
    18  
    19  	"github.com/juju/juju/apiserver"
    20  	"github.com/juju/juju/apiserver/common"
    21  	apiservererrors "github.com/juju/juju/apiserver/errors"
    22  	"github.com/juju/juju/apiserver/facade/facadetest"
    23  	"github.com/juju/juju/apiserver/facades/controller/migrationtarget"
    24  	apiservertesting "github.com/juju/juju/apiserver/testing"
    25  	"github.com/juju/juju/caas"
    26  	"github.com/juju/juju/cloud"
    27  	"github.com/juju/juju/core/crossmodel"
    28  	"github.com/juju/juju/core/facades"
    29  	"github.com/juju/juju/core/instance"
    30  	"github.com/juju/juju/core/leadership"
    31  	"github.com/juju/juju/environs"
    32  	"github.com/juju/juju/environs/context"
    33  	"github.com/juju/juju/environs/instances"
    34  	"github.com/juju/juju/provider/dummy"
    35  	_ "github.com/juju/juju/provider/manual"
    36  	"github.com/juju/juju/rpc/params"
    37  	"github.com/juju/juju/state"
    38  	"github.com/juju/juju/state/stateenvirons"
    39  	statetesting "github.com/juju/juju/state/testing"
    40  	jujutesting "github.com/juju/juju/testing"
    41  	"github.com/juju/juju/testing/factory"
    42  )
    43  
    44  type Suite struct {
    45  	statetesting.StateSuite
    46  	resources  *common.Resources
    47  	authorizer *apiservertesting.FakeAuthorizer
    48  
    49  	facadeContext facadetest.Context
    50  	callContext   context.ProviderCallContext
    51  	leaders       map[string]string
    52  }
    53  
    54  var _ = gc.Suite(&Suite{})
    55  
    56  func (s *Suite) SetUpTest(c *gc.C) {
    57  	// Set up InitialConfig with a dummy provider configuration. This
    58  	// is required to allow model import test to work.
    59  	s.InitialConfig = jujutesting.CustomModelConfig(c, dummy.SampleConfig())
    60  
    61  	// The call to StateSuite's SetUpTest uses s.InitialConfig so
    62  	// it has to happen here.
    63  	s.StateSuite.SetUpTest(c)
    64  
    65  	s.resources = common.NewResources()
    66  	s.AddCleanup(func(*gc.C) { s.resources.StopAll() })
    67  
    68  	s.authorizer = &apiservertesting.FakeAuthorizer{
    69  		Tag:      s.Owner,
    70  		AdminTag: s.Owner,
    71  	}
    72  	s.callContext = context.NewEmptyCloudCallContext()
    73  	s.facadeContext = facadetest.Context{
    74  		State_:     s.State,
    75  		StatePool_: s.StatePool,
    76  		Resources_: s.resources,
    77  		Auth_:      s.authorizer,
    78  	}
    79  
    80  	s.leaders = map[string]string{}
    81  }
    82  
    83  func (s *Suite) TestFacadeRegistered(c *gc.C) {
    84  	aFactory, err := apiserver.AllFacades().GetFactory("MigrationTarget", 3)
    85  	c.Assert(err, jc.ErrorIsNil)
    86  
    87  	api, err := aFactory(&facadetest.Context{
    88  		State_:     s.State,
    89  		Resources_: s.resources,
    90  		Auth_:      s.authorizer,
    91  	})
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	c.Assert(api, gc.FitsTypeOf, new(migrationtarget.API))
    94  }
    95  
    96  func (s *Suite) TestFacadeRegisteredV2(c *gc.C) {
    97  	aFactory, err := apiserver.AllFacades().GetFactory("MigrationTarget", 2)
    98  	c.Assert(err, jc.ErrorIsNil)
    99  
   100  	api, err := aFactory(&facadetest.Context{
   101  		State_:     s.State,
   102  		Resources_: s.resources,
   103  		Auth_:      s.authorizer,
   104  	})
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	c.Assert(api, gc.FitsTypeOf, new(migrationtarget.APIV2))
   107  }
   108  
   109  func (s *Suite) TestNotUser(c *gc.C) {
   110  	s.authorizer.Tag = names.NewMachineTag("0")
   111  	_, err := s.newAPI(nil, nil)
   112  	c.Assert(errors.Cause(err), gc.Equals, apiservererrors.ErrPerm)
   113  }
   114  
   115  func (s *Suite) TestNotControllerAdmin(c *gc.C) {
   116  	s.authorizer.Tag = names.NewUserTag("jrandomuser")
   117  	_, err := s.newAPI(nil, nil)
   118  	c.Assert(errors.Is(err, apiservererrors.ErrPerm), jc.IsTrue)
   119  }
   120  
   121  func (s *Suite) TestCACert(c *gc.C) {
   122  	api := s.mustNewAPI(c)
   123  	r, err := api.CACert()
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	c.Assert(string(r.Result), gc.Equals, jujutesting.CACert)
   126  }
   127  
   128  func (s *Suite) TestPrechecks(c *gc.C) {
   129  	api := s.mustNewAPI(c)
   130  	args := params.MigrationModelInfo{
   131  		UUID:                   "uuid",
   132  		Name:                   "some-model",
   133  		OwnerTag:               names.NewUserTag("someone").String(),
   134  		AgentVersion:           s.controllerVersion(c),
   135  		ControllerAgentVersion: s.controllerVersion(c),
   136  	}
   137  	err := api.Prechecks(args)
   138  	c.Assert(err, jc.ErrorIsNil)
   139  }
   140  
   141  func (s *Suite) TestPrechecksFail(c *gc.C) {
   142  	controllerVersion := s.controllerVersion(c)
   143  
   144  	// Set the model version ahead of the controller.
   145  	modelVersion := controllerVersion
   146  	modelVersion.Minor++
   147  
   148  	api := s.mustNewAPI(c)
   149  	args := params.MigrationModelInfo{
   150  		AgentVersion: modelVersion,
   151  	}
   152  	err := api.Prechecks(args)
   153  	c.Assert(err, gc.NotNil)
   154  }
   155  
   156  func (s *Suite) TestPrechecksFacadeVersionsFail(c *gc.C) {
   157  	controllerVersion := s.controllerVersion(c)
   158  
   159  	api := s.mustNewAPIWithFacadeVersions(c, facades.FacadeVersions{
   160  		"MigrationTarget": []int{1},
   161  	})
   162  	args := params.MigrationModelInfo{
   163  		AgentVersion:           controllerVersion,
   164  		ControllerAgentVersion: controllerVersion,
   165  	}
   166  	err := api.Prechecks(args)
   167  	c.Assert(err, gc.ErrorMatches, `
   168  Source controller does not support required facades for performing migration.
   169  Upgrade the controller to a newer version of .* or migrate to a controller
   170  with an earlier version of the target controller and try again.
   171  
   172  `[1:])
   173  }
   174  
   175  func (s *Suite) TestPrechecksFacadeVersionsWithPatchFail(c *gc.C) {
   176  	controllerVersion := s.controllerVersion(c)
   177  	controllerVersion.Patch++
   178  
   179  	api := s.mustNewAPIWithFacadeVersions(c, facades.FacadeVersions{
   180  		"MigrationTarget": []int{1},
   181  	})
   182  	args := params.MigrationModelInfo{
   183  		AgentVersion:           controllerVersion,
   184  		ControllerAgentVersion: controllerVersion,
   185  	}
   186  	err := api.Prechecks(args)
   187  	c.Assert(err, gc.ErrorMatches, `
   188  Source controller does not support required facades for performing migration.
   189  Upgrade the controller to a newer version of .* or migrate to a controller
   190  with an earlier version of the target controller and try again.
   191  
   192  `[1:])
   193  }
   194  
   195  func (s *Suite) TestImport(c *gc.C) {
   196  	api := s.mustNewAPI(c)
   197  	tag := s.importModel(c, api)
   198  	// Check the model was imported.
   199  	model, ph, err := s.StatePool.GetModel(tag.Id())
   200  	c.Assert(err, jc.ErrorIsNil)
   201  	defer ph.Release()
   202  	c.Assert(model.Name(), gc.Equals, "some-model")
   203  	c.Assert(model.MigrationMode(), gc.Equals, state.MigrationModeImporting)
   204  }
   205  
   206  func (s *Suite) TestImportLeadership(c *gc.C) {
   207  	application := s.Factory.MakeApplication(c, &factory.ApplicationParams{
   208  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{
   209  			Name: "wordpress",
   210  		}),
   211  	})
   212  	for i := 0; i < 3; i++ {
   213  		s.Factory.MakeUnit(c, &factory.UnitParams{Application: application})
   214  	}
   215  	s.leaders = map[string]string{
   216  		"wordpress": "wordpress/2",
   217  	}
   218  
   219  	var claimer fakeClaimer
   220  	s.facadeContext.LeadershipClaimer_ = &claimer
   221  	api := s.mustNewAPI(c)
   222  	s.importModel(c, api)
   223  
   224  	c.Assert(claimer.stub.Calls(), gc.HasLen, 1)
   225  	claimer.stub.CheckCall(c, 0, "ClaimLeadership", "wordpress", "wordpress/2", time.Minute)
   226  }
   227  
   228  func (s *Suite) TestAbort(c *gc.C) {
   229  	api := s.mustNewAPI(c)
   230  	tag := s.importModel(c, api)
   231  
   232  	err := api.Abort(params.ModelArgs{ModelTag: tag.String()})
   233  	c.Assert(err, jc.ErrorIsNil)
   234  
   235  	// The model should no longer exist.
   236  	exists, err := s.State.ModelExists(tag.Id())
   237  	c.Assert(err, jc.ErrorIsNil)
   238  	c.Check(exists, jc.IsFalse)
   239  }
   240  
   241  func (s *Suite) TestAbortNotATag(c *gc.C) {
   242  	api := s.mustNewAPI(c)
   243  	err := api.Abort(params.ModelArgs{ModelTag: "not-a-tag"})
   244  	c.Assert(err, gc.ErrorMatches, `"not-a-tag" is not a valid tag`)
   245  }
   246  
   247  func (s *Suite) TestAbortMissingModel(c *gc.C) {
   248  	api := s.mustNewAPI(c)
   249  	newUUID := utils.MustNewUUID().String()
   250  	err := api.Abort(params.ModelArgs{ModelTag: names.NewModelTag(newUUID).String()})
   251  	c.Assert(err, gc.ErrorMatches, `model "`+newUUID+`" not found`)
   252  }
   253  
   254  func (s *Suite) TestAbortNotImportingModel(c *gc.C) {
   255  	st := s.Factory.MakeModel(c, nil)
   256  	defer st.Close()
   257  	model, err := st.Model()
   258  	c.Assert(err, jc.ErrorIsNil)
   259  
   260  	api := s.mustNewAPI(c)
   261  	err = api.Abort(params.ModelArgs{ModelTag: model.ModelTag().String()})
   262  	c.Assert(err, gc.ErrorMatches, `migration mode for the model is not importing`)
   263  }
   264  
   265  func (s *Suite) TestActivate(c *gc.C) {
   266  	sourceModel := "deadbeef-0bad-400d-8000-4b1d0d06f666"
   267  	_, err := s.State.AddRemoteApplication(state.AddRemoteApplicationParams{
   268  		Name: "foo", SourceModel: names.NewModelTag(sourceModel),
   269  	})
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	api := s.mustNewAPI(c)
   272  	tag := s.importModel(c, api)
   273  
   274  	err = api.Activate(params.ActivateModelArgs{
   275  		ModelTag:        tag.String(),
   276  		ControllerTag:   jujutesting.ControllerTag.String(),
   277  		ControllerAlias: "mycontroller",
   278  		SourceAPIAddrs:  []string{"10.6.6.6:17070"},
   279  		SourceCACert:    jujutesting.CACert,
   280  		CrossModelUUIDs: []string{sourceModel},
   281  	})
   282  	c.Assert(err, jc.ErrorIsNil)
   283  
   284  	model, ph, err := s.StatePool.GetModel(tag.Id())
   285  	c.Assert(err, jc.ErrorIsNil)
   286  	defer ph.Release()
   287  	c.Assert(model.MigrationMode(), gc.Equals, state.MigrationModeNone)
   288  
   289  	ec := state.NewExternalControllers(model.State())
   290  	info, err := ec.ControllerForModel(sourceModel)
   291  	c.Assert(err, jc.ErrorIsNil)
   292  	c.Assert(info.ControllerInfo(), jc.DeepEquals, crossmodel.ControllerInfo{
   293  		ControllerTag: jujutesting.ControllerTag,
   294  		Alias:         "mycontroller",
   295  		Addrs:         []string{"10.6.6.6:17070"},
   296  		CACert:        jujutesting.CACert,
   297  	})
   298  	app, err := model.State().RemoteApplication("foo")
   299  	c.Assert(err, jc.ErrorIsNil)
   300  	c.Assert(app.SourceController(), gc.Equals, jujutesting.ControllerTag.Id())
   301  }
   302  
   303  func (s *Suite) TestActivateNotATag(c *gc.C) {
   304  	api := s.mustNewAPI(c)
   305  	err := api.Activate(params.ActivateModelArgs{ModelTag: "not-a-tag"})
   306  	c.Assert(err, gc.ErrorMatches, `"not-a-tag" is not a valid tag`)
   307  }
   308  
   309  func (s *Suite) TestActivateMissingModel(c *gc.C) {
   310  	api := s.mustNewAPI(c)
   311  	newUUID := utils.MustNewUUID().String()
   312  	err := api.Activate(params.ActivateModelArgs{ModelTag: names.NewModelTag(newUUID).String()})
   313  	c.Assert(err, gc.ErrorMatches, `model "`+newUUID+`" not found`)
   314  }
   315  
   316  func (s *Suite) TestActivateNotImportingModel(c *gc.C) {
   317  	st := s.Factory.MakeModel(c, nil)
   318  	defer st.Close()
   319  	model, err := st.Model()
   320  	c.Assert(err, jc.ErrorIsNil)
   321  
   322  	api := s.mustNewAPI(c)
   323  	err = api.Activate(params.ActivateModelArgs{ModelTag: model.ModelTag().String()})
   324  	c.Assert(err, gc.ErrorMatches, `migration mode for the model is not importing`)
   325  }
   326  
   327  func (s *Suite) TestLatestLogTime(c *gc.C) {
   328  	st := s.Factory.MakeModel(c, nil)
   329  	defer st.Close()
   330  	model, err := st.Model()
   331  	c.Assert(err, jc.ErrorIsNil)
   332  
   333  	t := time.Date(2016, 11, 30, 18, 14, 0, 100, time.UTC)
   334  	tracker := state.NewLastSentLogTracker(st, model.UUID(), "migration-logtransfer")
   335  	defer tracker.Close()
   336  	err = tracker.Set(0, t.UnixNano())
   337  	c.Assert(err, jc.ErrorIsNil)
   338  
   339  	api := s.mustNewAPI(c)
   340  	latest, err := api.LatestLogTime(params.ModelArgs{ModelTag: model.ModelTag().String()})
   341  	c.Assert(err, jc.ErrorIsNil)
   342  	c.Assert(latest, gc.Equals, t)
   343  }
   344  
   345  func (s *Suite) TestLatestLogTimeNeverSet(c *gc.C) {
   346  	st := s.Factory.MakeModel(c, nil)
   347  	defer st.Close()
   348  	model, err := st.Model()
   349  	c.Assert(err, jc.ErrorIsNil)
   350  
   351  	api := s.mustNewAPI(c)
   352  	latest, err := api.LatestLogTime(params.ModelArgs{ModelTag: model.ModelTag().String()})
   353  	c.Assert(err, jc.ErrorIsNil)
   354  	c.Assert(latest, gc.Equals, time.Time{})
   355  }
   356  
   357  func (s *Suite) TestAdoptIAASResources(c *gc.C) {
   358  	st := s.Factory.MakeModel(c, nil)
   359  	defer st.Close()
   360  
   361  	env := mockEnv{Stub: &testing.Stub{}}
   362  	api, err := s.newAPI(func(model stateenvirons.Model) (environs.Environ, error) {
   363  		c.Assert(model.ModelTag().Id(), gc.Equals, st.ModelUUID())
   364  		return &env, nil
   365  	}, func(model stateenvirons.Model) (caas.Broker, error) {
   366  		return nil, errors.New("should not be called")
   367  	})
   368  	c.Assert(err, jc.ErrorIsNil)
   369  
   370  	m, err := st.Model()
   371  	c.Assert(err, jc.ErrorIsNil)
   372  
   373  	err = api.AdoptResources(params.AdoptResourcesArgs{
   374  		ModelTag:                m.ModelTag().String(),
   375  		SourceControllerVersion: version.MustParse("3.2.1"),
   376  	})
   377  	c.Assert(err, jc.ErrorIsNil)
   378  
   379  	c.Assert(env.Stub.Calls(), gc.HasLen, 1)
   380  	aCall := env.Stub.Calls()[0]
   381  	c.Assert(aCall.FuncName, gc.Equals, "AdoptResources")
   382  	c.Assert(aCall.Args[1], gc.Equals, st.ControllerUUID())
   383  	c.Assert(aCall.Args[2], gc.Equals, version.MustParse("3.2.1"))
   384  }
   385  
   386  func (s *Suite) TestAdoptCAASResources(c *gc.C) {
   387  	st := s.Factory.MakeCAASModel(c, nil)
   388  	defer st.Close()
   389  
   390  	broker := mockBroker{Stub: &testing.Stub{}}
   391  	api, err := s.newAPI(func(model stateenvirons.Model) (environs.Environ, error) {
   392  		return nil, errors.New("should not be called")
   393  	}, func(model stateenvirons.Model) (caas.Broker, error) {
   394  		c.Assert(model.ModelTag().Id(), gc.Equals, st.ModelUUID())
   395  		return &broker, nil
   396  	})
   397  	c.Assert(err, jc.ErrorIsNil)
   398  
   399  	m, err := st.Model()
   400  	c.Assert(err, jc.ErrorIsNil)
   401  
   402  	err = api.AdoptResources(params.AdoptResourcesArgs{
   403  		ModelTag:                m.ModelTag().String(),
   404  		SourceControllerVersion: version.MustParse("3.2.1"),
   405  	})
   406  	c.Assert(err, jc.ErrorIsNil)
   407  
   408  	c.Assert(broker.Stub.Calls(), gc.HasLen, 1)
   409  	aCall := broker.Stub.Calls()[0]
   410  	c.Assert(aCall.FuncName, gc.Equals, "AdoptResources")
   411  	c.Assert(aCall.Args[1], gc.Equals, st.ControllerUUID())
   412  	c.Assert(aCall.Args[2], gc.Equals, version.MustParse("3.2.1"))
   413  }
   414  
   415  func (s *Suite) TestCheckMachinesSuccess(c *gc.C) {
   416  	st := s.Factory.MakeModel(c, nil)
   417  	defer st.Close()
   418  
   419  	fact := factory.NewFactory(st, s.StatePool)
   420  	fact.MakeMachine(c, &factory.MachineParams{
   421  		InstanceId: "eriatarka",
   422  	})
   423  	m := fact.MakeMachine(c, &factory.MachineParams{
   424  		InstanceId: "volta",
   425  	})
   426  	c.Assert(m.Id(), gc.Equals, "1")
   427  
   428  	mockEnv := mockEnv{
   429  		Stub: &testing.Stub{},
   430  		instances: []*mockInstance{
   431  			{id: "volta"},
   432  			{id: "eriatarka"},
   433  		},
   434  	}
   435  	api := s.mustNewAPIWithModel(c, &mockEnv, &mockBroker{})
   436  	model, err := st.Model()
   437  	c.Assert(err, jc.ErrorIsNil)
   438  	results, err := api.CheckMachines(
   439  		params.ModelArgs{ModelTag: model.ModelTag().String()})
   440  	c.Assert(err, jc.ErrorIsNil)
   441  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   442  }
   443  
   444  func (s *Suite) TestCheckMachinesHandlesContainers(c *gc.C) {
   445  	st := s.Factory.MakeModel(c, nil)
   446  	defer st.Close()
   447  
   448  	fact := factory.NewFactory(st, s.StatePool)
   449  	m := fact.MakeMachine(c, &factory.MachineParams{
   450  		InstanceId: "birds",
   451  	})
   452  	fact.MakeMachineNested(c, m.Id(), nil)
   453  
   454  	mockEnv := mockEnv{
   455  		Stub:      &testing.Stub{},
   456  		instances: []*mockInstance{{id: "birds"}},
   457  	}
   458  	api := s.mustNewAPIWithModel(c, &mockEnv, &mockBroker{})
   459  	model, err := st.Model()
   460  	c.Assert(err, jc.ErrorIsNil)
   461  	results, err := api.CheckMachines(
   462  		params.ModelArgs{ModelTag: model.ModelTag().String()})
   463  	c.Assert(err, jc.ErrorIsNil)
   464  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   465  }
   466  
   467  func (s *Suite) TestCheckMachinesIgnoresManualMachines(c *gc.C) {
   468  	st := s.Factory.MakeModel(c, nil)
   469  	defer st.Close()
   470  
   471  	fact := factory.NewFactory(st, s.StatePool)
   472  	fact.MakeMachine(c, &factory.MachineParams{
   473  		InstanceId: "birds",
   474  	})
   475  	fact.MakeMachine(c, &factory.MachineParams{
   476  		Nonce: "manual:flibbertigibbert",
   477  	})
   478  
   479  	mockEnv := mockEnv{
   480  		Stub:      &testing.Stub{},
   481  		instances: []*mockInstance{{id: "birds"}},
   482  	}
   483  	api := s.mustNewAPIWithModel(c, &mockEnv, &mockBroker{})
   484  
   485  	model, err := st.Model()
   486  	c.Assert(err, jc.ErrorIsNil)
   487  	results, err := api.CheckMachines(
   488  		params.ModelArgs{ModelTag: model.ModelTag().String()})
   489  	c.Assert(err, jc.ErrorIsNil)
   490  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   491  }
   492  
   493  func (s *Suite) TestCheckMachinesManualCloud(c *gc.C) {
   494  	owner := s.Factory.MakeUser(c, nil)
   495  	err := s.State.AddCloud(cloud.Cloud{
   496  		Name:      "manual",
   497  		Type:      "manual",
   498  		AuthTypes: cloud.AuthTypes{cloud.EmptyAuthType},
   499  		Endpoint:  "10.0.0.1",
   500  	}, owner.Name())
   501  	c.Assert(err, jc.ErrorIsNil)
   502  
   503  	cred := cloud.NewCredential(cloud.EmptyAuthType, nil)
   504  	tag := names.NewCloudCredentialTag(
   505  		fmt.Sprintf("manual/%s/dummy-credential", owner.Name()))
   506  	err = s.State.UpdateCloudCredential(tag, cred)
   507  	c.Assert(err, jc.ErrorIsNil)
   508  
   509  	st := s.Factory.MakeModel(c, &factory.ModelParams{
   510  		CloudName:       "manual",
   511  		CloudCredential: tag,
   512  		Owner:           owner.UserTag(),
   513  	})
   514  	defer st.Close()
   515  
   516  	fact := factory.NewFactory(st, s.StatePool)
   517  	fact.MakeMachine(c, &factory.MachineParams{
   518  		Nonce: "manual:birds",
   519  	})
   520  	fact.MakeMachine(c, &factory.MachineParams{
   521  		Nonce: "manual:flibbertigibbert",
   522  	})
   523  
   524  	mockEnv := mockEnv{
   525  		Stub:      &testing.Stub{},
   526  		instances: []*mockInstance{{id: "birds"}, {id: "flibbertigibbert"}},
   527  	}
   528  	api := s.mustNewAPIWithModel(c, &mockEnv, &mockBroker{})
   529  
   530  	model, err := st.Model()
   531  	c.Assert(err, jc.ErrorIsNil)
   532  	results, err := api.CheckMachines(
   533  		params.ModelArgs{ModelTag: model.ModelTag().String()})
   534  	c.Assert(err, jc.ErrorIsNil)
   535  	c.Assert(results, gc.DeepEquals, params.ErrorResults{})
   536  }
   537  
   538  func (s *Suite) newAPI(environFunc stateenvirons.NewEnvironFunc, brokerFunc stateenvirons.NewCAASBrokerFunc) (*migrationtarget.API, error) {
   539  	api, err := migrationtarget.NewAPI(&s.facadeContext, environFunc, brokerFunc, facades.FacadeVersions{})
   540  	return api, err
   541  }
   542  
   543  func (s *Suite) mustNewAPI(c *gc.C) *migrationtarget.API {
   544  	api, err := s.newAPI(nil, nil)
   545  	c.Assert(err, jc.ErrorIsNil)
   546  	return api
   547  }
   548  
   549  func (s *Suite) newAPIWithFacadeVersions(environFunc stateenvirons.NewEnvironFunc, brokerFunc stateenvirons.NewCAASBrokerFunc, versions facades.FacadeVersions) (*migrationtarget.API, error) {
   550  	api, err := migrationtarget.NewAPI(&s.facadeContext, environFunc, brokerFunc, versions)
   551  	return api, err
   552  }
   553  
   554  func (s *Suite) mustNewAPIWithFacadeVersions(c *gc.C, versions facades.FacadeVersions) *migrationtarget.API {
   555  	api, err := s.newAPIWithFacadeVersions(nil, nil, versions)
   556  	c.Assert(err, jc.ErrorIsNil)
   557  	return api
   558  }
   559  
   560  func (s *Suite) mustNewAPIWithModel(c *gc.C, env environs.Environ, broker caas.Broker) *migrationtarget.API {
   561  	api, err := s.newAPI(func(stateenvirons.Model) (environs.Environ, error) {
   562  		return env, nil
   563  	}, func(stateenvirons.Model) (caas.Broker, error) {
   564  		return broker, nil
   565  	})
   566  	c.Assert(err, jc.ErrorIsNil)
   567  	return api
   568  }
   569  
   570  func (s *Suite) makeExportedModel(c *gc.C) (string, []byte) {
   571  	model, err := s.State.Export(s.leaders)
   572  	c.Assert(err, jc.ErrorIsNil)
   573  
   574  	newUUID := utils.MustNewUUID().String()
   575  	model.UpdateConfig(map[string]interface{}{
   576  		"name": "some-model",
   577  		"uuid": newUUID,
   578  	})
   579  
   580  	bytes, err := description.Serialize(model)
   581  	c.Assert(err, jc.ErrorIsNil)
   582  	return newUUID, bytes
   583  }
   584  
   585  func (s *Suite) controllerVersion(c *gc.C) version.Number {
   586  	cfg, err := s.Model.ModelConfig()
   587  	c.Assert(err, jc.ErrorIsNil)
   588  	vers, ok := cfg.AgentVersion()
   589  	c.Assert(ok, jc.IsTrue)
   590  	return vers
   591  }
   592  
   593  func (s *Suite) importModel(c *gc.C, api *migrationtarget.API) names.ModelTag {
   594  	uuid, bytes := s.makeExportedModel(c)
   595  	err := api.Import(params.SerializedModel{Bytes: bytes})
   596  	c.Assert(err, jc.ErrorIsNil)
   597  	return names.NewModelTag(uuid)
   598  }
   599  
   600  type mockEnv struct {
   601  	environs.Environ
   602  	*testing.Stub
   603  
   604  	instances []*mockInstance
   605  }
   606  
   607  func (e *mockEnv) AdoptResources(ctx context.ProviderCallContext, controllerUUID string, sourceVersion version.Number) error {
   608  	e.MethodCall(e, "AdoptResources", ctx, controllerUUID, sourceVersion)
   609  	return e.NextErr()
   610  }
   611  
   612  func (e *mockEnv) AllInstances(ctx context.ProviderCallContext) ([]instances.Instance, error) {
   613  	e.MethodCall(e, "AllInstances", ctx)
   614  	results := make([]instances.Instance, len(e.instances))
   615  	for i, anInstance := range e.instances {
   616  		results[i] = anInstance
   617  	}
   618  	return results, e.NextErr()
   619  }
   620  
   621  type mockBroker struct {
   622  	caas.Broker
   623  	*testing.Stub
   624  }
   625  
   626  func (e *mockBroker) AdoptResources(ctx context.ProviderCallContext, controllerUUID string, sourceVersion version.Number) error {
   627  	e.MethodCall(e, "AdoptResources", ctx, controllerUUID, sourceVersion)
   628  	return e.NextErr()
   629  }
   630  
   631  type mockInstance struct {
   632  	instances.Instance
   633  	id string
   634  }
   635  
   636  func (i *mockInstance) Id() instance.Id {
   637  	return instance.Id(i.id)
   638  }
   639  
   640  type fakeClaimer struct {
   641  	leadership.Claimer
   642  	stub testing.Stub
   643  }
   644  
   645  func (c *fakeClaimer) ClaimLeadership(application, unit string, duration time.Duration) error {
   646  	c.stub.AddCall("ClaimLeadership", application, unit, duration)
   647  	return c.stub.NextErr()
   648  }