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