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 }