github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/addresser/worker_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package addresser_test 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/api" 15 apiaddresser "github.com/juju/juju/api/addresser" 16 "github.com/juju/juju/feature" 17 "github.com/juju/juju/instance" 18 "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/network" 20 "github.com/juju/juju/provider/common" 21 "github.com/juju/juju/provider/dummy" 22 "github.com/juju/juju/state" 23 coretesting "github.com/juju/juju/testing" 24 "github.com/juju/juju/worker" 25 "github.com/juju/juju/worker/addresser" 26 ) 27 28 type workerSuite struct { 29 testing.JujuConnSuite 30 31 Enabled bool 32 MachineA *state.Machine 33 MachineB *state.Machine 34 35 Worker worker.Worker 36 OpsChan chan dummy.Operation 37 38 APIConnection api.Connection 39 API *apiaddresser.API 40 } 41 42 func (s *workerSuite) SetUpTest(c *gc.C) { 43 s.JujuConnSuite.SetUpTest(c) 44 if s.Enabled { 45 s.SetFeatureFlags(feature.AddressAllocation) 46 } 47 48 // Unbreak dummy provider methods. 49 s.AssertConfigParameterUpdated(c, "broken", "") 50 51 s.APIConnection, _ = s.OpenAPIAsNewMachine(c, state.JobManageModel) 52 s.API = s.APIConnection.Addresser() 53 54 machineA, err := s.State.AddMachine("quantal", state.JobHostUnits) 55 s.MachineA = machineA 56 c.Assert(err, jc.ErrorIsNil) 57 err = s.MachineA.SetProvisioned("foo", "fake_nonce", nil) 58 c.Assert(err, jc.ErrorIsNil) 59 60 // This machine will be destroyed after address creation to test the 61 // handling of addresses for machines that have gone. 62 machineB, err := s.State.AddMachine("quantal", state.JobHostUnits) 63 s.MachineB = machineB 64 c.Assert(err, jc.ErrorIsNil) 65 66 s.createAddresses(c) 67 s.State.StartSync() 68 69 s.OpsChan = make(chan dummy.Operation, 10) 70 dummy.Listen(s.OpsChan) 71 72 // Start the Addresser worker. 73 w, err := addresser.NewWorker(s.API) 74 c.Assert(err, jc.ErrorIsNil) 75 s.Worker = w 76 77 s.waitForInitialDead(c) 78 } 79 80 func (s *workerSuite) TearDownTest(c *gc.C) { 81 c.Assert(worker.Stop(s.Worker), jc.ErrorIsNil) 82 s.JujuConnSuite.TearDownTest(c) 83 } 84 85 func (s *workerSuite) createAddresses(c *gc.C) { 86 addresses := []string{ 87 "0.1.2.3", "0.1.2.4", "0.1.2.5", "0.1.2.6", 88 } 89 for i, rawAddr := range addresses { 90 addr := network.NewAddress(rawAddr) 91 ipAddr, err := s.State.AddIPAddress(addr, "foobar") 92 c.Assert(err, jc.ErrorIsNil) 93 if i%2 == 1 { 94 err = ipAddr.AllocateTo(s.MachineB.Id(), "wobble", "") 95 } else { 96 err = ipAddr.AllocateTo(s.MachineA.Id(), "wobble", "") 97 c.Assert(err, jc.ErrorIsNil) 98 } 99 } 100 // Two of the addresses start out allocated to this 101 // machine which we destroy to test the handling of 102 // addresses allocated to dead machines. 103 err := s.MachineB.EnsureDead() 104 c.Assert(err, jc.ErrorIsNil) 105 err = s.MachineB.Remove() 106 c.Assert(err, jc.ErrorIsNil) 107 } 108 109 func (s *workerSuite) waitForInitialDead(c *gc.C) { 110 for a := common.ShortAttempt.Start(); a.Next(); { 111 dead, err := s.State.DeadIPAddresses() 112 c.Assert(err, jc.ErrorIsNil) 113 if s.Enabled { 114 // We expect dead IP addresses to be removed with 115 // enabled Addresser worker. 116 if len(dead) == 0 { 117 break 118 } 119 if !a.HasNext() { 120 c.Fatalf("timeout waiting for initial change (dead: %#v)", dead) 121 } 122 } else { 123 // Without Addresser worker the dead IP addresses 124 // will stay. 125 if len(dead) == 0 { 126 c.Fatal("IP addresses unexpectedly removed") 127 } 128 } 129 } 130 } 131 132 func (s *workerSuite) waitForReleaseOp(c *gc.C) dummy.OpReleaseAddress { 133 var releaseOp dummy.OpReleaseAddress 134 var ok bool 135 select { 136 case op := <-s.OpsChan: 137 releaseOp, ok = op.(dummy.OpReleaseAddress) 138 c.Assert(ok, jc.IsTrue) 139 case <-time.After(coretesting.LongWait): 140 c.Fatalf("timeout while expecting release operation") 141 } 142 return releaseOp 143 } 144 145 func (s *workerSuite) assertNoReleaseOp(c *gc.C) { 146 select { 147 case op := <-s.OpsChan: 148 _, ok := op.(dummy.OpReleaseAddress) 149 if ok { 150 c.Fatalf("received unexpected release operation") 151 } 152 case <-time.After(coretesting.ShortWait): 153 return 154 } 155 } 156 157 func (s *workerSuite) makeReleaseOp(digit int) dummy.OpReleaseAddress { 158 return dummy.OpReleaseAddress{ 159 Env: "admin", 160 InstanceId: "foo", 161 SubnetId: "foobar", 162 Address: network.NewAddress(fmt.Sprintf("0.1.2.%d", digit)), 163 } 164 } 165 166 func (s *workerSuite) assertIPAddressLife(c *gc.C, value string, life state.Life) { 167 ipAddr, err := s.State.IPAddress(value) 168 c.Assert(err, jc.ErrorIsNil) 169 c.Assert(ipAddr.Life(), gc.Equals, life) 170 } 171 172 func (s *workerSuite) assertIPAddressRemoved(c *gc.C, value string) { 173 for a := common.ShortAttempt.Start(); a.Next(); { 174 _, err := s.State.IPAddress(value) 175 if errors.IsNotFound(err) { 176 break 177 } 178 if !a.HasNext() { 179 c.Fatalf("IP address not removed") 180 } 181 } 182 } 183 184 // workerEnabledSuite runs the test with the enabled address allocation. 185 type workerEnabledSuite struct { 186 workerSuite 187 } 188 189 var _ = gc.Suite(&workerEnabledSuite{}) 190 191 func (s *workerEnabledSuite) SetUpTest(c *gc.C) { 192 s.workerSuite.Enabled = true 193 194 s.workerSuite.SetUpTest(c) 195 } 196 197 func (s *workerEnabledSuite) TestWorkerIsStringsWorker(c *gc.C) { 198 // In case of an environment able to allocte/deallocate 199 // IP addresses the addresser worker is no finished worker. 200 // See also TestWorkerIsFinishedWorker. 201 c.Assert(s.Worker, gc.Not(gc.FitsTypeOf), worker.FinishedWorker{}) 202 } 203 204 func (s *workerEnabledSuite) TestWorkerReleasesAlreadyDead(c *gc.C) { 205 // Wait for releases of 0.1.2.4 and 0.1.2.6 first. It's 206 // explicitely needed for this test for the assertion. 207 op1 := s.waitForReleaseOp(c) 208 op2 := s.waitForReleaseOp(c) 209 210 expected := []dummy.OpReleaseAddress{s.makeReleaseOp(4), s.makeReleaseOp(6)} 211 212 // The machines are dead, so ReleaseAddress should be called with 213 // instance.UnknownId. 214 expected[0].InstanceId = instance.UnknownId 215 expected[1].InstanceId = instance.UnknownId 216 217 c.Assert([]dummy.OpReleaseAddress{op1, op2}, jc.SameContents, expected) 218 } 219 220 func (s *workerEnabledSuite) TestWorkerIgnoresAliveAddresses(c *gc.C) { 221 // Wait for releases of 0.1.2.4 and 0.1.2.6 first. Result is not needed. 222 s.waitForReleaseOp(c) 223 s.waitForReleaseOp(c) 224 225 // Add a new alive address. 226 addr := network.NewAddress("0.1.2.9") 227 ipAddr, err := s.State.AddIPAddress(addr, "foobar") 228 c.Assert(err, jc.ErrorIsNil) 229 err = ipAddr.AllocateTo(s.MachineA.Id(), "wobble", "") 230 c.Assert(err, jc.ErrorIsNil) 231 232 // Assert no ReleaseAddress call.. 233 s.assertNoReleaseOp(c) 234 235 // The worker must not kill this address. 236 for a := common.ShortAttempt.Start(); a.Next(); { 237 s.assertIPAddressLife(c, "0.1.2.9", state.Alive) 238 } 239 } 240 241 func (s *workerEnabledSuite) TestWorkerRemovesDeadAddress(c *gc.C) { 242 // Wait for releases of 0.1.2.4 and 0.1.2.6 first. Result is not needed. 243 s.waitForReleaseOp(c) 244 s.waitForReleaseOp(c) 245 246 // Kill IP address. 247 addr, err := s.State.IPAddress("0.1.2.3") 248 c.Assert(err, jc.ErrorIsNil) 249 err = addr.EnsureDead() 250 c.Assert(err, jc.ErrorIsNil) 251 252 // Wait for ReleaseAddress attempt. 253 op := s.waitForReleaseOp(c) 254 c.Assert(op, jc.DeepEquals, s.makeReleaseOp(3)) 255 256 // The address should have been removed from state. 257 s.assertIPAddressRemoved(c, "0.1.2.3") 258 } 259 260 func (s *workerEnabledSuite) TestWorkerAcceptsBrokenRelease(c *gc.C) { 261 // Wait for releases of 0.1.2.4 and 0.1.2.6 first. Result is not needed. 262 s.waitForReleaseOp(c) 263 s.waitForReleaseOp(c) 264 265 // Break ReleaseAddress and kill IP address 0.1.2.3. 266 s.AssertConfigParameterUpdated(c, "broken", "ReleaseAddress") 267 268 ipAddr, err := s.State.IPAddress("0.1.2.3") 269 c.Assert(err, jc.ErrorIsNil) 270 err = ipAddr.EnsureDead() 271 c.Assert(err, jc.ErrorIsNil) 272 273 // The address should stay in state. 274 s.assertIPAddressLife(c, "0.1.2.3", state.Dead) 275 s.assertNoReleaseOp(c) 276 277 // Make ReleaseAddress work again, it must be cleaned up then. 278 s.AssertConfigParameterUpdated(c, "broken", "") 279 280 // The address should have been removed from state. 281 s.assertIPAddressRemoved(c, "0.1.2.3") 282 } 283 284 func (s *workerEnabledSuite) TestMachineRemovalTriggersWorker(c *gc.C) { 285 // Wait for releases of 0.1.2.4 and 0.1.2.6 first. Result is not needed. 286 s.waitForReleaseOp(c) 287 s.waitForReleaseOp(c) 288 289 // Add special test machine. 290 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 291 c.Assert(err, jc.ErrorIsNil) 292 err = machine.SetProvisioned("foo", "really-fake", nil) 293 c.Assert(err, jc.ErrorIsNil) 294 295 // Add a new alive address. 296 addr := network.NewAddress("0.1.2.9") 297 ipAddr, err := s.State.AddIPAddress(addr, "foobar") 298 c.Assert(err, jc.ErrorIsNil) 299 err = ipAddr.AllocateTo(machine.Id(), "foo", "") 300 c.Assert(err, jc.ErrorIsNil) 301 c.Assert(ipAddr.InstanceId(), gc.Equals, instance.Id("foo")) 302 303 // Ensure the alive address is not changed. 304 for a := common.ShortAttempt.Start(); a.Next(); { 305 s.assertIPAddressLife(c, ipAddr.Value(), state.Alive) 306 } 307 308 err = machine.EnsureDead() 309 c.Assert(err, jc.ErrorIsNil) 310 err = machine.Remove() 311 c.Assert(err, jc.ErrorIsNil) 312 313 s.assertIPAddressLife(c, ipAddr.Value(), state.Dead) 314 315 // Wait for ReleaseAddress attempt. 316 op := s.waitForReleaseOp(c) 317 c.Assert(op, jc.DeepEquals, s.makeReleaseOp(9)) 318 319 // The address should have been removed from state. 320 s.assertIPAddressRemoved(c, "0.1.2.9") 321 } 322 323 // workerEnabledSuite runs the test with the disabled address allocation. 324 type workerDisabledSuite struct { 325 workerSuite 326 } 327 328 var _ = gc.Suite(&workerDisabledSuite{}) 329 330 func (s *workerDisabledSuite) SetUpTest(c *gc.C) { 331 s.workerSuite.Enabled = false 332 333 s.workerSuite.SetUpTest(c) 334 } 335 336 func (s *workerDisabledSuite) TestWorkerIsFinishedWorker(c *gc.C) { 337 // In case of an environment not able to allocte/deallocate 338 // IP addresses the worker is a finished worker. 339 // See also TestWorkerIsStringsWorker. 340 c.Assert(s.Worker, gc.FitsTypeOf, worker.FinishedWorker{}) 341 } 342 343 func (s *workerDisabledSuite) TestWorkerIgnoresAddresses(c *gc.C) { 344 // The worker must not kill these addresses. 345 for a := common.ShortAttempt.Start(); a.Next(); { 346 s.assertIPAddressLife(c, "0.1.2.3", state.Alive) 347 s.assertIPAddressLife(c, "0.1.2.4", state.Dead) 348 s.assertIPAddressLife(c, "0.1.2.5", state.Alive) 349 s.assertIPAddressLife(c, "0.1.2.6", state.Dead) 350 } 351 }