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  }