github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/model_test.go (about) 1 // Copyright 2013 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 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/environs/config" 17 "github.com/juju/juju/state" 18 "github.com/juju/juju/testing" 19 "github.com/juju/juju/testing/factory" 20 ) 21 22 type ModelSuite struct { 23 ConnSuite 24 } 25 26 var _ = gc.Suite(&ModelSuite{}) 27 28 func (s *ModelSuite) TestModel(c *gc.C) { 29 model, err := s.State.Model() 30 c.Assert(err, jc.ErrorIsNil) 31 32 expectedTag := names.NewModelTag(model.UUID()) 33 c.Assert(model.Tag(), gc.Equals, expectedTag) 34 c.Assert(model.ControllerTag(), gc.Equals, expectedTag) 35 c.Assert(model.Name(), gc.Equals, "testenv") 36 c.Assert(model.Owner(), gc.Equals, s.Owner) 37 c.Assert(model.Life(), gc.Equals, state.Alive) 38 c.Assert(model.MigrationMode(), gc.Equals, state.MigrationModeActive) 39 } 40 41 func (s *ModelSuite) TestModelDestroy(c *gc.C) { 42 env, err := s.State.Model() 43 c.Assert(err, jc.ErrorIsNil) 44 45 now := state.NowToTheSecond() 46 s.PatchValue(&state.NowToTheSecond, func() time.Time { 47 return now 48 }) 49 50 err = env.Destroy() 51 c.Assert(err, jc.ErrorIsNil) 52 err = env.Refresh() 53 c.Assert(err, jc.ErrorIsNil) 54 c.Assert(env.Life(), gc.Equals, state.Dying) 55 } 56 57 func (s *ModelSuite) TestNewModelNonExistentLocalUser(c *gc.C) { 58 cfg, _ := s.createTestEnvConfig(c) 59 owner := names.NewUserTag("non-existent@local") 60 61 _, _, err := s.State.NewModel(state.ModelArgs{Config: cfg, Owner: owner}) 62 c.Assert(err, gc.ErrorMatches, `cannot create model: user "non-existent" not found`) 63 } 64 65 func (s *ModelSuite) TestNewModelSameUserSameNameFails(c *gc.C) { 66 cfg, _ := s.createTestEnvConfig(c) 67 owner := s.Factory.MakeUser(c, nil).UserTag() 68 69 // Create the first model. 70 _, st1, err := s.State.NewModel(state.ModelArgs{Config: cfg, Owner: owner}) 71 c.Assert(err, jc.ErrorIsNil) 72 defer st1.Close() 73 74 // Attempt to create another model with a different UUID but the 75 // same owner and name as the first. 76 newUUID, err := utils.NewUUID() 77 c.Assert(err, jc.ErrorIsNil) 78 cfg2 := testing.CustomModelConfig(c, testing.Attrs{ 79 "name": cfg.Name(), 80 "uuid": newUUID.String(), 81 }) 82 _, _, err = s.State.NewModel(state.ModelArgs{Config: cfg2, Owner: owner}) 83 errMsg := fmt.Sprintf("model %q for %s already exists", cfg2.Name(), owner.Canonical()) 84 c.Assert(err, gc.ErrorMatches, errMsg) 85 c.Assert(errors.IsAlreadyExists(err), jc.IsTrue) 86 87 // Remove the first model. 88 env1, err := st1.Model() 89 c.Assert(err, jc.ErrorIsNil) 90 err = env1.Destroy() 91 c.Assert(err, jc.ErrorIsNil) 92 // Destroy only sets the model to dying and RemoveAllModelDocs can 93 // only be called on a dead model. Normally, the environ's lifecycle 94 // would be set to dead after machines and services have been cleaned up. 95 err = state.SetModelLifeDead(st1, env1.ModelTag().Id()) 96 c.Assert(err, jc.ErrorIsNil) 97 err = st1.RemoveAllModelDocs() 98 c.Assert(err, jc.ErrorIsNil) 99 100 // We should now be able to create the other model. 101 env2, st2, err := s.State.NewModel(state.ModelArgs{Config: cfg2, Owner: owner}) 102 c.Assert(err, jc.ErrorIsNil) 103 defer st2.Close() 104 c.Assert(env2, gc.NotNil) 105 c.Assert(st2, gc.NotNil) 106 } 107 108 func (s *ModelSuite) TestNewModel(c *gc.C) { 109 cfg, uuid := s.createTestEnvConfig(c) 110 owner := names.NewUserTag("test@remote") 111 112 env, st, err := s.State.NewModel(state.ModelArgs{Config: cfg, Owner: owner}) 113 c.Assert(err, jc.ErrorIsNil) 114 defer st.Close() 115 116 modelTag := names.NewModelTag(uuid) 117 assertEnvMatches := func(env *state.Model) { 118 c.Assert(env.UUID(), gc.Equals, modelTag.Id()) 119 c.Assert(env.Tag(), gc.Equals, modelTag) 120 c.Assert(env.ControllerTag(), gc.Equals, s.modelTag) 121 c.Assert(env.Owner(), gc.Equals, owner) 122 c.Assert(env.Name(), gc.Equals, "testing") 123 c.Assert(env.Life(), gc.Equals, state.Alive) 124 } 125 assertEnvMatches(env) 126 127 // Since the model tag for the State connection is different, 128 // asking for this model through FindEntity returns a not found error. 129 env, err = s.State.GetModel(modelTag) 130 c.Assert(err, jc.ErrorIsNil) 131 assertEnvMatches(env) 132 133 env, err = st.Model() 134 c.Assert(err, jc.ErrorIsNil) 135 assertEnvMatches(env) 136 137 _, err = s.State.FindEntity(modelTag) 138 c.Assert(err, jc.Satisfies, errors.IsNotFound) 139 140 entity, err := st.FindEntity(modelTag) 141 c.Assert(err, jc.ErrorIsNil) 142 c.Assert(entity.Tag(), gc.Equals, modelTag) 143 144 // Ensure the model is functional by adding a machine 145 _, err = st.AddMachine("quantal", state.JobHostUnits) 146 c.Assert(err, jc.ErrorIsNil) 147 } 148 149 func (s *ModelSuite) TestNewModelImportingMode(c *gc.C) { 150 cfg, _ := s.createTestEnvConfig(c) 151 owner := names.NewUserTag("test@remote") 152 153 env, st, err := s.State.NewModel(state.ModelArgs{ 154 Config: cfg, 155 Owner: owner, 156 MigrationMode: state.MigrationModeImporting, 157 }) 158 c.Assert(err, jc.ErrorIsNil) 159 defer st.Close() 160 161 c.Assert(env.MigrationMode(), gc.Equals, state.MigrationModeImporting) 162 } 163 164 func (s *ModelSuite) TestSetMigrationMode(c *gc.C) { 165 cfg, _ := s.createTestEnvConfig(c) 166 owner := names.NewUserTag("test@remote") 167 168 env, st, err := s.State.NewModel(state.ModelArgs{Config: cfg, Owner: owner}) 169 c.Assert(err, jc.ErrorIsNil) 170 defer st.Close() 171 172 err = env.SetMigrationMode(state.MigrationModeExporting) 173 c.Assert(err, jc.ErrorIsNil) 174 c.Assert(env.MigrationMode(), gc.Equals, state.MigrationModeExporting) 175 } 176 177 func (s *ModelSuite) TestControllerModel(c *gc.C) { 178 env, err := s.State.ControllerModel() 179 c.Assert(err, jc.ErrorIsNil) 180 181 expectedTag := names.NewModelTag(env.UUID()) 182 c.Assert(env.Tag(), gc.Equals, expectedTag) 183 c.Assert(env.ControllerTag(), gc.Equals, expectedTag) 184 c.Assert(env.Name(), gc.Equals, "testenv") 185 c.Assert(env.Owner(), gc.Equals, s.Owner) 186 c.Assert(env.Life(), gc.Equals, state.Alive) 187 } 188 189 func (s *ModelSuite) TestControllerModelAccessibleFromOtherModels(c *gc.C) { 190 cfg, _ := s.createTestEnvConfig(c) 191 _, st, err := s.State.NewModel(state.ModelArgs{ 192 Config: cfg, 193 Owner: names.NewUserTag("test@remote"), 194 }) 195 defer st.Close() 196 197 env, err := st.ControllerModel() 198 c.Assert(err, jc.ErrorIsNil) 199 c.Assert(env.Tag(), gc.Equals, s.modelTag) 200 c.Assert(env.Name(), gc.Equals, "testenv") 201 c.Assert(env.Owner(), gc.Equals, s.Owner) 202 c.Assert(env.Life(), gc.Equals, state.Alive) 203 } 204 205 func (s *ModelSuite) TestConfigForControllerEnv(c *gc.C) { 206 otherState := s.Factory.MakeModel(c, &factory.ModelParams{Name: "other"}) 207 defer otherState.Close() 208 209 env, err := otherState.GetModel(s.modelTag) 210 c.Assert(err, jc.ErrorIsNil) 211 212 conf, err := env.Config() 213 c.Assert(err, jc.ErrorIsNil) 214 c.Assert(conf.Name(), gc.Equals, "testenv") 215 c.Assert(conf.UUID(), gc.Equals, s.modelTag.Id()) 216 } 217 218 func (s *ModelSuite) TestConfigForOtherEnv(c *gc.C) { 219 otherState := s.Factory.MakeModel(c, &factory.ModelParams{Name: "other"}) 220 defer otherState.Close() 221 otherEnv, err := otherState.Model() 222 c.Assert(err, jc.ErrorIsNil) 223 224 // By getting the model through a different state connection, 225 // the underlying state pointer in the *state.Model struct has 226 // a different model tag. 227 env, err := s.State.GetModel(otherEnv.ModelTag()) 228 c.Assert(err, jc.ErrorIsNil) 229 230 conf, err := env.Config() 231 c.Assert(err, jc.ErrorIsNil) 232 c.Assert(conf.Name(), gc.Equals, "other") 233 c.Assert(conf.UUID(), gc.Equals, otherEnv.UUID()) 234 } 235 236 // createTestEnvConfig returns a new model config and its UUID for testing. 237 func (s *ModelSuite) createTestEnvConfig(c *gc.C) (*config.Config, string) { 238 uuid, err := utils.NewUUID() 239 c.Assert(err, jc.ErrorIsNil) 240 return testing.CustomModelConfig(c, testing.Attrs{ 241 "name": "testing", 242 "uuid": uuid.String(), 243 }), uuid.String() 244 } 245 246 func (s *ModelSuite) TestModelConfigSameEnvAsState(c *gc.C) { 247 env, err := s.State.Model() 248 c.Assert(err, jc.ErrorIsNil) 249 cfg, err := env.Config() 250 c.Assert(err, jc.ErrorIsNil) 251 c.Assert(cfg.UUID(), gc.Equals, s.State.ModelUUID()) 252 } 253 254 func (s *ModelSuite) TestModelConfigDifferentEnvThanState(c *gc.C) { 255 otherState := s.Factory.MakeModel(c, nil) 256 defer otherState.Close() 257 env, err := otherState.Model() 258 c.Assert(err, jc.ErrorIsNil) 259 cfg, err := env.Config() 260 c.Assert(err, jc.ErrorIsNil) 261 uuid := cfg.UUID() 262 c.Assert(uuid, gc.Equals, env.UUID()) 263 c.Assert(uuid, gc.Not(gc.Equals), s.State.ModelUUID()) 264 } 265 266 func (s *ModelSuite) TestDestroyControllerModel(c *gc.C) { 267 env, err := s.State.Model() 268 c.Assert(err, jc.ErrorIsNil) 269 err = env.Destroy() 270 c.Assert(err, jc.ErrorIsNil) 271 } 272 273 func (s *ModelSuite) TestDestroyOtherModel(c *gc.C) { 274 st2 := s.Factory.MakeModel(c, nil) 275 defer st2.Close() 276 env, err := st2.Model() 277 c.Assert(err, jc.ErrorIsNil) 278 err = env.Destroy() 279 c.Assert(err, jc.ErrorIsNil) 280 } 281 282 func (s *ModelSuite) TestDestroyControllerNonEmptyModelFails(c *gc.C) { 283 st2 := s.Factory.MakeModel(c, nil) 284 defer st2.Close() 285 factory.NewFactory(st2).MakeService(c, nil) 286 287 env, err := s.State.Model() 288 c.Assert(err, jc.ErrorIsNil) 289 c.Assert(env.Destroy(), gc.ErrorMatches, "failed to destroy model: hosting 1 other models") 290 } 291 292 func (s *ModelSuite) TestDestroyControllerEmptyModel(c *gc.C) { 293 st2 := s.Factory.MakeModel(c, nil) 294 defer st2.Close() 295 296 controllerModel, err := s.State.Model() 297 c.Assert(err, jc.ErrorIsNil) 298 c.Assert(controllerModel.Destroy(), jc.ErrorIsNil) 299 c.Assert(controllerModel.Refresh(), jc.ErrorIsNil) 300 c.Assert(controllerModel.Life(), gc.Equals, state.Dying) 301 302 hostedModel, err := st2.Model() 303 c.Assert(err, jc.ErrorIsNil) 304 c.Assert(hostedModel.Life(), gc.Equals, state.Dead) 305 } 306 307 func (s *ModelSuite) TestDestroyControllerAndHostedModels(c *gc.C) { 308 st2 := s.Factory.MakeModel(c, nil) 309 defer st2.Close() 310 factory.NewFactory(st2).MakeService(c, nil) 311 312 controllerEnv, err := s.State.Model() 313 c.Assert(err, jc.ErrorIsNil) 314 c.Assert(controllerEnv.DestroyIncludingHosted(), jc.ErrorIsNil) 315 316 env, err := s.State.Model() 317 c.Assert(err, jc.ErrorIsNil) 318 c.Assert(env.Life(), gc.Equals, state.Dying) 319 320 assertNeedsCleanup(c, s.State) 321 assertCleanupRuns(c, s.State) 322 323 // Cleanups for hosted model enqueued by controller model cleanups. 324 assertNeedsCleanup(c, st2) 325 assertCleanupRuns(c, st2) 326 327 env2, err := st2.Model() 328 c.Assert(err, jc.ErrorIsNil) 329 c.Assert(env2.Life(), gc.Equals, state.Dying) 330 331 c.Assert(st2.ProcessDyingModel(), jc.ErrorIsNil) 332 333 c.Assert(env2.Refresh(), jc.ErrorIsNil) 334 c.Assert(env2.Life(), gc.Equals, state.Dead) 335 336 c.Assert(s.State.ProcessDyingModel(), jc.ErrorIsNil) 337 c.Assert(env.Refresh(), jc.ErrorIsNil) 338 c.Assert(env2.Life(), gc.Equals, state.Dead) 339 } 340 341 func (s *ModelSuite) TestDestroyControllerAndHostedModelsWithResources(c *gc.C) { 342 otherSt := s.Factory.MakeModel(c, nil) 343 defer otherSt.Close() 344 345 assertEnv := func(env *state.Model, st *state.State, life state.Life, expectedMachines, expectedServices int) { 346 c.Assert(env.Refresh(), jc.ErrorIsNil) 347 c.Assert(env.Life(), gc.Equals, life) 348 349 machines, err := st.AllMachines() 350 c.Assert(err, jc.ErrorIsNil) 351 c.Assert(machines, gc.HasLen, expectedMachines) 352 353 services, err := st.AllServices() 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(services, gc.HasLen, expectedServices) 356 } 357 358 // add some machines and services 359 otherEnv, err := otherSt.Model() 360 c.Assert(err, jc.ErrorIsNil) 361 _, err = otherSt.AddMachine("quantal", state.JobHostUnits) 362 c.Assert(err, jc.ErrorIsNil) 363 service := s.Factory.MakeService(c, &factory.ServiceParams{Creator: otherEnv.Owner()}) 364 ch, _, err := service.Charm() 365 c.Assert(err, jc.ErrorIsNil) 366 367 args := state.AddServiceArgs{ 368 Name: service.Name(), 369 Owner: service.GetOwnerTag(), 370 Charm: ch, 371 } 372 service, err = otherSt.AddService(args) 373 c.Assert(err, jc.ErrorIsNil) 374 375 controllerEnv, err := s.State.Model() 376 c.Assert(err, jc.ErrorIsNil) 377 c.Assert(controllerEnv.DestroyIncludingHosted(), jc.ErrorIsNil) 378 379 assertCleanupRuns(c, s.State) 380 assertDoesNotNeedCleanup(c, s.State) 381 assertAllMachinesDeadAndRemove(c, s.State) 382 assertEnv(controllerEnv, s.State, state.Dying, 0, 0) 383 384 err = s.State.ProcessDyingModel() 385 c.Assert(err, gc.ErrorMatches, `one or more hosted models are not yet dead`) 386 387 assertCleanupCount(c, otherSt, 3) 388 assertAllMachinesDeadAndRemove(c, otherSt) 389 assertEnv(otherEnv, otherSt, state.Dying, 0, 0) 390 c.Assert(otherSt.ProcessDyingModel(), jc.ErrorIsNil) 391 392 c.Assert(otherEnv.Refresh(), jc.ErrorIsNil) 393 c.Assert(otherEnv.Life(), gc.Equals, state.Dead) 394 395 c.Assert(s.State.ProcessDyingModel(), jc.ErrorIsNil) 396 c.Assert(controllerEnv.Refresh(), jc.ErrorIsNil) 397 c.Assert(controllerEnv.Life(), gc.Equals, state.Dead) 398 } 399 400 func (s *ModelSuite) TestDestroyControllerEmptyModelRace(c *gc.C) { 401 defer s.Factory.MakeModel(c, nil).Close() 402 403 // Simulate an empty model being added just before the 404 // remove txn is called. 405 defer state.SetBeforeHooks(c, s.State, func() { 406 s.Factory.MakeModel(c, nil).Close() 407 }).Check() 408 409 env, err := s.State.Model() 410 c.Assert(err, jc.ErrorIsNil) 411 c.Assert(env.Destroy(), jc.ErrorIsNil) 412 } 413 414 func (s *ModelSuite) TestDestroyControllerRemoveEmptyAddNonEmptyModel(c *gc.C) { 415 st2 := s.Factory.MakeModel(c, nil) 416 defer st2.Close() 417 418 // Simulate an empty model being removed, and a new non-empty 419 // model being added, just before the remove txn is called. 420 defer state.SetBeforeHooks(c, s.State, func() { 421 // Destroy the empty model, which should move it right 422 // along to Dead, and then remove it. 423 model, err := st2.Model() 424 c.Assert(err, jc.ErrorIsNil) 425 c.Assert(model.Destroy(), jc.ErrorIsNil) 426 err = st2.RemoveAllModelDocs() 427 c.Assert(err, jc.ErrorIsNil) 428 429 // Add a new, non-empty model. This should still prevent 430 // the controller from being destroyed. 431 st3 := s.Factory.MakeModel(c, nil) 432 defer st3.Close() 433 factory.NewFactory(st3).MakeService(c, nil) 434 }).Check() 435 436 env, err := s.State.Model() 437 c.Assert(err, jc.ErrorIsNil) 438 c.Assert(env.Destroy(), gc.ErrorMatches, "failed to destroy model: hosting 1 other models") 439 } 440 441 func (s *ModelSuite) TestDestroyControllerNonEmptyModelRace(c *gc.C) { 442 // Simulate an empty model being added just before the 443 // remove txn is called. 444 defer state.SetBeforeHooks(c, s.State, func() { 445 st := s.Factory.MakeModel(c, nil) 446 defer st.Close() 447 factory.NewFactory(st).MakeService(c, nil) 448 }).Check() 449 450 env, err := s.State.Model() 451 c.Assert(err, jc.ErrorIsNil) 452 c.Assert(env.Destroy(), gc.ErrorMatches, "failed to destroy model: hosting 1 other models") 453 } 454 455 func (s *ModelSuite) TestDestroyControllerAlreadyDyingRaceNoOp(c *gc.C) { 456 env, err := s.State.Model() 457 c.Assert(err, jc.ErrorIsNil) 458 459 // Simulate an model being destroyed by another client just before 460 // the remove txn is called. 461 defer state.SetBeforeHooks(c, s.State, func() { 462 c.Assert(env.Destroy(), jc.ErrorIsNil) 463 }).Check() 464 465 c.Assert(env.Destroy(), jc.ErrorIsNil) 466 } 467 468 func (s *ModelSuite) TestDestroyControllerAlreadyDyingNoOp(c *gc.C) { 469 env, err := s.State.Model() 470 c.Assert(err, jc.ErrorIsNil) 471 472 c.Assert(env.Destroy(), jc.ErrorIsNil) 473 c.Assert(env.Destroy(), jc.ErrorIsNil) 474 } 475 476 func (s *ModelSuite) TestDestroyModelNonEmpty(c *gc.C) { 477 m, err := s.State.Model() 478 c.Assert(err, jc.ErrorIsNil) 479 480 // Add a service to prevent the model from transitioning directly to Dead. 481 s.Factory.MakeService(c, nil) 482 483 c.Assert(m.Destroy(), jc.ErrorIsNil) 484 c.Assert(m.Refresh(), jc.ErrorIsNil) 485 c.Assert(m.Life(), gc.Equals, state.Dying) 486 } 487 488 func (s *ModelSuite) TestDestroyModelAddServiceConcurrently(c *gc.C) { 489 st := s.Factory.MakeModel(c, nil) 490 defer st.Close() 491 m, err := st.Model() 492 c.Assert(err, jc.ErrorIsNil) 493 494 defer state.SetBeforeHooks(c, st, func() { 495 factory.NewFactory(st).MakeService(c, nil) 496 }).Check() 497 498 c.Assert(m.Destroy(), jc.ErrorIsNil) 499 c.Assert(m.Refresh(), jc.ErrorIsNil) 500 c.Assert(m.Life(), gc.Equals, state.Dying) 501 } 502 503 func (s *ModelSuite) TestDestroyModelAddMachineConcurrently(c *gc.C) { 504 st := s.Factory.MakeModel(c, nil) 505 defer st.Close() 506 m, err := st.Model() 507 c.Assert(err, jc.ErrorIsNil) 508 509 defer state.SetBeforeHooks(c, st, func() { 510 factory.NewFactory(st).MakeMachine(c, nil) 511 }).Check() 512 513 c.Assert(m.Destroy(), jc.ErrorIsNil) 514 c.Assert(m.Refresh(), jc.ErrorIsNil) 515 c.Assert(m.Life(), gc.Equals, state.Dying) 516 } 517 518 func (s *ModelSuite) TestDestroyModelEmpty(c *gc.C) { 519 st := s.Factory.MakeModel(c, nil) 520 defer st.Close() 521 m, err := st.Model() 522 c.Assert(err, jc.ErrorIsNil) 523 524 c.Assert(m.Destroy(), jc.ErrorIsNil) 525 c.Assert(m.Refresh(), jc.ErrorIsNil) 526 c.Assert(m.Life(), gc.Equals, state.Dead) 527 } 528 529 func (s *ModelSuite) TestProcessDyingServerEnvironTransitionDyingToDead(c *gc.C) { 530 s.assertDyingEnvironTransitionDyingToDead(c, s.State) 531 } 532 533 func (s *ModelSuite) TestProcessDyingHostedEnvironTransitionDyingToDead(c *gc.C) { 534 st := s.Factory.MakeModel(c, nil) 535 defer st.Close() 536 s.assertDyingEnvironTransitionDyingToDead(c, st) 537 } 538 539 func (s *ModelSuite) assertDyingEnvironTransitionDyingToDead(c *gc.C, st *state.State) { 540 // Add a service to prevent the model from transitioning directly to Dead. 541 // Add the service before getting the Model, otherwise we'll have to run 542 // the transaction twice, and hit the hook point too early. 543 svc := factory.NewFactory(st).MakeService(c, nil) 544 env, err := st.Model() 545 c.Assert(err, jc.ErrorIsNil) 546 547 // ProcessDyingModel is called by a worker after Destroy is called. To 548 // avoid a race, we jump the gun here and test immediately after the 549 // environement was set to dead. 550 defer state.SetAfterHooks(c, st, func() { 551 c.Assert(env.Refresh(), jc.ErrorIsNil) 552 c.Assert(env.Life(), gc.Equals, state.Dying) 553 554 err := svc.Destroy() 555 c.Assert(err, jc.ErrorIsNil) 556 557 c.Assert(st.ProcessDyingModel(), jc.ErrorIsNil) 558 559 c.Assert(env.Refresh(), jc.ErrorIsNil) 560 c.Assert(env.Life(), gc.Equals, state.Dead) 561 }).Check() 562 563 c.Assert(env.Destroy(), jc.ErrorIsNil) 564 } 565 566 func (s *ModelSuite) TestProcessDyingEnvironWithMachinesAndServicesNoOp(c *gc.C) { 567 st := s.Factory.MakeModel(c, nil) 568 defer st.Close() 569 570 // calling ProcessDyingModel on a live environ should fail. 571 err := st.ProcessDyingModel() 572 c.Assert(err, gc.ErrorMatches, "model is not dying") 573 574 // add some machines and services 575 env, err := st.Model() 576 c.Assert(err, jc.ErrorIsNil) 577 _, err = st.AddMachine("quantal", state.JobHostUnits) 578 c.Assert(err, jc.ErrorIsNil) 579 service := s.Factory.MakeService(c, &factory.ServiceParams{Creator: env.Owner()}) 580 ch, _, err := service.Charm() 581 c.Assert(err, jc.ErrorIsNil) 582 args := state.AddServiceArgs{ 583 Name: service.Name(), 584 Owner: service.GetOwnerTag(), 585 Charm: ch, 586 } 587 service, err = st.AddService(args) 588 c.Assert(err, jc.ErrorIsNil) 589 590 assertEnv := func(life state.Life, expectedMachines, expectedServices int) { 591 c.Assert(env.Refresh(), jc.ErrorIsNil) 592 c.Assert(env.Life(), gc.Equals, life) 593 594 machines, err := st.AllMachines() 595 c.Assert(err, jc.ErrorIsNil) 596 c.Assert(machines, gc.HasLen, expectedMachines) 597 598 services, err := st.AllServices() 599 c.Assert(err, jc.ErrorIsNil) 600 c.Assert(services, gc.HasLen, expectedServices) 601 } 602 603 // Simulate processing a dying envrionment after an envrionment is set to 604 // dying, but before the cleanup has removed machines and services. 605 defer state.SetAfterHooks(c, st, func() { 606 assertEnv(state.Dying, 1, 1) 607 err := st.ProcessDyingModel() 608 c.Assert(err, gc.ErrorMatches, `model not empty, found 1 machine\(s\)`) 609 assertEnv(state.Dying, 1, 1) 610 }).Check() 611 612 c.Assert(env.Refresh(), jc.ErrorIsNil) 613 c.Assert(env.Destroy(), jc.ErrorIsNil) 614 } 615 616 func (s *ModelSuite) TestProcessDyingControllerEnvironWithHostedEnvsNoOp(c *gc.C) { 617 // Add a non-empty model to the controller. 618 st := s.Factory.MakeModel(c, nil) 619 defer st.Close() 620 factory.NewFactory(st).MakeService(c, nil) 621 622 controllerEnv, err := s.State.Model() 623 c.Assert(err, jc.ErrorIsNil) 624 c.Assert(controllerEnv.DestroyIncludingHosted(), jc.ErrorIsNil) 625 626 err = s.State.ProcessDyingModel() 627 c.Assert(err, gc.ErrorMatches, `one or more hosted models are not yet dead`) 628 629 c.Assert(controllerEnv.Refresh(), jc.ErrorIsNil) 630 c.Assert(controllerEnv.Life(), gc.Equals, state.Dying) 631 } 632 633 func (s *ModelSuite) TestListModelUsers(c *gc.C) { 634 env, err := s.State.Model() 635 c.Assert(err, jc.ErrorIsNil) 636 637 expected := addModelUsers(c, s.State) 638 obtained, err := env.Users() 639 c.Assert(err, gc.IsNil) 640 641 assertObtainedUsersMatchExpectedUsers(c, obtained, expected) 642 } 643 644 func (s *ModelSuite) TestMisMatchedEnvs(c *gc.C) { 645 // create another model 646 otherEnvState := s.Factory.MakeModel(c, nil) 647 defer otherEnvState.Close() 648 otherEnv, err := otherEnvState.Model() 649 c.Assert(err, jc.ErrorIsNil) 650 651 // get that model from State 652 env, err := s.State.GetModel(otherEnv.ModelTag()) 653 c.Assert(err, jc.ErrorIsNil) 654 655 // check that the Users method errors 656 users, err := env.Users() 657 c.Assert(users, gc.IsNil) 658 c.Assert(err, gc.ErrorMatches, "cannot lookup model users outside the current model") 659 } 660 661 func (s *ModelSuite) TestListUsersTwoModels(c *gc.C) { 662 env, err := s.State.Model() 663 c.Assert(err, jc.ErrorIsNil) 664 665 otherEnvState := s.Factory.MakeModel(c, nil) 666 defer otherEnvState.Close() 667 otherEnv, err := otherEnvState.Model() 668 c.Assert(err, jc.ErrorIsNil) 669 670 // Add users to both models 671 expectedUsers := addModelUsers(c, s.State) 672 expectedUsersOtherEnv := addModelUsers(c, otherEnvState) 673 674 // test that only the expected users are listed for each model 675 obtainedUsers, err := env.Users() 676 c.Assert(err, jc.ErrorIsNil) 677 assertObtainedUsersMatchExpectedUsers(c, obtainedUsers, expectedUsers) 678 679 obtainedUsersOtherEnv, err := otherEnv.Users() 680 c.Assert(err, jc.ErrorIsNil) 681 assertObtainedUsersMatchExpectedUsers(c, obtainedUsersOtherEnv, expectedUsersOtherEnv) 682 } 683 684 func addModelUsers(c *gc.C, st *state.State) (expected []*state.ModelUser) { 685 // get the model owner 686 testAdmin := names.NewUserTag("test-admin") 687 owner, err := st.ModelUser(testAdmin) 688 c.Assert(err, jc.ErrorIsNil) 689 690 f := factory.NewFactory(st) 691 return []*state.ModelUser{ 692 // we expect the owner to be an existing model user 693 owner, 694 // add new users to the model 695 f.MakeModelUser(c, nil), 696 f.MakeModelUser(c, nil), 697 f.MakeModelUser(c, nil), 698 } 699 } 700 701 func assertObtainedUsersMatchExpectedUsers(c *gc.C, obtainedUsers, expectedUsers []*state.ModelUser) { 702 c.Assert(len(obtainedUsers), gc.Equals, len(expectedUsers)) 703 for i, obtained := range obtainedUsers { 704 c.Assert(obtained.ModelTag().Id(), gc.Equals, expectedUsers[i].ModelTag().Id()) 705 c.Assert(obtained.UserName(), gc.Equals, expectedUsers[i].UserName()) 706 c.Assert(obtained.DisplayName(), gc.Equals, expectedUsers[i].DisplayName()) 707 c.Assert(obtained.CreatedBy(), gc.Equals, expectedUsers[i].CreatedBy()) 708 } 709 } 710 711 func (s *ModelSuite) TestAllModels(c *gc.C) { 712 s.Factory.MakeModel(c, &factory.ModelParams{ 713 Name: "test", Owner: names.NewUserTag("bob@remote")}).Close() 714 s.Factory.MakeModel(c, &factory.ModelParams{ 715 Name: "test", Owner: names.NewUserTag("mary@remote")}).Close() 716 envs, err := s.State.AllModels() 717 c.Assert(err, jc.ErrorIsNil) 718 c.Assert(envs, gc.HasLen, 3) 719 var obtained []string 720 for _, env := range envs { 721 obtained = append(obtained, fmt.Sprintf("%s/%s", env.Owner().Canonical(), env.Name())) 722 } 723 expected := []string{ 724 "test-admin@local/testenv", 725 "bob@remote/test", 726 "mary@remote/test", 727 } 728 c.Assert(obtained, jc.SameContents, expected) 729 } 730 731 func (s *ModelSuite) TestHostedModelCount(c *gc.C) { 732 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 0) 733 734 st1 := s.Factory.MakeModel(c, nil) 735 defer st1.Close() 736 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 1) 737 738 st2 := s.Factory.MakeModel(c, nil) 739 defer st2.Close() 740 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 2) 741 742 env1, err := st1.Model() 743 c.Assert(err, jc.ErrorIsNil) 744 c.Assert(env1.Destroy(), jc.ErrorIsNil) 745 c.Assert(st1.RemoveAllModelDocs(), jc.ErrorIsNil) 746 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 1) 747 748 env2, err := st2.Model() 749 c.Assert(err, jc.ErrorIsNil) 750 c.Assert(env2.Destroy(), jc.ErrorIsNil) 751 c.Assert(st2.RemoveAllModelDocs(), jc.ErrorIsNil) 752 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 0) 753 } 754 755 func assertCleanupRuns(c *gc.C, st *state.State) { 756 err := st.Cleanup() 757 c.Assert(err, jc.ErrorIsNil) 758 } 759 760 func assertNeedsCleanup(c *gc.C, st *state.State) { 761 actual, err := st.NeedsCleanup() 762 c.Assert(err, jc.ErrorIsNil) 763 c.Assert(actual, jc.IsTrue) 764 } 765 766 func assertDoesNotNeedCleanup(c *gc.C, st *state.State) { 767 actual, err := st.NeedsCleanup() 768 c.Assert(err, jc.ErrorIsNil) 769 c.Assert(actual, jc.IsFalse) 770 } 771 772 // assertCleanupCount is useful because certain cleanups cause other cleanups 773 // to be queued; it makes more sense to just run cleanup again than to unpick 774 // object destruction so that we run the cleanups inline while running cleanups. 775 func assertCleanupCount(c *gc.C, st *state.State, count int) { 776 for i := 0; i < count; i++ { 777 c.Logf("checking cleanups %d", i) 778 assertNeedsCleanup(c, st) 779 assertCleanupRuns(c, st) 780 } 781 assertDoesNotNeedCleanup(c, st) 782 } 783 784 // The provisioner will remove dead machines once their backing instances are 785 // stopped. For the tests, we remove them directly. 786 func assertAllMachinesDeadAndRemove(c *gc.C, st *state.State) { 787 machines, err := st.AllMachines() 788 c.Assert(err, jc.ErrorIsNil) 789 for _, m := range machines { 790 if m.IsManager() { 791 continue 792 } 793 if _, isContainer := m.ParentId(); isContainer { 794 continue 795 } 796 manual, err := m.IsManual() 797 c.Assert(err, jc.ErrorIsNil) 798 if manual { 799 continue 800 } 801 802 c.Assert(m.Life(), gc.Equals, state.Dead) 803 c.Assert(m.Remove(), jc.ErrorIsNil) 804 } 805 }