github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/client/controller/destroy_test.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/names/v5" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 commontesting "github.com/juju/juju/apiserver/common/testing" 16 "github.com/juju/juju/apiserver/facade/facadetest" 17 "github.com/juju/juju/apiserver/facades/client/controller" 18 apiservertesting "github.com/juju/juju/apiserver/testing" 19 jujutesting "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/rpc/params" 21 "github.com/juju/juju/state" 22 stateerrors "github.com/juju/juju/state/errors" 23 "github.com/juju/juju/testing" 24 "github.com/juju/juju/testing/factory" 25 ) 26 27 // NOTE: the testing of the general model destruction code 28 // is found in apiserver/common/modeldestroy_test.go. 29 // 30 // The tests here are around the validation and behaviour of 31 // the flags passed in to the destroy controller call. 32 33 type destroyControllerSuite struct { 34 jujutesting.JujuConnSuite 35 commontesting.BlockHelper 36 37 authorizer apiservertesting.FakeAuthorizer 38 resources *common.Resources 39 controller *controller.ControllerAPI 40 41 otherState *state.State 42 otherModel *state.Model 43 otherModelOwner names.UserTag 44 otherModelUUID string 45 } 46 47 var _ = gc.Suite(&destroyControllerSuite{}) 48 49 func (s *destroyControllerSuite) SetUpTest(c *gc.C) { 50 s.JujuConnSuite.SetUpTest(c) 51 52 s.BlockHelper = commontesting.NewBlockHelper(s.APIState) 53 s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() }) 54 55 s.resources = common.NewResources() 56 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 57 58 s.authorizer = apiservertesting.FakeAuthorizer{ 59 Tag: s.AdminUserTag(c), 60 } 61 testController, err := controller.NewControllerAPIv11( 62 facadetest.Context{ 63 State_: s.State, 64 StatePool_: s.StatePool, 65 Resources_: s.resources, 66 Auth_: s.authorizer, 67 }) 68 c.Assert(err, jc.ErrorIsNil) 69 s.controller = testController 70 71 s.otherModelOwner = names.NewUserTag("jess@dummy") 72 s.otherState = s.Factory.MakeModel(c, &factory.ModelParams{ 73 Name: "dummytoo", 74 Owner: s.otherModelOwner, 75 ConfigAttrs: testing.Attrs{ 76 "controller": false, 77 }, 78 }) 79 s.AddCleanup(func(c *gc.C) { s.otherState.Close() }) 80 s.otherModelUUID = s.otherState.ModelUUID() 81 82 s.otherModel, err = s.otherState.Model() 83 c.Assert(err, jc.ErrorIsNil) 84 } 85 86 func (s *destroyControllerSuite) TestDestroyControllerKillErrsOnHostedModelsWithBlocks(c *gc.C) { 87 s.BlockDestroyModel(c, "TestBlockDestroyModel") 88 s.BlockRemoveObject(c, "TestBlockRemoveObject") 89 s.otherState.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 90 s.otherState.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 91 92 err := s.controller.DestroyController(params.DestroyControllerArgs{ 93 DestroyModels: true, 94 }) 95 c.Assert(err, gc.ErrorMatches, "found blocks in controller models") 96 97 model, err := s.State.Model() 98 c.Assert(err, jc.ErrorIsNil) 99 c.Assert(model.Life(), gc.Equals, state.Alive) 100 } 101 102 func (s *destroyControllerSuite) TestDestroyControllerReturnsBlockedModelErr(c *gc.C) { 103 s.BlockDestroyModel(c, "TestBlockDestroyModel") 104 s.BlockRemoveObject(c, "TestBlockRemoveObject") 105 s.otherState.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 106 s.otherState.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 107 108 err := s.controller.DestroyController(params.DestroyControllerArgs{ 109 DestroyModels: true, 110 }) 111 c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) 112 113 numBlocks, err := s.State.AllBlocksForController() 114 c.Assert(err, jc.ErrorIsNil) 115 c.Assert(len(numBlocks), gc.Equals, 4) 116 117 _, err = s.otherState.Model() 118 c.Assert(err, jc.ErrorIsNil) 119 } 120 121 func (s *destroyControllerSuite) TestDestroyControllerKillsHostedModels(c *gc.C) { 122 err := s.controller.DestroyController(params.DestroyControllerArgs{ 123 DestroyModels: true, 124 }) 125 c.Assert(err, jc.ErrorIsNil) 126 127 model, err := s.State.Model() 128 c.Assert(err, jc.ErrorIsNil) 129 c.Assert(model.Life(), gc.Equals, state.Dying) 130 } 131 132 func (s *destroyControllerSuite) TestDestroyControllerLeavesBlocksIfNotKillAll(c *gc.C) { 133 s.BlockDestroyModel(c, "TestBlockDestroyModel") 134 s.BlockRemoveObject(c, "TestBlockRemoveObject") 135 s.otherState.SwitchBlockOn(state.DestroyBlock, "TestBlockDestroyModel") 136 s.otherState.SwitchBlockOn(state.ChangeBlock, "TestChangeBlock") 137 138 err := s.controller.DestroyController(params.DestroyControllerArgs{}) 139 c.Assert(err, gc.ErrorMatches, "found blocks in controller models") 140 141 numBlocks, err := s.State.AllBlocksForController() 142 c.Assert(err, jc.ErrorIsNil) 143 c.Assert(len(numBlocks), gc.Equals, 4) 144 } 145 146 func (s *destroyControllerSuite) TestDestroyControllerNoHostedModels(c *gc.C) { 147 err := common.DestroyModel(common.NewModelManagerBackend(s.otherModel, s.StatePool), nil, nil, nil, nil) 148 c.Assert(err, jc.ErrorIsNil) 149 c.Assert(s.otherModel.Refresh(), jc.ErrorIsNil) 150 c.Assert(s.otherModel.Life(), gc.Equals, state.Dying) 151 c.Assert(s.otherModel.State().RemoveDyingModel(), jc.ErrorIsNil) 152 c.Assert(s.otherModel.Refresh(), jc.Satisfies, errors.IsNotFound) 153 154 err = s.controller.DestroyController(params.DestroyControllerArgs{}) 155 c.Assert(err, jc.ErrorIsNil) 156 157 model, err := s.State.Model() 158 c.Assert(err, jc.ErrorIsNil) 159 c.Assert(model.Life(), gc.Equals, state.Dying) 160 } 161 162 func (s *destroyControllerSuite) TestDestroyControllerErrsOnNoHostedModelsWithBlock(c *gc.C) { 163 err := common.DestroyModel(common.NewModelManagerBackend(s.otherModel, s.StatePool), nil, nil, nil, nil) 164 c.Assert(err, jc.ErrorIsNil) 165 166 s.BlockDestroyModel(c, "TestBlockDestroyModel") 167 s.BlockRemoveObject(c, "TestBlockRemoveObject") 168 169 err = s.controller.DestroyController(params.DestroyControllerArgs{}) 170 c.Assert(err, gc.ErrorMatches, "found blocks in controller models") 171 models, err := s.State.Model() 172 c.Assert(err, jc.ErrorIsNil) 173 c.Assert(models.Life(), gc.Equals, state.Alive) 174 } 175 176 func (s *destroyControllerSuite) TestDestroyControllerNoHostedModelsWithBlockFail(c *gc.C) { 177 err := common.DestroyModel(common.NewModelManagerBackend(s.otherModel, s.StatePool), nil, nil, nil, nil) 178 c.Assert(err, jc.ErrorIsNil) 179 180 s.BlockDestroyModel(c, "TestBlockDestroyModel") 181 s.BlockRemoveObject(c, "TestBlockRemoveObject") 182 183 err = s.controller.DestroyController(params.DestroyControllerArgs{}) 184 c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue) 185 186 numBlocks, err := s.State.AllBlocksForController() 187 c.Assert(err, jc.ErrorIsNil) 188 c.Assert(len(numBlocks), gc.Equals, 2) 189 } 190 191 func (s *destroyControllerSuite) TestDestroyControllerDestroyStorageNotSpecified(c *gc.C) { 192 f := factory.NewFactory(s.otherState, s.StatePool) 193 f.MakeUnit(c, &factory.UnitParams{ 194 Application: f.MakeApplication(c, &factory.ApplicationParams{ 195 Charm: f.MakeCharm(c, &factory.CharmParams{ 196 Name: "storage-block", 197 }), 198 Storage: map[string]state.StorageConstraints{ 199 "data": {Pool: "modelscoped"}, 200 }, 201 }), 202 }) 203 204 err := s.controller.DestroyController(params.DestroyControllerArgs{ 205 DestroyModels: true, 206 }) 207 c.Assert(errors.Is(err, stateerrors.PersistentStorageError), jc.IsTrue) 208 209 model, err := s.State.Model() 210 c.Assert(err, jc.ErrorIsNil) 211 c.Assert(model.Life(), gc.Equals, state.Alive) 212 } 213 214 func (s *destroyControllerSuite) TestDestroyControllerDestroyStorageSpecified(c *gc.C) { 215 f := factory.NewFactory(s.otherState, s.StatePool) 216 f.MakeUnit(c, &factory.UnitParams{ 217 Application: f.MakeApplication(c, &factory.ApplicationParams{ 218 Charm: f.MakeCharm(c, &factory.CharmParams{ 219 Name: "storage-block", 220 }), 221 Storage: map[string]state.StorageConstraints{ 222 "data": {Pool: "modelscoped"}, 223 }, 224 }), 225 }) 226 227 destroyStorage := false 228 err := s.controller.DestroyController(params.DestroyControllerArgs{ 229 DestroyModels: true, 230 DestroyStorage: &destroyStorage, 231 }) 232 c.Assert(err, jc.ErrorIsNil) 233 234 model, err := s.State.Model() 235 c.Assert(err, jc.ErrorIsNil) 236 c.Assert(model.Life(), gc.Equals, state.Dying) 237 } 238 239 func (s *destroyControllerSuite) TestDestroyControllerForce(c *gc.C) { 240 force := true 241 timeout := 1 * time.Hour 242 err := s.controller.DestroyController(params.DestroyControllerArgs{ 243 DestroyModels: true, 244 Force: &force, 245 ModelTimeout: &timeout, 246 }) 247 c.Assert(err, jc.ErrorIsNil) 248 model, err := s.State.Model() 249 c.Assert(err, jc.ErrorIsNil) 250 c.Assert(model.ForceDestroyed(), jc.IsTrue) 251 c.Assert(model.DestroyTimeout().Hours(), gc.Equals, 1.0) 252 }