func (s *destroyTwoModelsSuite) TestCanDestroyNonBlockedModel(c *gc.C) { bh := commontesting.NewBlockHelper(s.APIState) defer bh.Close() bh.BlockDestroyModel(c, "TestBlockDestroyDestroyModel") err := common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) err = common.DestroyModel(s.State, s.State.ModelTag()) bh.AssertBlocked(c, err, "TestBlockDestroyDestroyModel") }
func (s *destroyModelSuite) TestBlockRemoveDestroyModel(c *gc.C) { // Setup model s.setUpInstances(c) s.BlockRemoveObject(c, "TestBlockRemoveDestroyModel") err := common.DestroyModel(s.State, s.State.ModelTag()) s.AssertBlocked(c, err, "TestBlockRemoveDestroyModel") }
// DestroyModels will try to destroy the specified models. // If there is a block on destruction, this method will return an error. func (m *ModelManagerAPI) DestroyModels(args params.Entities) (params.ErrorResults, error) { results := params.ErrorResults{ Results: make([]params.ErrorResult, len(args.Entities)), } destroyModel := func(tag names.ModelTag) error { model, err := m.state.GetModel(tag) if err != nil { return errors.Trace(err) } if err := m.authCheck(model.Owner()); err != nil { return errors.Trace(err) } return errors.Trace(common.DestroyModel(m.state, model.ModelTag())) } for i, arg := range args.Entities { tag, err := names.ParseModelTag(arg.Tag) if err != nil { results.Results[i].Error = common.ServerError(err) continue } if err := destroyModel(tag); err != nil { results.Results[i].Error = common.ServerError(err) continue } } return results, nil }
// DestroyController will attempt to destroy the controller. If the args // specify the removal of blocks or the destruction of the models, this // method will attempt to do so. // // If the controller has any non-Dead hosted models, then an error with // the code params.CodeHasHostedModels will be transmitted, regardless of // the value of the DestroyModels parameter. This is to inform the client // that it should wait for hosted models to be completely cleaned up // before proceeding. func (s *ControllerAPI) DestroyController(args params.DestroyControllerArgs) error { hasPermission, err := s.authorizer.HasPermission(permission.SuperuserAccess, s.state.ControllerTag()) if err != nil { return errors.Trace(err) } if !hasPermission { return errors.Trace(common.ErrPerm) } st := common.NewModelManagerBackend(s.state) controllerModel, err := st.ControllerModel() if err != nil { return errors.Trace(err) } systemTag := controllerModel.ModelTag() if err = s.ensureNotBlocked(args); err != nil { return errors.Trace(err) } // If we are destroying models, we need to tolerate living // models but set the controller to dying to prevent new // models sneaking in. If we are not destroying hosted models, // this will fail if any hosted models are found. if args.DestroyModels { return errors.Trace(common.DestroyModelIncludingHosted(st, systemTag)) } if err := common.DestroyModel(st, systemTag); err != nil { return errors.Trace(err) } return nil }
func (s *destroyModelSuite) TestBlockDestroyDestroyEnvironment(c *gc.C) { // Setup environment s.setUpInstances(c) s.BlockDestroyModel(c, "TestBlockDestroyDestroyModel") err := common.DestroyModel(s.State, s.State.ModelTag()) s.AssertBlocked(c, err, "TestBlockDestroyDestroyModel") }
func (s *destroyModelSuite) TestBlockChangesDestroyModel(c *gc.C) { // Setup model s.setUpInstances(c) // lock model: can't destroy locked model s.BlockAllChanges(c, "TestBlockChangesDestroyModel") err := common.DestroyModel(s.State, s.State.ModelTag()) s.AssertBlocked(c, err, "TestBlockChangesDestroyModel") }
// DestroyModel will try to destroy the current model. // If there is a block on destruction, this method will return an error. func (c *Client) DestroyModel() (err error) { if err := c.check.DestroyAllowed(); err != nil { return errors.Trace(err) } modelTag := c.api.stateAccessor.ModelTag() return errors.Trace(common.DestroyModel(c.api.state(), modelTag)) }
func (s *destroyModelSuite) TestMetrics(c *gc.C) { metricSender := &testMetricSender{} s.PatchValue(common.SendMetrics, metricSender.SendMetrics) err := common.DestroyModel(s.State, s.State.ModelTag()) c.Assert(err, jc.ErrorIsNil) metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}}) }
func (s *destroyControllerSuite) TestDestroyControllerNoHostedEnvs(c *gc.C) { err := common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) err = s.controller.DestroyController(params.DestroyControllerArgs{}) c.Assert(err, jc.ErrorIsNil) env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Dying) }
func (s *destroyTwoModelsSuite) TestDestroyControllerAfterNonControllerIsDestroyed(c *gc.C) { otherFactory := factory.NewFactory(s.otherState) otherFactory.MakeMachine(c, nil) m := otherFactory.MakeMachine(c, nil) otherFactory.MakeMachineNested(c, m.Id(), nil) err := common.DestroyModel(s.modelManager, s.State.ModelTag()) c.Assert(err, gc.ErrorMatches, "failed to destroy model: hosting 1 other models") needsCleanup, err := s.State.NeedsCleanup() c.Assert(err, jc.ErrorIsNil) c.Assert(needsCleanup, jc.IsFalse) err = common.DestroyModel(s.modelManager, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) // The hosted model is Dying, not Dead; we cannot destroy // the controller model until all hosted models are Dead. err = common.DestroyModel(s.modelManager, s.State.ModelTag()) c.Assert(err, gc.ErrorMatches, "failed to destroy model: hosting 1 other models") // Continue to take the hosted model down so we can // destroy the controller model. runAllCleanups(c, s.otherState) assertAllMachinesDeadAndRemove(c, s.otherState) c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) err = common.DestroyModel(s.modelManager, s.State.ModelTag()) c.Assert(err, jc.ErrorIsNil) otherEnv, err := s.otherState.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(otherEnv.Life(), gc.Equals, state.Dead) env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Dying) c.Assert(s.State.ProcessDyingModel(), jc.ErrorIsNil) c.Assert(env.Refresh(), jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Dead) }
func (s *destroyControllerSuite) TestDestroyControllerErrsOnNoHostedEnvsWithBlock(c *gc.C) { err := common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) s.BlockDestroyModel(c, "TestBlockDestroyModel") s.BlockRemoveObject(c, "TestBlockRemoveObject") err = s.controller.DestroyController(params.DestroyControllerArgs{}) c.Assert(err, gc.ErrorMatches, "found blocks in controller models") env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Alive) }
func (s *destroyControllerSuite) TestDestroyControllerNoHostedEnvsWithBlockFail(c *gc.C) { err := common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) s.BlockDestroyModel(c, "TestBlockDestroyModel") s.BlockRemoveObject(c, "TestBlockRemoveObject") err = s.controller.DestroyController(params.DestroyControllerArgs{}) c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) numBlocks, err := s.State.AllBlocksForController() c.Assert(err, jc.ErrorIsNil) c.Assert(len(numBlocks), gc.Equals, 2) }
func (s *destroyModelSuite) TestDestroyModelManual(c *gc.C) { _, nonManager := s.setUpManual(c) // If there are any non-manager manual machines in state, DestroyModel will // error. It will not set the Dying flag on the environment. err := common.DestroyModel(s.State, s.State.ModelTag()) 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())) env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Alive) // If we remove the non-manager machine, it should pass. // Manager machines will remain. err = nonManager.EnsureDead() c.Assert(err, jc.ErrorIsNil) err = nonManager.Remove() c.Assert(err, jc.ErrorIsNil) err = common.DestroyModel(s.State, s.State.ModelTag()) c.Assert(err, jc.ErrorIsNil) err = env.Refresh() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Dying) }
func (s *destroyTwoModelsSuite) TestDestroyControllerAfterNonControllerIsDestroyed(c *gc.C) { otherFactory := factory.NewFactory(s.otherState) otherFactory.MakeMachine(c, nil) m := otherFactory.MakeMachine(c, nil) otherFactory.MakeMachineNested(c, m.Id(), nil) err := common.DestroyModel(s.State, s.State.ModelTag()) c.Assert(err, gc.ErrorMatches, "failed to destroy model: hosting 1 other models") needsCleanup, err := s.State.NeedsCleanup() c.Assert(err, jc.ErrorIsNil) c.Assert(needsCleanup, jc.IsFalse) err = common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) err = common.DestroyModel(s.State, s.State.ModelTag()) c.Assert(err, jc.ErrorIsNil) // Make sure we can continue to take the hosted model down while the // controller environ is dying. runAllCleanups(c, s.otherState) assertAllMachinesDeadAndRemove(c, s.otherState) c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) otherEnv, err := s.otherState.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(otherEnv.Life(), gc.Equals, state.Dead) env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Dying) c.Assert(s.State.ProcessDyingModel(), jc.ErrorIsNil) c.Assert(env.Refresh(), jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Dead) }
func (s *destroyModelSuite) TestDestroyModel(c *gc.C) { manager, nonManager, _ := s.setUpInstances(c) managerId, _ := manager.InstanceId() nonManagerId, _ := nonManager.InstanceId() instances, err := s.Environ.Instances([]instance.Id{managerId, nonManagerId}) c.Assert(err, jc.ErrorIsNil) for _, inst := range instances { c.Assert(inst, gc.NotNil) } services, err := s.State.AllServices() c.Assert(err, jc.ErrorIsNil) err = common.DestroyModel(s.State, s.State.ModelTag()) c.Assert(err, jc.ErrorIsNil) runAllCleanups(c, s.State) // After DestroyModel returns and all cleanup jobs have run, we should have: // - all non-manager machines dying assertLife(c, manager, state.Alive) // Note: we leave the machine in a dead state and rely on the provisioner // to stop the backing instances, remove the dead machines and finally // remove all environment docs from state. assertLife(c, nonManager, state.Dead) // - all services in state are Dying or Dead (or removed altogether), // after running the state Cleanups. for _, s := range services { err = s.Refresh() if err != nil { c.Assert(err, jc.Satisfies, errors.IsNotFound) } else { c.Assert(s.Life(), gc.Not(gc.Equals), state.Alive) } } // - environment is Dying or Dead. env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Not(gc.Equals), state.Alive) }
func (s *destroyTwoModelsSuite) TestCleanupModelResources(c *gc.C) { otherFactory := factory.NewFactory(s.otherState) m := otherFactory.MakeMachine(c, nil) otherFactory.MakeMachineNested(c, m.Id(), nil) err := common.DestroyModel(s.otherState, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) // Assert that the machines are not removed until the cleanup runs. c.Assert(m.Refresh(), jc.ErrorIsNil) assertMachineCount(c, s.otherState, 2) runAllCleanups(c, s.otherState) assertAllMachinesDeadAndRemove(c, s.otherState) otherEnv, err := s.otherState.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(otherEnv.Life(), gc.Equals, state.Dying) c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) c.Assert(otherEnv.Refresh(), jc.ErrorIsNil) c.Assert(otherEnv.Life(), gc.Equals, state.Dead) }
// DestroyController will attempt to destroy the controller. If the args // specify the removal of blocks or the destruction of the models, this // method will attempt to do so. // // If the controller has any non-Dead hosted models, then an error with // the code params.CodeHasHostedModels will be transmitted, regardless of // the value of the DestroyModels parameter. This is to inform the client // that it should wait for hosted models to be completely cleaned up // before proceeding. func (s *ControllerAPI) DestroyController(args params.DestroyControllerArgs) error { controllerEnv, err := s.state.ControllerModel() if err != nil { return errors.Trace(err) } systemTag := controllerEnv.ModelTag() if err = s.ensureNotBlocked(args); err != nil { return errors.Trace(err) } // If we are destroying models, we need to tolerate living // models but set the controller to dying to prevent new // models sneaking in. If we are not destroying hosted models, // this will fail if any hosted models are found. if args.DestroyModels { return errors.Trace(common.DestroyModelIncludingHosted(s.state, systemTag)) } if err := common.DestroyModel(s.state, systemTag); err != nil { return errors.Trace(err) } return nil }
func (s *destroyTwoModelsSuite) TestDifferentStateModel(c *gc.C) { otherFactory := factory.NewFactory(s.otherState) otherFactory.MakeMachine(c, nil) m := otherFactory.MakeMachine(c, nil) otherFactory.MakeMachineNested(c, m.Id(), nil) // NOTE: pass in the main test State instance, which is 'bound' // to the controller model. err := common.DestroyModel(s.State, s.otherState.ModelTag()) c.Assert(err, jc.ErrorIsNil) runAllCleanups(c, s.otherState) assertAllMachinesDeadAndRemove(c, s.otherState) otherEnv, err := s.otherState.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(s.otherState.ProcessDyingModel(), jc.ErrorIsNil) c.Assert(otherEnv.Refresh(), jc.ErrorIsNil) c.Assert(otherEnv.Life(), gc.Equals, state.Dead) env, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) c.Assert(env.Life(), gc.Equals, state.Alive) }