github.com/geofffranks/garden-linux@v0.0.0-20160715111146-26c893169cfa/integration/networking/net_in_test.go (about)

     1  package networking_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os/exec"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/garden"
    10  	"code.cloudfoundry.org/garden-linux/integration/runner"
    11  	"github.com/onsi/gomega/gbytes"
    12  
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/gomega"
    15  )
    16  
    17  func restartGarden(argv ...string) *runner.RunningGarden {
    18  	Expect(client.Ping()).To(Succeed(), "tried to restart garden while it was not running")
    19  	Expect(client.Stop()).To(Succeed())
    20  	return startGarden(argv...)
    21  }
    22  
    23  var _ = Describe("Net In", func() {
    24  	var (
    25  		container     garden.Container
    26  		containerPort uint32
    27  		hostPort      uint32
    28  		externalIP    string
    29  	)
    30  
    31  	const containerHandle = "6e4ea858-6b31-4243-5dcc-093cfb83952d"
    32  
    33  	var listenInContainer = func(container garden.Container, containerPort uint32) error {
    34  		_, err := container.Run(garden.ProcessSpec{
    35  			User: "alice",
    36  			Path: "sh",
    37  			Args: []string{"-c", fmt.Sprintf("echo %d | nc -l %d", containerPort, containerPort)},
    38  		}, garden.ProcessIO{
    39  			Stdout: GinkgoWriter,
    40  			Stderr: GinkgoWriter,
    41  		})
    42  		Expect(err).ToNot(HaveOccurred())
    43  		time.Sleep(2 * time.Second)
    44  
    45  		return err
    46  	}
    47  
    48  	var sendRequest = func(ip string, port uint32) *gbytes.Buffer {
    49  		stdout := gbytes.NewBuffer()
    50  		cmd := exec.Command("nc", "-w1", ip, fmt.Sprintf("%d", port))
    51  		cmd.Stdout = stdout
    52  		cmd.Stderr = GinkgoWriter
    53  
    54  		err := cmd.Run()
    55  		Expect(err).ToNot(HaveOccurred())
    56  
    57  		return stdout
    58  	}
    59  
    60  	BeforeEach(func() {
    61  		client = startGarden()
    62  
    63  		var err error
    64  		container, err = client.Create(garden.ContainerSpec{
    65  			RootFSPath: "/opt/warden/nestable-rootfs",
    66  			Privileged: true,
    67  		})
    68  		Expect(err).ToNot(HaveOccurred())
    69  
    70  		info, err := container.Info()
    71  		Expect(err).ToNot(HaveOccurred())
    72  		externalIP = info.ExternalIP
    73  		hostPort = 8888
    74  		containerPort = 8080
    75  	})
    76  
    77  	AfterEach(func() {
    78  		err := client.Destroy(container.Handle())
    79  		Expect(err).ToNot(HaveOccurred())
    80  	})
    81  
    82  	It("maps the provided host port to the container port", func() {
    83  		_, _, err := container.NetIn(hostPort, containerPort)
    84  		Expect(err).ToNot(HaveOccurred())
    85  
    86  		Expect(listenInContainer(container, containerPort)).To(Succeed())
    87  
    88  		stdout := sendRequest(externalIP, hostPort)
    89  		Expect(stdout).To(gbytes.Say(fmt.Sprintf("%d", containerPort)))
    90  	})
    91  
    92  	Context("when multiple netin calls map the same host port to distinct container ports", func() {
    93  		var containerPort2 uint32
    94  
    95  		BeforeEach(func() {
    96  			containerPort2 = uint32(8081)
    97  
    98  			_, _, err := container.NetIn(hostPort, containerPort)
    99  			Expect(err).ToNot(HaveOccurred())
   100  
   101  			_, _, err = container.NetIn(hostPort, containerPort2)
   102  			Expect(err).ToNot(HaveOccurred())
   103  		})
   104  
   105  		// The following behaviour is a bug. See #98463890.
   106  		It("routes the request to the first container port", func() {
   107  			Expect(listenInContainer(container, containerPort)).To(Succeed())
   108  			Expect(listenInContainer(container, containerPort2)).To(Succeed())
   109  
   110  			stdout := sendRequest(externalIP, hostPort)
   111  			Expect(stdout).To(gbytes.Say(fmt.Sprintf("%d", containerPort)))
   112  		})
   113  	})
   114  
   115  	Context("when multiple netin calls map distinct host ports to the same container port", func() {
   116  		var hostPort2 uint32
   117  
   118  		BeforeEach(func() {
   119  			hostPort2 = uint32(8889)
   120  
   121  			_, _, err := container.NetIn(hostPort, containerPort)
   122  			Expect(err).ToNot(HaveOccurred())
   123  
   124  			_, _, err = container.NetIn(hostPort2, containerPort)
   125  			Expect(err).ToNot(HaveOccurred())
   126  		})
   127  
   128  		It("routes request from either host port to the container port", func() {
   129  			Expect(listenInContainer(container, containerPort)).To(Succeed())
   130  			stdout := sendRequest(externalIP, hostPort)
   131  			Expect(stdout).To(gbytes.Say(fmt.Sprintf("%d", containerPort)))
   132  
   133  			Expect(listenInContainer(container, containerPort)).To(Succeed())
   134  			stdout = sendRequest(externalIP, hostPort2)
   135  			Expect(stdout).To(gbytes.Say(fmt.Sprintf("%d", containerPort)))
   136  		})
   137  	})
   138  })
   139  
   140  var _ = Describe("Port Selection", func() {
   141  	var (
   142  		portPoolSize int
   143  		extraArgs    []string
   144  	)
   145  
   146  	BeforeEach(func() {
   147  		portPoolSize = 100
   148  		extraArgs = []string{}
   149  	})
   150  
   151  	JustBeforeEach(func() {
   152  		args := append(
   153  			[]string{"--portPoolSize", fmt.Sprintf("%d", portPoolSize)},
   154  			extraArgs...,
   155  		)
   156  		client = startGarden(args...)
   157  	})
   158  
   159  	It("should not reuse ports of destroyed containers", func() {
   160  		container, err := client.Create(garden.ContainerSpec{})
   161  		Expect(err).NotTo(HaveOccurred())
   162  
   163  		oldHostPort, _, err := container.NetIn(0, 0)
   164  		Expect(err).NotTo(HaveOccurred())
   165  
   166  		client.Destroy(container.Handle())
   167  
   168  		container, err = client.Create(garden.ContainerSpec{})
   169  		Expect(err).NotTo(HaveOccurred())
   170  
   171  		newHostPort, _, err := container.NetIn(0, 0)
   172  		Expect(err).NotTo(HaveOccurred())
   173  
   174  		Expect(newHostPort).To(BeNumerically("==", oldHostPort+1))
   175  	})
   176  
   177  	Context("when server is restarted", func() {
   178  		It("should not reuse ports", func() {
   179  			var (
   180  				containers   []string
   181  				lastHostPort uint32
   182  			)
   183  
   184  			for index := 0; index < 2; index++ {
   185  				container, err := client.Create(garden.ContainerSpec{})
   186  				Expect(err).NotTo(HaveOccurred())
   187  
   188  				hostPort, _, err := container.NetIn(0, 0)
   189  				Expect(err).NotTo(HaveOccurred())
   190  
   191  				containers = append(containers, container.Handle())
   192  				lastHostPort = hostPort
   193  			}
   194  
   195  			for index := 0; index < 2; index++ {
   196  				Expect(client.Destroy(containers[index])).To(Succeed())
   197  			}
   198  
   199  			client = restartGarden("--portPoolSize", fmt.Sprintf("%d", portPoolSize))
   200  
   201  			container, err := client.Create(garden.ContainerSpec{})
   202  			Expect(err).NotTo(HaveOccurred())
   203  
   204  			newHostPort, _, err := container.NetIn(0, 0)
   205  			Expect(err).NotTo(HaveOccurred())
   206  
   207  			Expect(newHostPort).To(BeNumerically("==", lastHostPort+1))
   208  		})
   209  
   210  		Context("and the port range is reduced", func() {
   211  			It("should start from the first port", func() {
   212  				var (
   213  					containers    []string
   214  					firstHostPort uint32
   215  				)
   216  
   217  				for index := 0; index < 2; index++ {
   218  					container, err := client.Create(garden.ContainerSpec{})
   219  					Expect(err).NotTo(HaveOccurred())
   220  
   221  					hostPort, _, err := container.NetIn(0, 0)
   222  					Expect(err).NotTo(HaveOccurred())
   223  
   224  					containers = append(containers, container.Handle())
   225  					if index == 0 {
   226  						firstHostPort = hostPort
   227  					}
   228  				}
   229  
   230  				for index := 0; index < 2; index++ {
   231  					Expect(client.Destroy(containers[index])).To(Succeed())
   232  				}
   233  
   234  				client = restartGarden("--portPoolSize", fmt.Sprintf("%d", 1))
   235  
   236  				container, err := client.Create(garden.ContainerSpec{})
   237  				Expect(err).NotTo(HaveOccurred())
   238  
   239  				newHostPort, _, err := container.NetIn(0, 0)
   240  				Expect(err).NotTo(HaveOccurred())
   241  
   242  				Expect(newHostPort).To(BeNumerically("==", firstHostPort))
   243  			})
   244  		})
   245  
   246  		Context("and the port range is exhausted with snapshotting disabled", func() {
   247  			BeforeEach(func() {
   248  				portPoolSize = 1
   249  				extraArgs = append(extraArgs, "--snapshots", "")
   250  			})
   251  
   252  			It("returns the first port in the range", func() {
   253  				container, err := client.Create(garden.ContainerSpec{})
   254  				Expect(err).NotTo(HaveOccurred())
   255  
   256  				firstHostPort, _, err := container.NetIn(0, 0)
   257  				Expect(err).NotTo(HaveOccurred())
   258  
   259  				client = restartGarden("--portPoolSize", fmt.Sprintf("%d", 2))
   260  
   261  				container, err = client.Create(garden.ContainerSpec{})
   262  				Expect(err).NotTo(HaveOccurred())
   263  
   264  				newHostPort, _, err := container.NetIn(0, 0)
   265  				Expect(err).NotTo(HaveOccurred())
   266  
   267  				Expect(newHostPort).To(BeNumerically("==", firstHostPort))
   268  			})
   269  		})
   270  
   271  		Context("and the port range is exhausted with snapshotting enabled", func() {
   272  			BeforeEach(func() {
   273  				portPoolSize = 1
   274  				snapshotsPath, err := ioutil.TempDir("", "snapshots")
   275  				Expect(err).NotTo(HaveOccurred())
   276  				extraArgs = append(extraArgs, "--snapshots", snapshotsPath)
   277  			})
   278  
   279  			It("stays exhausted after a restart", func() {
   280  				container, err := client.Create(garden.ContainerSpec{})
   281  				Expect(err).NotTo(HaveOccurred())
   282  
   283  				_, _, err = container.NetIn(0, 0)
   284  				Expect(err).NotTo(HaveOccurred())
   285  
   286  				args := append(extraArgs, "--portPoolSize", fmt.Sprintf("%d", portPoolSize))
   287  				client = restartGarden(args...)
   288  
   289  				containers, err := client.Containers(garden.Properties{})
   290  				Expect(err).NotTo(HaveOccurred())
   291  				Expect(containers).To(HaveLen(1))
   292  
   293  				container, err = client.Create(garden.ContainerSpec{})
   294  				Expect(err).NotTo(HaveOccurred())
   295  
   296  				_, _, err = container.NetIn(0, 0)
   297  				Expect(err).To(HaveOccurred())
   298  			})
   299  		})
   300  	})
   301  })