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  })