github.com/geofffranks/garden-linux@v0.0.0-20160715111146-26c893169cfa/network/configure_test.go (about) 1 package network_test 2 3 import ( 4 "errors" 5 "net" 6 7 "code.cloudfoundry.org/garden-linux/network" 8 "code.cloudfoundry.org/garden-linux/network/devices/fakedevices" 9 "code.cloudfoundry.org/garden-linux/network/fakes" 10 "code.cloudfoundry.org/lager/lagertest" 11 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("Configure", func() { 17 Describe("ConfigureHost", func() { 18 var ( 19 vethCreator *fakedevices.FaveVethCreator 20 linkConfigurer *fakedevices.FakeLink 21 bridger *fakedevices.FakeBridge 22 23 configurer *network.NetworkConfigurer 24 existingBridge *net.Interface 25 config *network.HostConfig 26 ) 27 28 BeforeEach(func() { 29 vethCreator = &fakedevices.FaveVethCreator{} 30 linkConfigurer = &fakedevices.FakeLink{AddIPReturns: make(map[string]error)} 31 bridger = &fakedevices.FakeBridge{} 32 configurer = &network.NetworkConfigurer{Veth: vethCreator, Link: linkConfigurer, Bridge: bridger, Logger: lagertest.NewTestLogger("test")} 33 34 existingBridge = &net.Interface{Name: "bridge"} 35 36 config = &network.HostConfig{} 37 38 }) 39 40 JustBeforeEach(func() { 41 linkConfigurer.InterfaceByNameFunc = func(name string) (*net.Interface, bool, error) { 42 if name == "bridge" { 43 return existingBridge, true, nil 44 } 45 46 return nil, false, nil 47 } 48 }) 49 50 It("creates a virtual ethernet pair", func() { 51 config.HostIntf = "host" 52 config.BridgeName = "bridge" 53 config.ContainerIntf = "container" 54 Expect(configurer.ConfigureHost(config)).To(Succeed()) 55 56 Expect(vethCreator.CreateCalledWith.HostIfcName).To(Equal("host")) 57 Expect(vethCreator.CreateCalledWith.ContainerIfcName).To(Equal("container")) 58 }) 59 60 Context("when creating the pair fails", func() { 61 It("returns a wrapped error", func() { 62 config.HostIntf = "host" 63 config.BridgeName = "bridge" 64 config.ContainerIntf = "container" 65 vethCreator.CreateReturns.Err = errors.New("foo bar baz") 66 err := configurer.ConfigureHost(config) 67 Expect(err).To(HaveOccurred()) 68 Expect(err).To(MatchError(&network.VethPairCreationError{vethCreator.CreateReturns.Err, "host", "container"})) 69 }) 70 }) 71 72 Context("when creating the pair succeeds", func() { 73 BeforeEach(func() { 74 vethCreator.CreateReturns.Host = &net.Interface{Name: "the-host"} 75 vethCreator.CreateReturns.Container = &net.Interface{Name: "the-container"} 76 }) 77 78 It("should set mtu on the host interface", func() { 79 config.HostIntf = "host" 80 config.BridgeName = "bridge" 81 config.Mtu = 123 82 Expect(configurer.ConfigureHost(config)).To(Succeed()) 83 84 Expect(linkConfigurer.SetMTUCalledWith.Interface).To(Equal(vethCreator.CreateReturns.Host)) 85 Expect(linkConfigurer.SetMTUCalledWith.MTU).To(Equal(123)) 86 }) 87 88 Context("When setting the mtu fails", func() { 89 It("returns a wrapped error", func() { 90 config.HostIntf = "host" 91 config.BridgeName = "bridge" 92 config.ContainerIntf = "container" 93 config.Mtu = 14 94 linkConfigurer.SetMTUReturns = errors.New("o no") 95 err := configurer.ConfigureHost(config) 96 Expect(err).To(MatchError(&network.MTUError{linkConfigurer.SetMTUReturns, vethCreator.CreateReturns.Host, 14})) 97 }) 98 }) 99 100 It("should move the container interface in to the container's namespace", func() { 101 config.BridgeName = "bridge" 102 config.ContainerPid = 3 103 Expect(configurer.ConfigureHost(config)).To(Succeed()) 104 Expect(linkConfigurer.SetNsCalledWith.Pid).To(Equal(3)) 105 }) 106 107 Context("When moving the container interface into the namespace fails", func() { 108 It("returns a wrapped error", func() { 109 config.BridgeName = "bridge" 110 config.ContainerPid = 3 111 linkConfigurer.SetNsReturns = errors.New("o no") 112 err := configurer.ConfigureHost(config) 113 Expect(err).To(MatchError(&network.SetNsFailedError{linkConfigurer.SetNsReturns, vethCreator.CreateReturns.Container, 3})) 114 }) 115 }) 116 117 Describe("adding the host to the bridge", func() { 118 Context("when the bridge interface does not exist", func() { 119 It("returns a wrapped error", func() { 120 config.BridgeName = "bridge-that-doesnt-exist" 121 config.BridgeIP = net.ParseIP("1.2.3.1") 122 _, config.Subnet, _ = net.ParseCIDR("1.2.3.0/30") 123 err := configurer.ConfigureHost(config) 124 Expect(err).To(HaveOccurred()) 125 }) 126 }) 127 128 Context("when the bridge interface exists", func() { 129 It("adds the host interface to the existing bridge", func() { 130 config.BridgeName = "bridge" 131 Expect(configurer.ConfigureHost(config)).To(Succeed()) 132 Expect(bridger.AddCalledWith.Bridge).To(Equal(existingBridge)) 133 }) 134 135 It("brings the host interface up", func() { 136 config.BridgeName = "bridge" 137 Expect(configurer.ConfigureHost(config)).To(Succeed()) 138 Expect(linkConfigurer.SetUpCalledWith).To(ContainElement(vethCreator.CreateReturns.Host)) 139 }) 140 141 Context("when bringing the host interface up fails", func() { 142 It("returns a wrapped error", func() { 143 cause := errors.New("there's jam in this sandwich and it's not ok") 144 linkConfigurer.SetUpFunc = func(intf *net.Interface) error { 145 if vethCreator.CreateReturns.Host == intf { 146 return cause 147 } 148 149 return nil 150 } 151 152 config.BridgeName = "bridge" 153 err := configurer.ConfigureHost(config) 154 Expect(err).To(MatchError(&network.LinkUpError{cause, vethCreator.CreateReturns.Host, "host"})) 155 }) 156 }) 157 }) 158 }) 159 160 }) 161 }) 162 163 Describe("ConfigureContainer", func() { 164 var ( 165 linkConfigurer *fakedevices.FakeLink 166 hostnameSetter *fakes.FakeHostname 167 configurer *network.NetworkConfigurer 168 config *network.ContainerConfig 169 ) 170 171 BeforeEach(func() { 172 linkConfigurer = &fakedevices.FakeLink{AddIPReturns: make(map[string]error)} 173 hostnameSetter = &fakes.FakeHostname{} 174 configurer = &network.NetworkConfigurer{ 175 Link: linkConfigurer, 176 Hostname: hostnameSetter, 177 } 178 config = &network.ContainerConfig{} 179 }) 180 181 Context("when the loopback device does not exist", func() { 182 var eth *net.Interface 183 BeforeEach(func() { 184 linkConfigurer.InterfaceByNameFunc = func(name string) (*net.Interface, bool, error) { 185 if name != "lo" { 186 return eth, true, nil 187 } 188 189 return nil, false, nil 190 } 191 }) 192 193 It("returns a wrapped error", func() { 194 err := configurer.ConfigureContainer(config) 195 Expect(err).To(MatchError(&network.FindLinkError{nil, "loopback", "lo"})) 196 }) 197 198 It("does not attempt to configure other devices", func() { 199 Expect(configurer.ConfigureContainer(config)).ToNot(Succeed()) 200 Expect(linkConfigurer.SetUpCalledWith).ToNot(ContainElement(eth)) 201 }) 202 }) 203 204 Context("when the loopback exists", func() { 205 var lo *net.Interface 206 207 BeforeEach(func() { 208 lo = &net.Interface{Name: "lo"} 209 linkConfigurer.InterfaceByNameFunc = func(name string) (*net.Interface, bool, error) { 210 return &net.Interface{Name: name}, true, nil 211 } 212 }) 213 214 It("sets the hostname of the container", func() { 215 err := configurer.ConfigureContainer(&network.ContainerConfig{ 216 Hostname: "somehost", 217 }) 218 Expect(err).ToNot(HaveOccurred()) 219 Expect(hostnameSetter.SetHostnameCallCount()).To(Equal(1)) 220 Expect(hostnameSetter.SetHostnameArgsForCall(0)).To(Equal("somehost")) 221 }) 222 223 Context("when setting the hostname returns an error", func() { 224 BeforeEach(func() { 225 hostnameSetter.SetHostnameReturns(errors.New("oh no!")) 226 }) 227 228 It("returns the error", func() { 229 err := configurer.ConfigureContainer(&network.ContainerConfig{ 230 Hostname: "somehost", 231 }) 232 Expect(err).To(MatchError("oh no!")) 233 }) 234 }) 235 236 It("adds 127.0.0.1/8 as an address", func() { 237 ip, subnet, _ := net.ParseCIDR("127.0.0.1/8") 238 Expect(configurer.ConfigureContainer(config)).To(Succeed()) 239 Expect(linkConfigurer.AddIPCalledWith).To(ContainElement(fakedevices.InterfaceIPAndSubnet{lo, ip, subnet})) 240 }) 241 242 Context("when adding the IP address fails", func() { 243 It("returns a wrapped error", func() { 244 linkConfigurer.AddIPReturns["lo"] = errors.New("o no") 245 err := configurer.ConfigureContainer(config) 246 ip, subnet, _ := net.ParseCIDR("127.0.0.1/8") 247 Expect(err).To(MatchError(&network.ConfigureLinkError{errors.New("o no"), "loopback", lo, ip, subnet})) 248 }) 249 }) 250 251 It("brings it up", func() { 252 Expect(configurer.ConfigureContainer(config)).To(Succeed()) 253 Expect(linkConfigurer.SetUpCalledWith).To(ContainElement(lo)) 254 }) 255 256 Context("when bringing the link up fails", func() { 257 It("returns a wrapped error", func() { 258 linkConfigurer.SetUpFunc = func(intf *net.Interface) error { 259 return errors.New("o no") 260 } 261 262 err := configurer.ConfigureContainer(config) 263 Expect(err).To(MatchError(&network.LinkUpError{errors.New("o no"), lo, "loopback"})) 264 }) 265 }) 266 }) 267 268 Context("when the container interface does not exist", func() { 269 BeforeEach(func() { 270 linkConfigurer.InterfaceByNameFunc = func(name string) (*net.Interface, bool, error) { 271 if name == "lo" { 272 return &net.Interface{Name: name}, true, nil 273 } 274 275 return nil, false, nil 276 } 277 }) 278 279 It("returns a wrapped error", func() { 280 config.ContainerIntf = "foo" 281 err := configurer.ConfigureContainer(config) 282 Expect(err).To(MatchError(&network.FindLinkError{nil, "container", "foo"})) 283 }) 284 }) 285 286 Context("when the container interface exists", func() { 287 BeforeEach(func() { 288 linkConfigurer.InterfaceByNameFunc = func(name string) (*net.Interface, bool, error) { 289 return &net.Interface{Name: name}, true, nil 290 } 291 }) 292 293 It("Adds the requested IP", func() { 294 config.ContainerIntf = "foo" 295 config.ContainerIP, config.Subnet, _ = net.ParseCIDR("2.3.4.5/6") 296 297 Expect(configurer.ConfigureContainer(config)).To(Succeed()) 298 Expect(linkConfigurer.AddIPCalledWith).To(ContainElement(fakedevices.InterfaceIPAndSubnet{ 299 &net.Interface{Name: "foo"}, 300 config.ContainerIP, 301 config.Subnet, 302 })) 303 }) 304 305 Context("when adding the IP fails", func() { 306 It("returns a wrapped error", func() { 307 linkConfigurer.AddIPReturns["foo"] = errors.New("o no") 308 309 config.ContainerIntf = "foo" 310 config.ContainerIP, config.Subnet, _ = net.ParseCIDR("2.3.4.5/6") 311 err := configurer.ConfigureContainer(config) 312 Expect(err).To(MatchError(&network.ConfigureLinkError{ 313 errors.New("o no"), 314 "container", 315 &net.Interface{Name: "foo"}, 316 config.ContainerIP, 317 config.Subnet, 318 })) 319 }) 320 }) 321 322 It("Brings the link up", func() { 323 config.ContainerIntf = "foo" 324 Expect(configurer.ConfigureContainer(config)).To(Succeed()) 325 Expect(linkConfigurer.SetUpCalledWith).To(ContainElement(&net.Interface{Name: "foo"})) 326 }) 327 328 Context("when bringing the link up fails", func() { 329 It("returns a wrapped error", func() { 330 cause := errors.New("who ate my pie?") 331 linkConfigurer.SetUpFunc = func(iface *net.Interface) error { 332 if iface.Name == "foo" { 333 return cause 334 } 335 336 return nil 337 } 338 339 config.ContainerIntf = "foo" 340 err := configurer.ConfigureContainer(config) 341 Expect(err).To(MatchError(&network.LinkUpError{cause, &net.Interface{Name: "foo"}, "container"})) 342 }) 343 }) 344 345 It("sets the mtu", func() { 346 config.ContainerIntf = "foo" 347 config.Mtu = 1234 348 Expect(configurer.ConfigureContainer(config)).To(Succeed()) 349 Expect(linkConfigurer.SetMTUCalledWith.Interface).To(Equal(&net.Interface{Name: "foo"})) 350 Expect(linkConfigurer.SetMTUCalledWith.MTU).To(Equal(1234)) 351 }) 352 353 Context("when setting the mtu fails", func() { 354 It("returns a wrapped error", func() { 355 linkConfigurer.SetMTUReturns = errors.New("this is NOT the right potato") 356 357 config.ContainerIntf = "foo" 358 config.Mtu = 1234 359 err := configurer.ConfigureContainer(config) 360 Expect(err).To(MatchError(&network.MTUError{linkConfigurer.SetMTUReturns, &net.Interface{Name: "foo"}, 1234})) 361 }) 362 }) 363 364 It("adds a default gateway with the requested IP", func() { 365 config.ContainerIntf = "foo" 366 config.GatewayIP = net.ParseIP("2.3.4.5") 367 Expect(configurer.ConfigureContainer(config)).To(Succeed()) 368 Expect(linkConfigurer.AddDefaultGWCalledWith.Interface).To(Equal(&net.Interface{Name: "foo"})) 369 Expect(linkConfigurer.AddDefaultGWCalledWith.IP).To(Equal(net.ParseIP("2.3.4.5"))) 370 }) 371 372 Context("when adding a default gateway fails", func() { 373 It("returns a wrapped error", func() { 374 linkConfigurer.AddDefaultGWReturns = errors.New("this is NOT the right potato") 375 376 config.ContainerIntf = "foo" 377 config.GatewayIP = net.ParseIP("2.3.4.5") 378 err := configurer.ConfigureContainer(config) 379 Expect(err).To(MatchError(&network.ConfigureDefaultGWError{linkConfigurer.AddDefaultGWReturns, &net.Interface{Name: "foo"}, net.ParseIP("2.3.4.5")})) 380 }) 381 }) 382 }) 383 }) 384 })