github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/network/subnets/subnets_test.go (about) 1 package subnets_test 2 3 import ( 4 "net" 5 "runtime" 6 7 "github.com/cloudfoundry-incubator/garden-linux/linux_backend" 8 "github.com/cloudfoundry-incubator/garden-linux/network/subnets" 9 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("Subnet Pool", func() { 15 var subnetpool subnets.Subnets 16 var defaultSubnetPool *net.IPNet 17 18 JustBeforeEach(func() { 19 var err error 20 subnetpool, err = subnets.NewSubnets(defaultSubnetPool) 21 Expect(err).ToNot(HaveOccurred()) 22 }) 23 24 Describe("Capacity", func() { 25 Context("when the dynamic allocation net is empty", func() { 26 BeforeEach(func() { 27 defaultSubnetPool = subnetPool("10.2.3.0/32") 28 }) 29 30 It("returns zero", func() { 31 Expect(subnetpool.Capacity()).To(Equal(0)) 32 }) 33 }) 34 35 Context("when the dynamic allocation net is non-empty", func() { 36 BeforeEach(func() { 37 defaultSubnetPool = subnetPool("10.2.3.0/27") 38 }) 39 40 It("returns the correct number of subnets initially and repeatedly", func() { 41 Expect(subnetpool.Capacity()).To(Equal(8)) 42 Expect(subnetpool.Capacity()).To(Equal(8)) 43 }) 44 45 It("returns the correct capacity after allocating subnets", func() { 46 cap := subnetpool.Capacity() 47 48 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 49 Expect(err).ToNot(HaveOccurred()) 50 51 Expect(subnetpool.Capacity()).To(Equal(cap)) 52 53 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 54 Expect(err).ToNot(HaveOccurred()) 55 56 Expect(subnetpool.Capacity()).To(Equal(cap)) 57 }) 58 }) 59 }) 60 61 Describe("Allocating and Releasing", func() { 62 Describe("Static Subnet Allocation", func() { 63 Context("when the requested subnet is within the dynamic allocation range", func() { 64 BeforeEach(func() { 65 defaultSubnetPool = subnetPool("10.2.3.0/29") 66 }) 67 68 It("returns an appropriate error", func() { 69 _, static := networkParms("10.2.3.4/30") 70 71 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 72 Expect(err).To(MatchError("the requested subnet (10.2.3.4/30) overlaps the dynamic allocation range (10.2.3.0/29)")) 73 }) 74 }) 75 76 Context("when the requested subnet subsumes the dynamic allocation range", func() { 77 BeforeEach(func() { 78 defaultSubnetPool = subnetPool("10.2.3.4/30") 79 }) 80 81 It("returns an appropriate error", func() { 82 _, static := networkParms("10.2.3.0/24") 83 84 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 85 Expect(err).To(HaveOccurred()) 86 Expect(err).To(MatchError("the requested subnet (10.2.3.0/24) overlaps the dynamic allocation range (10.2.3.4/30)")) 87 }) 88 }) 89 90 Context("when the requested subnet is not within the dynamic allocation range", func() { 91 BeforeEach(func() { 92 defaultSubnetPool = subnetPool("10.2.3.0/29") 93 }) 94 95 Context("allocating a static subnet", func() { 96 Context("and a static IP", func() { 97 It("returns an error if the IP is not inside the subnet", func() { 98 _, static := networkParms("11.0.0.0/8") 99 100 ip := net.ParseIP("9.0.0.1") 101 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 102 Expect(err).To(Equal(subnets.ErrInvalidIP)) 103 }) 104 105 It("returns the same subnet and IP if the IP is inside the subnet", func() { 106 _, static := networkParms("11.0.0.0/8") 107 108 ip := net.ParseIP("11.0.0.1") 109 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 110 Expect(err).ToNot(HaveOccurred()) 111 112 Expect(network.Subnet).To(Equal(static)) 113 Expect(network.IP).To(Equal(ip)) 114 }) 115 116 It("does not allow the same IP to be requested twice", func() { 117 _, static := networkParms("11.0.0.0/8") 118 119 ip := net.ParseIP("11.0.0.1") 120 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 121 Expect(err).ToNot(HaveOccurred()) 122 123 _, static = networkParms("11.0.0.0/8") // make sure we get a new pointer 124 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 125 Expect(err).To(Equal(subnets.ErrIPAlreadyAcquired)) 126 }) 127 128 It("allows two IPs to be serially requested in the same subnet", func() { 129 _, static := networkParms("11.0.0.0/8") 130 131 ip := net.ParseIP("11.0.0.1") 132 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 133 Expect(err).ToNot(HaveOccurred()) 134 Expect(network.Subnet).To(Equal(static)) 135 Expect(network.IP).To(Equal(ip)) 136 137 ip2 := net.ParseIP("11.0.0.2") 138 139 _, static = networkParms("11.0.0.0/8") // make sure we get a new pointer 140 network2, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip2}) 141 Expect(err).ToNot(HaveOccurred()) 142 Expect(network2.Subnet).To(Equal(static)) 143 Expect(network2.IP).To(Equal(ip2)) 144 }) 145 146 It("when an IP is allocated from a subnet but released in between, it should be treated as new both times", func() { 147 _, static := networkParms("11.0.0.0/8") 148 149 ip := net.ParseIP("11.0.0.1") 150 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 151 Expect(err).ToNot(HaveOccurred()) 152 Expect(network.Subnet).To(Equal(static)) 153 Expect(network.IP).To(Equal(ip)) 154 155 err = subnetpool.Release(network) 156 Expect(err).ToNot(HaveOccurred()) 157 158 _, static = networkParms("11.0.0.0/8") // make sure we get a new pointer 159 network, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 160 Expect(err).ToNot(HaveOccurred()) 161 Expect(network.Subnet).To(Equal(static)) 162 Expect(network.IP).To(Equal(ip)) 163 }) 164 165 It("prevents dynamic allocation of the same IP", func() { 166 _, static := networkParms("11.0.0.0/8") 167 168 ip := net.ParseIP("11.0.0.2") 169 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 170 Expect(err).ToNot(HaveOccurred()) 171 172 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 173 Expect(err).ToNot(HaveOccurred()) 174 Expect(network.IP.String()).To(Equal("11.0.0.1")) 175 176 network, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 177 Expect(err).ToNot(HaveOccurred()) 178 Expect(network.IP.String()).To(Equal("11.0.0.3")) 179 }) 180 181 Describe("errors", func() { 182 It("fails if a static subnet is requested specifying an IP address which clashes with the gateway IP address", func() { 183 _, static := networkParms("11.0.0.0/8") 184 gateway := net.ParseIP("11.255.255.254") 185 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{gateway}) 186 Expect(err).To(MatchError(subnets.ErrIPEqualsGateway)) 187 }) 188 189 It("fails if a static subnet is requested specifying an IP address which clashes with the broadcast IP address", func() { 190 _, static := networkParms("11.0.0.0/8") 191 max := net.ParseIP("11.255.255.255") 192 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{max}) 193 Expect(err).To(MatchError(subnets.ErrIPEqualsBroadcast)) 194 }) 195 }) 196 }) 197 198 Context("and a dynamic IP", func() { 199 It("does not return an error", func() { 200 _, static := networkParms("11.0.0.0/8") 201 202 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 203 Expect(err).ToNot(HaveOccurred()) 204 }) 205 206 It("returns the first available IP", func() { 207 _, static := networkParms("11.0.0.0/8") 208 209 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 210 Expect(err).ToNot(HaveOccurred()) 211 212 Expect(network.IP.String()).To(Equal("11.0.0.1")) 213 }) 214 215 It("returns distinct IPs", func() { 216 _, static := networkParms("11.0.0.0/22") 217 218 seen := make(map[string]bool) 219 var err error 220 for err == nil { 221 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 222 223 if err != nil { 224 Expect(err).To(Equal(subnets.ErrInsufficientIPs)) 225 break 226 } 227 228 Expect(seen).ToNot(HaveKey(network.IP.String())) 229 seen[network.IP.String()] = true 230 } 231 }) 232 233 It("returns all IPs except gateway, minimum and broadcast", func() { 234 _, static := networkParms("11.0.0.0/23") 235 236 var err error 237 count := 0 238 for err == nil { 239 if _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector); err != nil { 240 Expect(err).To(Equal(subnets.ErrInsufficientIPs)) 241 } 242 243 count++ 244 } 245 246 Expect(count).To(Equal(510)) 247 }) 248 249 It("causes static alocation to fail if it tries to allocate the same IP afterwards", func() { 250 _, static := networkParms("11.0.0.0/8") 251 252 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 253 Expect(err).ToNot(HaveOccurred()) 254 255 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{network.IP}) 256 Expect(err).To(Equal(subnets.ErrIPAlreadyAcquired)) 257 }) 258 }) 259 }) 260 261 Context("after all IPs are allocated from a subnet, a subsequent request for the same subnet", func() { 262 var ( 263 static *net.IPNet 264 ips [5]net.IP 265 ) 266 267 JustBeforeEach(func() { 268 var err error 269 _, static, err = net.ParseCIDR("10.9.3.0/29") 270 Expect(err).ToNot(HaveOccurred()) 271 272 for i := 0; i < 5; i++ { 273 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 274 Expect(err).ToNot(HaveOccurred()) 275 276 ips[i] = network.IP 277 } 278 }) 279 280 It("returns an appropriate error", func() { 281 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 282 Expect(err).To(HaveOccurred()) 283 Expect(err).To(Equal(subnets.ErrInsufficientIPs)) 284 }) 285 286 Context("but after it is released", func() { 287 It("dynamically allocates the released IP again", func() { 288 err := subnetpool.Release(&linux_backend.Network{static, ips[3]}) 289 Expect(err).ToNot(HaveOccurred()) 290 291 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 292 Expect(err).ToNot(HaveOccurred()) 293 Expect(network.IP).To(Equal(ips[3])) 294 }) 295 296 It("allows static allocation again", func() { 297 err := subnetpool.Release(&linux_backend.Network{static, ips[3]}) 298 Expect(err).ToNot(HaveOccurred()) 299 300 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ips[3]}) 301 Expect(err).ToNot(HaveOccurred()) 302 }) 303 }) 304 }) 305 306 Context("after a subnet has been allocated, a subsequent request for an overlapping subnet which begins on the same ip", func() { 307 var ( 308 firstSubnetPool *net.IPNet 309 firstContainerIP net.IP 310 secondSubnetPool *net.IPNet 311 ) 312 313 JustBeforeEach(func() { 314 var err error 315 firstContainerIP, firstSubnetPool = networkParms("10.9.3.0/30") 316 Expect(err).ToNot(HaveOccurred()) 317 318 _, secondSubnetPool = networkParms("10.9.3.0/29") 319 Expect(err).ToNot(HaveOccurred()) 320 321 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{firstSubnetPool}, subnets.DynamicIPSelector) 322 Expect(err).ToNot(HaveOccurred()) 323 }) 324 325 It("returns an appropriate error", func() { 326 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{secondSubnetPool}, subnets.DynamicIPSelector) 327 Expect(err).To(MatchError("the requested subnet (10.9.3.0/29) overlaps an existing subnet (10.9.3.0/30)")) 328 }) 329 }) 330 331 Context("after a subnet has been allocated, a subsequent request for an overlapping subnet", func() { 332 var ( 333 firstSubnetPool *net.IPNet 334 firstContainerIP net.IP 335 secondSubnetPool *net.IPNet 336 ) 337 338 JustBeforeEach(func() { 339 var err error 340 firstContainerIP, firstSubnetPool = networkParms("10.9.3.4/30") 341 Expect(err).ToNot(HaveOccurred()) 342 343 _, secondSubnetPool = networkParms("10.9.3.0/29") 344 Expect(err).ToNot(HaveOccurred()) 345 346 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{firstSubnetPool}, subnets.DynamicIPSelector) 347 Expect(err).ToNot(HaveOccurred()) 348 }) 349 350 It("returns an appropriate error", func() { 351 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{secondSubnetPool}, subnets.DynamicIPSelector) 352 Expect(err).To(MatchError("the requested subnet (10.9.3.0/29) overlaps an existing subnet (10.9.3.4/30)")) 353 }) 354 355 Context("but after it is released", func() { 356 It("allows allocation again", func() { 357 err := subnetpool.Release(&linux_backend.Network{firstSubnetPool, firstContainerIP}) 358 Expect(err).ToNot(HaveOccurred()) 359 360 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{secondSubnetPool}, subnets.DynamicIPSelector) 361 Expect(err).ToNot(HaveOccurred()) 362 }) 363 }) 364 }) 365 366 Context("requesting a specific IP address in a static subnet", func() { 367 It("does not return an error", func() { 368 _, static := networkParms("10.9.3.6/29") 369 370 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 371 Expect(err).ToNot(HaveOccurred()) 372 }) 373 }) 374 375 }) 376 }) 377 378 Describe("Dynamic /30 Subnet Allocation", func() { 379 Context("when the pool does not have sufficient IPs to allocate a subnet", func() { 380 BeforeEach(func() { 381 defaultSubnetPool = subnetPool("10.2.3.0/31") 382 }) 383 384 It("the first request returns an error", func() { 385 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 386 Expect(err).To(HaveOccurred()) 387 }) 388 }) 389 390 Context("when the pool has sufficient IPs to allocate a single subnet", func() { 391 BeforeEach(func() { 392 defaultSubnetPool = subnetPool("10.2.3.0/30") 393 }) 394 395 Context("the first request", func() { 396 It("succeeds, and returns a /30 network within the subnet", func() { 397 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 398 Expect(err).ToNot(HaveOccurred()) 399 400 Expect(network.Subnet).ToNot(BeNil()) 401 Expect(network.Subnet.String()).To(Equal("10.2.3.0/30")) 402 }) 403 }) 404 405 Context("subsequent requests", func() { 406 It("fails, and return an err", func() { 407 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 408 Expect(err).ToNot(HaveOccurred()) 409 410 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 411 Expect(err).To(HaveOccurred()) 412 }) 413 }) 414 415 Context("when an allocated network is released", func() { 416 It("a subsequent allocation succeeds, and returns the first network again", func() { 417 // first 418 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 419 Expect(err).ToNot(HaveOccurred()) 420 421 // second - will fail (sanity check) 422 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 423 Expect(err).To(HaveOccurred()) 424 425 // release 426 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}) 427 Expect(err).ToNot(HaveOccurred()) 428 429 // third - should work now because of release 430 network2, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 431 Expect(err).ToNot(HaveOccurred()) 432 433 Expect(network2.Subnet).ToNot(BeNil()) 434 Expect(network2.Subnet.String()).To(Equal(network.Subnet.String())) 435 }) 436 437 Context("and it is not the last IP in the subnet", func() { 438 It("returns gone=false", func() { 439 _, static := networkParms("10.3.3.0/29") 440 441 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 442 Expect(err).ToNot(HaveOccurred()) 443 444 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector) 445 Expect(err).ToNot(HaveOccurred()) 446 447 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}) 448 Expect(err).ToNot(HaveOccurred()) 449 }) 450 }) 451 }) 452 453 Context("when a network is released twice", func() { 454 It("returns an error", func() { 455 // first 456 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 457 Expect(err).ToNot(HaveOccurred()) 458 459 // release 460 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}) 461 Expect(err).ToNot(HaveOccurred()) 462 463 // release again 464 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}) 465 Expect(err).To(HaveOccurred()) 466 Expect(err).To(Equal(subnets.ErrReleasedUnallocatedSubnet)) 467 }) 468 }) 469 }) 470 471 Context("when the pool has sufficient IPs to allocate two /30 subnets", func() { 472 BeforeEach(func() { 473 defaultSubnetPool = subnetPool("10.2.3.0/29") 474 }) 475 476 Context("the second request", func() { 477 It("succeeds", func() { 478 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 479 Expect(err).ToNot(HaveOccurred()) 480 481 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 482 Expect(err).ToNot(HaveOccurred()) 483 }) 484 485 It("returns the second /30 network within the subnet", func() { 486 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 487 Expect(err).ToNot(HaveOccurred()) 488 489 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 490 Expect(err).ToNot(HaveOccurred()) 491 492 Expect(network.Subnet).ToNot(BeNil()) 493 Expect(network.Subnet.String()).To(Equal("10.2.3.4/30")) 494 }) 495 }) 496 497 It("allocates distinct networks concurrently", func() { 498 prev := runtime.GOMAXPROCS(2) 499 defer runtime.GOMAXPROCS(prev) 500 501 Consistently(func() bool { 502 _, network, err := net.ParseCIDR("10.0.0.0/29") 503 Expect(err).ToNot(HaveOccurred()) 504 505 subnetpool, err := subnets.NewSubnets(network) 506 Expect(err).ToNot(HaveOccurred()) 507 508 out := make(chan *net.IPNet) 509 go func(out chan *net.IPNet) { 510 defer GinkgoRecover() 511 n1, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 512 Expect(err).ToNot(HaveOccurred()) 513 out <- n1.Subnet 514 }(out) 515 516 go func(out chan *net.IPNet) { 517 defer GinkgoRecover() 518 n1, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 519 Expect(err).ToNot(HaveOccurred()) 520 out <- n1.Subnet 521 }(out) 522 523 a := <-out 524 b := <-out 525 return a.IP.Equal(b.IP) 526 }, "100ms", "2ms").ShouldNot(BeTrue()) 527 }) 528 529 It("correctly handles concurrent release of the same network", func() { 530 prev := runtime.GOMAXPROCS(2) 531 defer runtime.GOMAXPROCS(prev) 532 533 Consistently(func() bool { 534 _, network, err := net.ParseCIDR("10.0.0.0/29") 535 Expect(err).ToNot(HaveOccurred()) 536 537 subnetpool, err := subnets.NewSubnets(network) 538 Expect(err).ToNot(HaveOccurred()) 539 540 acquired, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector) 541 Expect(err).ToNot(HaveOccurred()) 542 543 out := make(chan error) 544 go func(out chan error) { 545 defer GinkgoRecover() 546 err := subnetpool.Release(&linux_backend.Network{acquired.Subnet, acquired.IP}) 547 out <- err 548 }(out) 549 550 go func(out chan error) { 551 defer GinkgoRecover() 552 err := subnetpool.Release(&linux_backend.Network{acquired.Subnet, acquired.IP}) 553 out <- err 554 }(out) 555 556 a := <-out 557 b := <-out 558 return (a == nil) != (b == nil) 559 }, "200ms", "2ms").Should(BeTrue()) 560 }) 561 562 It("correctly handles concurrent allocation of the same network", func() { 563 prev := runtime.GOMAXPROCS(2) 564 defer runtime.GOMAXPROCS(prev) 565 566 Consistently(func() bool { 567 network := subnetPool("10.0.0.0/29") 568 569 subnetpool, err := subnets.NewSubnets(network) 570 Expect(err).ToNot(HaveOccurred()) 571 572 ip, n1 := networkParms("10.1.0.0/30") 573 574 out := make(chan error) 575 go func(out chan error) { 576 defer GinkgoRecover() 577 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{n1}, subnets.StaticIPSelector{ip}) 578 out <- err 579 }(out) 580 581 go func(out chan error) { 582 defer GinkgoRecover() 583 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{n1}, subnets.StaticIPSelector{ip}) 584 out <- err 585 }(out) 586 587 a := <-out 588 b := <-out 589 return (a == nil) != (b == nil) 590 }, "200ms", "2ms").Should(BeTrue()) 591 }) 592 }) 593 }) 594 595 Describe("Removeing", func() { 596 BeforeEach(func() { 597 defaultSubnetPool = subnetPool("10.2.3.0/29") 598 }) 599 600 Context("an allocation outside the dynamic allocation net", func() { 601 It("recovers the first time", func() { 602 _, static := networkParms("10.9.3.4/30") 603 604 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.9.3.5")}) 605 Expect(err).ToNot(HaveOccurred()) 606 }) 607 608 It("does not allow recovering twice", func() { 609 _, static := networkParms("10.9.3.4/30") 610 611 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.9.3.5")}) 612 Expect(err).ToNot(HaveOccurred()) 613 614 err = subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.9.3.5")}) 615 Expect(err).To(HaveOccurred()) 616 }) 617 618 It("does not allow allocating after recovery", func() { 619 _, static := networkParms("10.9.3.4/30") 620 621 ip := net.ParseIP("10.9.3.5") 622 err := subnetpool.Remove(&linux_backend.Network{static, ip}) 623 Expect(err).ToNot(HaveOccurred()) 624 625 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}) 626 Expect(err).To(HaveOccurred()) 627 }) 628 629 It("does not allow recovering without an explicit IP", func() { 630 _, static := networkParms("10.9.3.4/30") 631 632 err := subnetpool.Remove(&linux_backend.Network{static, nil}) 633 Expect(err).To(HaveOccurred()) 634 }) 635 }) 636 637 Context("an allocation inside the dynamic allocation net", func() { 638 It("recovers the first time", func() { 639 _, static := networkParms("10.2.3.4/30") 640 641 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.5")}) 642 Expect(err).ToNot(HaveOccurred()) 643 }) 644 645 It("does not allow recovering twice", func() { 646 _, static := networkParms("10.2.3.4/30") 647 648 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.5")}) 649 Expect(err).ToNot(HaveOccurred()) 650 651 err = subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.5")}) 652 Expect(err).To(HaveOccurred()) 653 }) 654 655 It("does not dynamically allocate a recovered network", func() { 656 _, static := networkParms("10.2.3.4/30") 657 658 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.1")}) 659 Expect(err).ToNot(HaveOccurred()) 660 661 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.StaticIPSelector{net.ParseIP("10.2.3.1")}) 662 Expect(err).ToNot(HaveOccurred()) 663 Expect(network.Subnet.String()).To(Equal("10.2.3.0/30")) 664 665 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.StaticIPSelector{net.ParseIP("10.2.3.1")}) 666 Expect(err).To(Equal(subnets.ErrInsufficientSubnets)) 667 }) 668 }) 669 670 }) 671 672 }) 673 }) 674 675 func subnetPool(networkString string) *net.IPNet { 676 _, subnetPool := networkParms(networkString) 677 return subnetPool 678 } 679 680 func networkParms(networkString string) (net.IP, *net.IPNet) { 681 containerIP, subnet, err := net.ParseCIDR(networkString) 682 Expect(err).ToNot(HaveOccurred()) 683 if containerIP.Equal(subnet.IP) { 684 containerIP = nextIP(containerIP) 685 } 686 return containerIP, subnet 687 } 688 689 func nextIP(ip net.IP) net.IP { 690 next := net.ParseIP(ip.String()) 691 inc(next) 692 return next 693 } 694 695 func inc(ip net.IP) { 696 for j := len(ip) - 1; j >= 0; j-- { 697 ip[j]++ 698 if ip[j] > 0 { 699 break 700 } 701 } 702 }