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  }