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 }