github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/common/modeldestroy_test.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "github.com/juju/errors" 8 jtesting "github.com/juju/testing" 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/api" 14 "github.com/juju/juju/apiserver/common" 15 commontesting "github.com/juju/juju/apiserver/common/testing" 16 "github.com/juju/juju/apiserver/metricsender" 17 "github.com/juju/juju/instance" 18 "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/state" 20 jujutesting "github.com/juju/juju/testing" 21 "github.com/juju/juju/testing/factory" 22 ) 23 24 type destroyModelSuite struct { 25 testing.JujuConnSuite 26 commontesting.BlockHelper 27 modelManager common.ModelManagerBackend 28 } 29 30 var _ = gc.Suite(&destroyModelSuite{}) 31 32 func (s *destroyModelSuite) SetUpTest(c *gc.C) { 33 s.JujuConnSuite.SetUpTest(c) 34 s.BlockHelper = commontesting.NewBlockHelper(s.APIState) 35 s.modelManager = common.NewModelManagerBackend(s.State) 36 s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() }) 37 } 38 39 // setUpManual adds "manually provisioned" machines to state: 40 // one manager machine, and one non-manager. 41 func (s *destroyModelSuite) setUpManual(c *gc.C) (m0, m1 *state.Machine) { 42 m0, err := s.State.AddMachine("precise", state.JobManageModel) 43 c.Assert(err, jc.ErrorIsNil) 44 err = m0.SetProvisioned(instance.Id("manual:0"), "manual:0:fake_nonce", nil) 45 c.Assert(err, jc.ErrorIsNil) 46 m1, err = s.State.AddMachine("precise", state.JobHostUnits) 47 c.Assert(err, jc.ErrorIsNil) 48 err = m1.SetProvisioned(instance.Id("manual:1"), "manual:1:fake_nonce", nil) 49 c.Assert(err, jc.ErrorIsNil) 50 return m0, m1 51 } 52 53 // setUpInstances adds machines to state backed by instances: 54 // one manager machine, one non-manager, and a container in the 55 // non-manager. 56 func (s *destroyModelSuite) setUpInstances(c *gc.C) (m0, m1, m2 *state.Machine) { 57 m0, err := s.State.AddMachine("precise", state.JobManageModel) 58 c.Assert(err, jc.ErrorIsNil) 59 inst, _ := testing.AssertStartInstance(c, s.Environ, s.ControllerConfig.ControllerUUID(), m0.Id()) 60 err = m0.SetProvisioned(inst.Id(), "fake_nonce", nil) 61 c.Assert(err, jc.ErrorIsNil) 62 63 m1, err = s.State.AddMachine("precise", state.JobHostUnits) 64 c.Assert(err, jc.ErrorIsNil) 65 inst, _ = testing.AssertStartInstance(c, s.Environ, s.ControllerConfig.ControllerUUID(), m1.Id()) 66 err = m1.SetProvisioned(inst.Id(), "fake_nonce", nil) 67 c.Assert(err, jc.ErrorIsNil) 68 69 m2, err = s.State.AddMachineInsideMachine(state.MachineTemplate{ 70 Series: "precise", 71 Jobs: []state.MachineJob{state.JobHostUnits}, 72 }, m1.Id(), instance.LXD) 73 c.Assert(err, jc.ErrorIsNil) 74 err = m2.SetProvisioned("container0", "fake_nonce", nil) 75 c.Assert(err, jc.ErrorIsNil) 76 77 return m0, m1, m2 78 } 79 80 type testMetricSender struct { 81 jtesting.Stub 82 } 83 84 func (t *testMetricSender) SendMetrics(st metricsender.ModelBackend) error { 85 t.AddCall("SendMetrics") 86 return nil 87 } 88 89 func (s *destroyModelSuite) TestMetrics(c *gc.C) { 90 metricSender := &testMetricSender{} 91 s.PatchValue(common.SendMetrics, metricSender.SendMetrics) 92 93 err := common.DestroyModel(s.modelManager, s.State.ModelTag()) 94 c.Assert(err, jc.ErrorIsNil) 95 96 metricSender.CheckCalls(c, []jtesting.StubCall{{ 97 FuncName: "SendMetrics", 98 }}) 99 } 100 101 func (s *destroyModelSuite) TestDestroyModel(c *gc.C) { 102 manager, nonManager, _ := s.setUpInstances(c) 103 managerId, _ := manager.InstanceId() 104 nonManagerId, _ := nonManager.InstanceId() 105 106 instances, err := s.Environ.Instances([]instance.Id{managerId, nonManagerId}) 107 c.Assert(err, jc.ErrorIsNil) 108 for _, inst := range instances { 109 c.Assert(inst, gc.NotNil) 110 } 111 112 services, err := s.State.AllApplications() 113 c.Assert(err, jc.ErrorIsNil) 114 115 err = common.DestroyModel(s.modelManager, s.State.ModelTag()) 116 c.Assert(err, jc.ErrorIsNil) 117 118 runAllCleanups(c, s.State) 119 120 // After DestroyModel returns and all cleanup jobs have run, we should have: 121 // - all non-manager machines dying 122 assertLife(c, manager, state.Alive) 123 // Note: we leave the machine in a dead state and rely on the provisioner 124 // to stop the backing instances, remove the dead machines and finally 125 // remove all model docs from state. 126 assertLife(c, nonManager, state.Dead) 127 128 // - all services in state are Dying or Dead (or removed altogether), 129 // after running the state Cleanups. 130 for _, s := range services { 131 err = s.Refresh() 132 if err != nil { 133 c.Assert(err, jc.Satisfies, errors.IsNotFound) 134 } else { 135 c.Assert(s.Life(), gc.Not(gc.Equals), state.Alive) 136 } 137 } 138 // - model is Dying or Dead. 139 model, err := s.State.Model() 140 c.Assert(err, jc.ErrorIsNil) 141 c.Assert(model.Life(), gc.Not(gc.Equals), state.Alive) 142 } 143 144 func assertLife(c *gc.C, entity state.Living, life state.Life) { 145 err := entity.Refresh() 146 c.Assert(err, jc.ErrorIsNil) 147 c.Assert(entity.Life(), gc.Equals, life) 148 } 149 150 func (s *destroyModelSuite) TestBlockDestroyDestroyEnvironment(c *gc.C) { 151 // Setup model 152 s.setUpInstances(c) 153 s.BlockDestroyModel(c, "TestBlockDestroyDestroyModel") 154 err := common.DestroyModel(s.modelManager, s.State.ModelTag()) 155 s.AssertBlocked(c, err, "TestBlockDestroyDestroyModel") 156 } 157 158 func (s *destroyModelSuite) TestBlockDestroyDestroyHostedModel(c *gc.C) { 159 otherSt := s.Factory.MakeModel(c, nil) 160 defer otherSt.Close() 161 info := s.APIInfo(c) 162 info.ModelTag = otherSt.ModelTag() 163 apiState, err := api.Open(info, api.DefaultDialOpts()) 164 165 block := commontesting.NewBlockHelper(apiState) 166 defer block.Close() 167 168 block.BlockDestroyModel(c, "TestBlockDestroyDestroyModel") 169 err = common.DestroyModelIncludingHosted(s.modelManager, s.State.ModelTag()) 170 s.AssertBlocked(c, err, "TestBlockDestroyDestroyModel") 171 } 172 173 func (s *destroyModelSuite) TestBlockRemoveDestroyModel(c *gc.C) { 174 // Setup model 175 s.setUpInstances(c) 176 s.BlockRemoveObject(c, "TestBlockRemoveDestroyModel") 177 err := common.DestroyModel(s.modelManager, s.State.ModelTag()) 178 s.AssertBlocked(c, err, "TestBlockRemoveDestroyModel") 179 } 180 181 func (s *destroyModelSuite) TestBlockChangesDestroyModel(c *gc.C) { 182 // Setup model 183 s.setUpInstances(c) 184 // lock model: can't destroy locked model 185 s.BlockAllChanges(c, "TestBlockChangesDestroyModel") 186 err := common.DestroyModel(s.modelManager, s.State.ModelTag()) 187 s.AssertBlocked(c, err, "TestBlockChangesDestroyModel") 188 } 189 190 type destroyTwoModelsSuite struct { 191 testing.JujuConnSuite 192 otherState *state.State 193 otherModelOwner names.UserTag 194 195 modelManager common.ModelManagerBackend 196 otherModelManager common.ModelManagerBackend 197 } 198 199 var _ = gc.Suite(&destroyTwoModelsSuite{}) 200 201 func (s *destroyTwoModelsSuite) SetUpTest(c *gc.C) { 202 s.JujuConnSuite.SetUpTest(c) 203 _, err := s.State.AddUser("jess", "jess", "", "test") 204 c.Assert(err, jc.ErrorIsNil) 205 s.otherModelOwner = names.NewUserTag("jess") 206 s.otherState = factory.NewFactory(s.State).MakeModel(c, &factory.ModelParams{ 207 Owner: s.otherModelOwner, 208 ConfigAttrs: jujutesting.Attrs{ 209 "controller": false, 210 }, 211 }) 212 s.modelManager = common.NewModelManagerBackend(s.State) 213 s.otherModelManager = common.NewModelManagerBackend(s.otherState) 214 s.AddCleanup(func(*gc.C) { s.otherState.Close() }) 215 } 216 217 func (s *destroyTwoModelsSuite) TestCleanupModelResources(c *gc.C) { 218 otherFactory := factory.NewFactory(s.otherState) 219 m := otherFactory.MakeMachine(c, nil) 220 otherFactory.MakeMachineNested(c, m.Id(), nil) 221 222 err := common.DestroyModel(s.otherModelManager, s.otherState.ModelTag()) 223 c.Assert(err, jc.ErrorIsNil) 224 225 // Assert that the machines are not removed until the cleanup runs. 226 c.Assert(m.Refresh(), jc.ErrorIsNil) 227 assertMachineCount(c, s.otherState, 2) 228 runAllCleanups(c, s.otherState) 229 assertAllMachinesDeadAndRemove(c, s.otherState) 230 231 otherModel, err := s.otherState.Model() 232 c.Assert(err, jc.ErrorIsNil) 233 c.Assert(otherModel.Life(), gc.Equals, state.Dying) 234 235 c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) 236 c.Assert(otherModel.Refresh(), jc.ErrorIsNil) 237 c.Assert(otherModel.Life(), gc.Equals, state.Dead) 238 239 } 240 241 // The provisioner will remove dead machines once their backing instances are 242 // stopped. For the tests, we remove them directly. 243 func assertAllMachinesDeadAndRemove(c *gc.C, st *state.State) { 244 machines, err := st.AllMachines() 245 c.Assert(err, jc.ErrorIsNil) 246 for _, m := range machines { 247 if m.IsManager() { 248 continue 249 } 250 if _, isContainer := m.ParentId(); isContainer { 251 continue 252 } 253 manual, err := m.IsManual() 254 c.Assert(err, jc.ErrorIsNil) 255 if manual { 256 continue 257 } 258 259 c.Assert(m.Life(), gc.Equals, state.Dead) 260 c.Assert(m.Remove(), jc.ErrorIsNil) 261 } 262 } 263 264 func (s *destroyTwoModelsSuite) TestDifferentStateModel(c *gc.C) { 265 otherFactory := factory.NewFactory(s.otherState) 266 otherFactory.MakeMachine(c, nil) 267 m := otherFactory.MakeMachine(c, nil) 268 otherFactory.MakeMachineNested(c, m.Id(), nil) 269 270 // NOTE: pass in the main test State instance, which is 'bound' 271 // to the controller model. 272 err := common.DestroyModel(s.modelManager, s.otherState.ModelTag()) 273 c.Assert(err, jc.ErrorIsNil) 274 275 runAllCleanups(c, s.otherState) 276 assertAllMachinesDeadAndRemove(c, s.otherState) 277 278 otherModel, err := s.otherState.Model() 279 c.Assert(err, jc.ErrorIsNil) 280 c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) 281 c.Assert(otherModel.Refresh(), jc.ErrorIsNil) 282 c.Assert(otherModel.Life(), gc.Equals, state.Dead) 283 284 model, err := s.State.Model() 285 c.Assert(err, jc.ErrorIsNil) 286 c.Assert(model.Life(), gc.Equals, state.Alive) 287 } 288 289 func (s *destroyTwoModelsSuite) TestDestroyControllerAfterNonControllerIsDestroyed(c *gc.C) { 290 otherFactory := factory.NewFactory(s.otherState) 291 otherFactory.MakeMachine(c, nil) 292 m := otherFactory.MakeMachine(c, nil) 293 otherFactory.MakeMachineNested(c, m.Id(), nil) 294 295 err := common.DestroyModel(s.modelManager, s.State.ModelTag()) 296 c.Assert(err, gc.ErrorMatches, "failed to destroy model: hosting 1 other models") 297 298 needsCleanup, err := s.State.NeedsCleanup() 299 c.Assert(err, jc.ErrorIsNil) 300 c.Assert(needsCleanup, jc.IsFalse) 301 302 err = common.DestroyModel(s.modelManager, s.otherState.ModelTag()) 303 c.Assert(err, jc.ErrorIsNil) 304 305 // The hosted model is Dying, not Dead; we cannot destroy 306 // the controller model until all hosted models are Dead. 307 err = common.DestroyModel(s.modelManager, s.State.ModelTag()) 308 c.Assert(err, gc.ErrorMatches, "failed to destroy model: hosting 1 other models") 309 310 // Continue to take the hosted model down so we can 311 // destroy the controller model. 312 runAllCleanups(c, s.otherState) 313 assertAllMachinesDeadAndRemove(c, s.otherState) 314 c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) 315 316 err = common.DestroyModel(s.modelManager, s.State.ModelTag()) 317 c.Assert(err, jc.ErrorIsNil) 318 319 otherEnv, err := s.otherState.Model() 320 c.Assert(err, jc.ErrorIsNil) 321 c.Assert(otherEnv.Life(), gc.Equals, state.Dead) 322 323 env, err := s.State.Model() 324 c.Assert(err, jc.ErrorIsNil) 325 c.Assert(env.Life(), gc.Equals, state.Dying) 326 c.Assert(s.State.ProcessDyingModel(), jc.ErrorIsNil) 327 c.Assert(env.Refresh(), jc.ErrorIsNil) 328 c.Assert(env.Life(), gc.Equals, state.Dead) 329 } 330 331 func (s *destroyTwoModelsSuite) TestDestroyControllerAndNonController(c *gc.C) { 332 otherFactory := factory.NewFactory(s.otherState) 333 otherFactory.MakeMachine(c, nil) 334 m := otherFactory.MakeMachine(c, nil) 335 otherFactory.MakeMachineNested(c, m.Id(), nil) 336 337 err := common.DestroyModelIncludingHosted(s.modelManager, s.State.ModelTag()) 338 c.Assert(err, jc.ErrorIsNil) 339 340 runAllCleanups(c, s.State) 341 runAllCleanups(c, s.otherState) 342 assertAllMachinesDeadAndRemove(c, s.otherState) 343 344 // Make sure we can continue to take the hosted model down while the 345 // controller model is dying. 346 c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) 347 } 348 349 func (s *destroyTwoModelsSuite) TestCanDestroyNonBlockedModel(c *gc.C) { 350 bh := commontesting.NewBlockHelper(s.APIState) 351 defer bh.Close() 352 353 bh.BlockDestroyModel(c, "TestBlockDestroyDestroyModel") 354 355 err := common.DestroyModel(s.modelManager, s.otherState.ModelTag()) 356 c.Assert(err, jc.ErrorIsNil) 357 358 err = common.DestroyModel(s.modelManager, s.State.ModelTag()) 359 bh.AssertBlocked(c, err, "TestBlockDestroyDestroyModel") 360 } 361 362 func runAllCleanups(c *gc.C, st *state.State) { 363 needCleanup, err := st.NeedsCleanup() 364 c.Assert(err, jc.ErrorIsNil) 365 366 for needCleanup { 367 err := st.Cleanup() 368 c.Assert(err, jc.ErrorIsNil) 369 needCleanup, err = st.NeedsCleanup() 370 c.Assert(err, jc.ErrorIsNil) 371 } 372 } 373 374 func assertMachineCount(c *gc.C, st *state.State, count int) { 375 otherMachines, err := st.AllMachines() 376 c.Assert(err, jc.ErrorIsNil) 377 c.Assert(otherMachines, gc.HasLen, count) 378 }