github.com/geofffranks/garden-linux@v0.0.0-20160715111146-26c893169cfa/network/bridgemgr/mgr_test.go (about) 1 package bridgemgr_test 2 3 import ( 4 "errors" 5 "net" 6 7 "code.cloudfoundry.org/garden-linux/network/bridgemgr" 8 . "github.com/onsi/ginkgo" 9 . "github.com/onsi/gomega" 10 ) 11 12 var _ = Describe("BridgeNamePool", func() { 13 var subnet1 *net.IPNet 14 var subnet2 *net.IPNet 15 var fakeBuilder *builder 16 var fakeLister *lister 17 18 var mgr bridgemgr.BridgeManager 19 20 BeforeEach(func() { 21 _, subnet1, _ = net.ParseCIDR("1.2.3.4/30") 22 _, subnet2, _ = net.ParseCIDR("1.2.3.4/29") 23 24 fakeBuilder = &builder{} 25 fakeLister = &lister{} 26 mgr = bridgemgr.New("pr", fakeBuilder, fakeLister) 27 }) 28 29 Describe("reserving", func() { 30 Context("when no bridge names have been assigned", func() { 31 It("assigns a prefixed name", func() { 32 name, err := mgr.Reserve(subnet1, "container1") 33 34 Expect(err).ToNot(HaveOccurred()) 35 Expect(name).To(MatchRegexp("^pr")) 36 }) 37 38 It("creates the bridge", func() { 39 name, err := mgr.Reserve(subnet1, "container-name") 40 Expect(err).ToNot(HaveOccurred()) 41 Expect(fakeBuilder.CreatedBridges).To(ContainElement(createParams{ 42 name: name, 43 subnet: subnet1, 44 ip: net.ParseIP("1.2.3.5").To4(), 45 })) 46 }) 47 48 Context("when creating the bridge fails", func() { 49 BeforeEach(func() { 50 fakeBuilder.CreateReturns = errors.New("Bananas") 51 }) 52 53 It("returns the error", func() { 54 _, err := mgr.Reserve(subnet1, "container1") 55 Expect(err).To(HaveOccurred()) 56 }) 57 58 Context("when the same subnet is acquired later", func() { 59 It("retries the creation", func() { 60 mgr.Reserve(subnet1, "container1") 61 mgr.Reserve(subnet1, "container1") 62 63 Expect(fakeBuilder.CreatedBridges).To(HaveLen(2)) 64 }) 65 }) 66 }) 67 }) 68 69 Context("when a subnet has already been assigned a bridge name", func() { 70 It("reuses the same name", func() { 71 name1, err := mgr.Reserve(subnet1, "container1") 72 Expect(err).ToNot(HaveOccurred()) 73 74 name2, err := mgr.Reserve(subnet1, "container2") 75 Expect(err).ToNot(HaveOccurred()) 76 77 Expect(name2).To(Equal(name1)) 78 Expect(fakeBuilder.CreatedBridges).To(HaveLen(1)) 79 }) 80 }) 81 82 Context("when a bridge is acquired for a different subnet", func() { 83 It("assigns a new bridge name", func() { 84 name1, err := mgr.Reserve(subnet1, "container1") 85 Expect(err).ToNot(HaveOccurred()) 86 87 name2, err := mgr.Reserve(subnet2, "container2") 88 Expect(err).ToNot(HaveOccurred()) 89 90 Expect(name2).ToNot(Equal(name1)) 91 Expect(fakeBuilder.CreatedBridges).To(HaveLen(2)) 92 }) 93 }) 94 }) 95 96 Describe("releasing", func() { 97 Context("when a container releases its bridge", func() { 98 var name string 99 100 Context("and there are still containers in the subnet", func() { 101 BeforeEach(func() { 102 _, err := mgr.Reserve(subnet1, "container1") 103 Expect(err).ToNot(HaveOccurred()) 104 name, err = mgr.Reserve(subnet1, "container2") 105 Expect(err).ToNot(HaveOccurred()) 106 107 Expect(mgr.Release(name, "container1")).To(Succeed()) 108 }) 109 110 It("reuses the existing bridge name on the next Reserve", func() { 111 newName, err := mgr.Reserve(subnet1, "container3") 112 Expect(err).ToNot(HaveOccurred()) 113 Expect(newName).To(Equal(name)) 114 }) 115 116 It("does not destroy the bridge", func() { 117 Expect(fakeBuilder.Destroyed).ToNot(ContainElement(name)) 118 }) 119 }) 120 121 Context("and it is the final container using the bridge", func() { 122 var name string 123 BeforeEach(func() { 124 var err error 125 name, err = mgr.Reserve(subnet1, "container1") 126 Expect(err).ToNot(HaveOccurred()) 127 128 Expect(mgr.Release(name, "container1")).To(Succeed()) 129 }) 130 131 It("assigns a new bridge name on the next Reserve", func() { 132 newName, err := mgr.Reserve(subnet1, "container2") 133 Expect(err).ToNot(HaveOccurred()) 134 Expect(newName).ToNot(Equal(name)) 135 }) 136 137 It("destroys the bridge with the passed destroyer", func() { 138 Expect(mgr.Release("some-bridge", "container1")).To(Succeed()) 139 Expect(fakeBuilder.Destroyed).To(ContainElement("some-bridge")) 140 }) 141 142 Context("when the destroyer returns an error", func() { 143 It("returns an error", func() { 144 fakeBuilder.DestroyReturns = errors.New("bboom ") 145 Expect(mgr.Release("some-bridge", "container1")).ToNot(Succeed()) 146 }) 147 }) 148 }) 149 150 Context("and it has not previously been acquired (e.g. when releasing an unknown bridge during recovery)", func() { 151 It("destroys the bridge with the passed destroyer", func() { 152 Expect(mgr.Release("some-bridge", "container1")).To(Succeed()) 153 Expect(fakeBuilder.Destroyed).To(ContainElement("some-bridge")) 154 }) 155 }) 156 }) 157 }) 158 159 Describe("rereserving", func() { 160 It("returns an error if the bridge name is empty", func() { 161 Expect(mgr.Rereserve("", subnet1, "some-id")).To(MatchError("bridgemgr: re-reserving bridge: bridge name must not be empty")) 162 }) 163 164 Context("when a bridge name is rereserved", func() { 165 It("returns an error if the reacquired subnet is already assigned to another bridge name", func() { 166 name, err := mgr.Reserve(subnet1, "") 167 Expect(err).ToNot(HaveOccurred()) 168 169 Expect(mgr.Rereserve(name, subnet2, "")).ToNot(Succeed()) 170 }) 171 172 Context("when the bridge could be reacquired", func() { 173 BeforeEach(func() { 174 Expect(mgr.Rereserve("my-bridge", subnet1, "my-container")).To(Succeed()) 175 }) 176 177 Context("when a bridge name is acquired for the same subnet", func() { 178 It("reuses the bridge name", func() { 179 name, err := mgr.Reserve(subnet1, "another-container") 180 Expect(err).ToNot(HaveOccurred()) 181 182 Expect(name).To(Equal("my-bridge")) 183 }) 184 185 Context("when it is released", func() { 186 It("does not destroy the bridge, since the reacquired container is still using it", func() { 187 Expect(mgr.Release("my-bridge", "another-container")).To(Succeed()) 188 Expect(fakeBuilder.Destroyed).ToNot(ContainElement("my-bridge")) 189 }) 190 }) 191 }) 192 193 Context("when it is released", func() { 194 It("destroys the bridge with the passed destroyer", func() { 195 Expect(mgr.Release("my-bridge", "my-container")).To(Succeed()) 196 Expect(fakeBuilder.Destroyed).To(ContainElement("my-bridge")) 197 }) 198 }) 199 }) 200 }) 201 }) 202 203 Describe("pruning", func() { 204 Context("when listing bridges fails", func() { 205 BeforeEach(func() { 206 fakeLister.ListReturns = errors.New("o no") 207 }) 208 209 It("returns a wrapped error", func() { 210 Expect(mgr.Prune()).To(MatchError("bridgemgr: pruning bridges: o no")) 211 }) 212 }) 213 214 Context("when there are no bridges", func() { 215 It("does not destroy any bridges", func() { 216 Expect(mgr.Prune()).To(Succeed()) 217 Expect(fakeBuilder.Destroyed).To(HaveLen(0)) 218 }) 219 }) 220 221 Context("when there are multiple bridges", func() { 222 BeforeEach(func() { 223 fakeLister.Bridges = []string{"doesnotmatch", "pr-123", "pr-234"} 224 mgr.Rereserve("pr-234", subnet1, "somecontainerid") 225 Expect(mgr.Prune()).To(Succeed()) 226 }) 227 228 It("destroys bridges with the prefix", func() { 229 Expect(fakeBuilder.Destroyed).To(ContainElement("pr-123")) 230 }) 231 232 It("does not destroy bridges without the prefix", func() { 233 Expect(fakeBuilder.Destroyed).ToNot(ContainElement("doesnotmatch")) 234 }) 235 236 It("does not destroy bridges which are reserved", func() { 237 Expect(fakeBuilder.Destroyed).ToNot(ContainElement("pr-234")) 238 }) 239 }) 240 }) 241 }) 242 243 type builder struct { 244 CreatedBridges []createParams 245 CreateReturns error 246 Destroyed []string 247 DestroyReturns error 248 } 249 250 type createParams struct { 251 name string 252 subnet *net.IPNet 253 ip net.IP 254 } 255 256 func (c *builder) Create(name string, ip net.IP, subnet *net.IPNet) (*net.Interface, error) { 257 c.CreatedBridges = append(c.CreatedBridges, createParams{ 258 name: name, 259 subnet: subnet, 260 ip: ip, 261 }) 262 263 return nil, c.CreateReturns 264 } 265 266 func (d *builder) Destroy(name string) error { 267 d.Destroyed = append(d.Destroyed, name) 268 return d.DestroyReturns 269 } 270 271 type lister struct { 272 Bridges []string 273 ListReturns error 274 } 275 276 func (l *lister) List() ([]string, error) { 277 return l.Bridges, l.ListReturns 278 }