github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/common/environdestroy_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  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/client"
    15  	"github.com/juju/juju/apiserver/common"
    16  	commontesting "github.com/juju/juju/apiserver/common/testing"
    17  	apiservertesting "github.com/juju/juju/apiserver/testing"
    18  	"github.com/juju/juju/environs"
    19  	"github.com/juju/juju/instance"
    20  	"github.com/juju/juju/juju/testing"
    21  	"github.com/juju/juju/provider/dummy"
    22  	"github.com/juju/juju/state"
    23  	jujutesting "github.com/juju/juju/testing"
    24  	"github.com/juju/juju/testing/factory"
    25  	jtesting "github.com/juju/testing"
    26  )
    27  
    28  type destroyEnvironmentSuite struct {
    29  	testing.JujuConnSuite
    30  	commontesting.BlockHelper
    31  	metricSender *testMetricSender
    32  }
    33  
    34  var _ = gc.Suite(&destroyEnvironmentSuite{})
    35  
    36  func (s *destroyEnvironmentSuite) SetUpTest(c *gc.C) {
    37  	s.JujuConnSuite.SetUpTest(c)
    38  	s.BlockHelper = commontesting.NewBlockHelper(s.APIState)
    39  	s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() })
    40  
    41  	s.metricSender = &testMetricSender{}
    42  	s.PatchValue(common.SendMetrics, s.metricSender.SendMetrics)
    43  }
    44  
    45  // setUpManual adds "manually provisioned" machines to state:
    46  // one manager machine, and one non-manager.
    47  func (s *destroyEnvironmentSuite) setUpManual(c *gc.C) (m0, m1 *state.Machine) {
    48  	m0, err := s.State.AddMachine("precise", state.JobManageEnviron)
    49  	c.Assert(err, jc.ErrorIsNil)
    50  	err = m0.SetProvisioned(instance.Id("manual:0"), "manual:0:fake_nonce", nil)
    51  	c.Assert(err, jc.ErrorIsNil)
    52  	m1, err = s.State.AddMachine("precise", state.JobHostUnits)
    53  	c.Assert(err, jc.ErrorIsNil)
    54  	err = m1.SetProvisioned(instance.Id("manual:1"), "manual:1:fake_nonce", nil)
    55  	c.Assert(err, jc.ErrorIsNil)
    56  	return m0, m1
    57  }
    58  
    59  // setUpInstances adds machines to state backed by instances:
    60  // one manager machine, one non-manager, and a container in the
    61  // non-manager.
    62  func (s *destroyEnvironmentSuite) setUpInstances(c *gc.C) (m0, m1, m2 *state.Machine) {
    63  	m0, err := s.State.AddMachine("precise", state.JobManageEnviron)
    64  	c.Assert(err, jc.ErrorIsNil)
    65  	inst, _ := testing.AssertStartInstance(c, s.Environ, m0.Id())
    66  	err = m0.SetProvisioned(inst.Id(), "fake_nonce", nil)
    67  	c.Assert(err, jc.ErrorIsNil)
    68  
    69  	m1, err = s.State.AddMachine("precise", state.JobHostUnits)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	inst, _ = testing.AssertStartInstance(c, s.Environ, m1.Id())
    72  	err = m1.SetProvisioned(inst.Id(), "fake_nonce", nil)
    73  	c.Assert(err, jc.ErrorIsNil)
    74  
    75  	m2, err = s.State.AddMachineInsideMachine(state.MachineTemplate{
    76  		Series: "precise",
    77  		Jobs:   []state.MachineJob{state.JobHostUnits},
    78  	}, m1.Id(), instance.LXC)
    79  	c.Assert(err, jc.ErrorIsNil)
    80  	err = m2.SetProvisioned("container0", "fake_nonce", nil)
    81  	c.Assert(err, jc.ErrorIsNil)
    82  
    83  	return m0, m1, m2
    84  }
    85  
    86  func (s *destroyEnvironmentSuite) TestDestroyEnvironmentManual(c *gc.C) {
    87  	_, nonManager := s.setUpManual(c)
    88  
    89  	// If there are any non-manager manual machines in state, DestroyEnvironment will
    90  	// error. It will not set the Dying flag on the environment.
    91  	err := common.DestroyEnvironment(s.State, s.State.EnvironTag())
    92  	c.Assert(err, gc.ErrorMatches, fmt.Sprintf("failed to destroy environment: manually provisioned machines must first be destroyed with `juju destroy-machine %s`", nonManager.Id()))
    93  	env, err := s.State.Environment()
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	c.Assert(env.Life(), gc.Equals, state.Alive)
    96  
    97  	// If we remove the non-manager machine, it should pass.
    98  	// Manager machines will remain.
    99  	err = nonManager.EnsureDead()
   100  	c.Assert(err, jc.ErrorIsNil)
   101  	err = nonManager.Remove()
   102  	c.Assert(err, jc.ErrorIsNil)
   103  	err = common.DestroyEnvironment(s.State, s.State.EnvironTag())
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	err = env.Refresh()
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	c.Assert(env.Life(), gc.Equals, state.Dying)
   108  
   109  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}})
   110  }
   111  
   112  func (s *destroyEnvironmentSuite) TestDestroyEnvironment(c *gc.C) {
   113  	manager, nonManager, _ := s.setUpInstances(c)
   114  	managerId, _ := manager.InstanceId()
   115  	nonManagerId, _ := nonManager.InstanceId()
   116  
   117  	instances, err := s.Environ.Instances([]instance.Id{managerId, nonManagerId})
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	for _, inst := range instances {
   120  		c.Assert(inst, gc.NotNil)
   121  	}
   122  
   123  	services, err := s.State.AllServices()
   124  	c.Assert(err, jc.ErrorIsNil)
   125  
   126  	err = common.DestroyEnvironment(s.State, s.State.EnvironTag())
   127  	c.Assert(err, jc.ErrorIsNil)
   128  
   129  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}})
   130  
   131  	// After DestroyEnvironment returns, we should have:
   132  	//   - all non-manager instances stopped
   133  	instances, err = s.Environ.Instances([]instance.Id{managerId, nonManagerId})
   134  	c.Assert(err, gc.Equals, environs.ErrPartialInstances)
   135  	c.Assert(instances[0], gc.NotNil)
   136  	c.Assert(instances[1], jc.ErrorIsNil)
   137  	//   - all services in state are Dying or Dead (or removed altogether),
   138  	//     after running the state Cleanups.
   139  	needsCleanup, err := s.State.NeedsCleanup()
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	c.Assert(needsCleanup, jc.IsTrue)
   142  	err = s.State.Cleanup()
   143  	c.Assert(err, jc.ErrorIsNil)
   144  	for _, s := range services {
   145  		err = s.Refresh()
   146  		if err != nil {
   147  			c.Assert(err, jc.Satisfies, errors.IsNotFound)
   148  		} else {
   149  			c.Assert(s.Life(), gc.Not(gc.Equals), state.Alive)
   150  		}
   151  	}
   152  	//   - environment is Dying
   153  	env, err := s.State.Environment()
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	c.Assert(env.Life(), gc.Equals, state.Dying)
   156  }
   157  
   158  func (s *destroyEnvironmentSuite) TestDestroyEnvironmentWithContainers(c *gc.C) {
   159  	ops := make(chan dummy.Operation, 500)
   160  	dummy.Listen(ops)
   161  
   162  	_, nonManager, _ := s.setUpInstances(c)
   163  	nonManagerId, _ := nonManager.InstanceId()
   164  
   165  	err := common.DestroyEnvironment(s.State, s.State.EnvironTag())
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	for op := range ops {
   168  		if op, ok := op.(dummy.OpStopInstances); ok {
   169  			c.Assert(op.Ids, jc.SameContents, []instance.Id{nonManagerId})
   170  			break
   171  		}
   172  	}
   173  
   174  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}})
   175  }
   176  
   177  func (s *destroyEnvironmentSuite) TestBlockDestroyDestroyEnvironment(c *gc.C) {
   178  	// Setup environment
   179  	s.setUpInstances(c)
   180  	s.BlockDestroyEnvironment(c, "TestBlockDestroyDestroyEnvironment")
   181  	err := common.DestroyEnvironment(s.State, s.State.EnvironTag())
   182  	s.AssertBlocked(c, err, "TestBlockDestroyDestroyEnvironment")
   183  	s.metricSender.CheckCalls(c, []jtesting.StubCall{})
   184  }
   185  
   186  func (s *destroyEnvironmentSuite) TestBlockRemoveDestroyEnvironment(c *gc.C) {
   187  	// Setup environment
   188  	s.setUpInstances(c)
   189  	s.BlockRemoveObject(c, "TestBlockRemoveDestroyEnvironment")
   190  	err := common.DestroyEnvironment(s.State, s.State.EnvironTag())
   191  	s.AssertBlocked(c, err, "TestBlockRemoveDestroyEnvironment")
   192  	s.metricSender.CheckCalls(c, []jtesting.StubCall{})
   193  }
   194  
   195  func (s *destroyEnvironmentSuite) TestBlockChangesDestroyEnvironment(c *gc.C) {
   196  	// Setup environment
   197  	s.setUpInstances(c)
   198  	// lock environment: can't destroy locked environment
   199  	s.BlockAllChanges(c, "TestBlockChangesDestroyEnvironment")
   200  	err := common.DestroyEnvironment(s.State, s.State.EnvironTag())
   201  	s.AssertBlocked(c, err, "TestBlockChangesDestroyEnvironment")
   202  	s.metricSender.CheckCalls(c, []jtesting.StubCall{})
   203  }
   204  
   205  type destroyTwoEnvironmentsSuite struct {
   206  	testing.JujuConnSuite
   207  	otherState     *state.State
   208  	otherEnvOwner  names.UserTag
   209  	otherEnvClient *client.Client
   210  	metricSender   *testMetricSender
   211  }
   212  
   213  var _ = gc.Suite(&destroyTwoEnvironmentsSuite{})
   214  
   215  func (s *destroyTwoEnvironmentsSuite) SetUpTest(c *gc.C) {
   216  	s.JujuConnSuite.SetUpTest(c)
   217  	_, err := s.State.AddUser("jess", "jess", "", "test")
   218  	c.Assert(err, jc.ErrorIsNil)
   219  	s.otherEnvOwner = names.NewUserTag("jess")
   220  	s.otherState = factory.NewFactory(s.State).MakeEnvironment(c, &factory.EnvParams{
   221  		Owner:   s.otherEnvOwner,
   222  		Prepare: true,
   223  		ConfigAttrs: jujutesting.Attrs{
   224  			"state-server": false,
   225  		},
   226  	})
   227  	s.AddCleanup(func(*gc.C) { s.otherState.Close() })
   228  
   229  	// get the client for the other environment
   230  	auth := apiservertesting.FakeAuthorizer{
   231  		Tag:            s.otherEnvOwner,
   232  		EnvironManager: false,
   233  	}
   234  	s.otherEnvClient, err = client.NewClient(s.otherState, common.NewResources(), auth)
   235  	c.Assert(err, jc.ErrorIsNil)
   236  
   237  	s.metricSender = &testMetricSender{}
   238  	s.PatchValue(common.SendMetrics, s.metricSender.SendMetrics)
   239  }
   240  
   241  func (s *destroyTwoEnvironmentsSuite) TestCleanupEnvironDocs(c *gc.C) {
   242  	otherFactory := factory.NewFactory(s.otherState)
   243  	otherFactory.MakeMachine(c, nil)
   244  	m := otherFactory.MakeMachine(c, nil)
   245  	otherFactory.MakeMachineNested(c, m.Id(), nil)
   246  
   247  	err := common.DestroyEnvironment(s.otherState, s.otherState.EnvironTag())
   248  	c.Assert(err, jc.ErrorIsNil)
   249  
   250  	_, err = s.otherState.Environment()
   251  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
   252  
   253  	_, err = s.State.Environment()
   254  	c.Assert(err, jc.ErrorIsNil)
   255  	c.Assert(s.otherState.EnsureEnvironmentRemoved(), jc.ErrorIsNil)
   256  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}})
   257  }
   258  
   259  func (s *destroyTwoEnvironmentsSuite) TestDifferentStateEnv(c *gc.C) {
   260  	otherFactory := factory.NewFactory(s.otherState)
   261  	otherFactory.MakeMachine(c, nil)
   262  	m := otherFactory.MakeMachine(c, nil)
   263  	otherFactory.MakeMachineNested(c, m.Id(), nil)
   264  
   265  	// NOTE: pass in the main test State instance, which is 'bound'
   266  	// to the state server environment.
   267  	err := common.DestroyEnvironment(s.State, s.otherState.EnvironTag())
   268  	c.Assert(err, jc.ErrorIsNil)
   269  
   270  	_, err = s.otherState.Environment()
   271  	c.Assert(errors.IsNotFound(err), jc.IsTrue)
   272  
   273  	_, err = s.State.Environment()
   274  	c.Assert(err, jc.ErrorIsNil)
   275  	c.Assert(s.otherState.EnsureEnvironmentRemoved(), jc.ErrorIsNil)
   276  
   277  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}})
   278  }
   279  
   280  func (s *destroyTwoEnvironmentsSuite) TestDestroyStateServerAfterNonStateServerIsDestroyed(c *gc.C) {
   281  	err := common.DestroyEnvironment(s.State, s.State.EnvironTag())
   282  	c.Assert(err, gc.ErrorMatches, "failed to destroy environment: hosting 1 other environments")
   283  	err = common.DestroyEnvironment(s.State, s.otherState.EnvironTag())
   284  	c.Assert(err, jc.ErrorIsNil)
   285  	err = common.DestroyEnvironment(s.State, s.State.EnvironTag())
   286  	c.Assert(err, jc.ErrorIsNil)
   287  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}, {FuncName: "SendMetrics"}})
   288  }
   289  
   290  func (s *destroyTwoEnvironmentsSuite) TestCanDestroyNonBlockedEnv(c *gc.C) {
   291  	bh := commontesting.NewBlockHelper(s.APIState)
   292  	defer bh.Close()
   293  
   294  	bh.BlockDestroyEnvironment(c, "TestBlockDestroyDestroyEnvironment")
   295  
   296  	err := common.DestroyEnvironment(s.State, s.otherState.EnvironTag())
   297  	c.Assert(err, jc.ErrorIsNil)
   298  
   299  	err = common.DestroyEnvironment(s.State, s.State.EnvironTag())
   300  	bh.AssertBlocked(c, err, "TestBlockDestroyDestroyEnvironment")
   301  
   302  	s.metricSender.CheckCalls(c, []jtesting.StubCall{{FuncName: "SendMetrics"}})
   303  }
   304  
   305  type testMetricSender struct {
   306  	jtesting.Stub
   307  }
   308  
   309  func (t *testMetricSender) SendMetrics(st *state.State) error {
   310  	t.AddCall("SendMetrics")
   311  	return nil
   312  }