github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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  }