github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/integration/networking/ip_test.go (about)

     1  package networking_test
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/http"
     7  	"os/exec"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/cloudfoundry-incubator/garden"
    12  	"github.com/cloudfoundry/gunk/localip"
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/gomega"
    15  	"github.com/onsi/gomega/gbytes"
    16  )
    17  
    18  var _ = Describe("IP settings", func() {
    19  	var (
    20  		container1 garden.Container
    21  		container2 garden.Container
    22  
    23  		containerNetwork1 string
    24  		containerNetwork2 string
    25  
    26  		containerInterface string
    27  
    28  		gardenParms []string
    29  	)
    30  
    31  	BeforeEach(func() {
    32  		container1 = nil
    33  		container2 = nil
    34  		containerNetwork1 = ""
    35  		containerNetwork2 = ""
    36  
    37  		gardenParms = []string{}
    38  	})
    39  
    40  	JustBeforeEach(func() {
    41  		client = startGarden(gardenParms...)
    42  
    43  		var err error
    44  		container1, err = client.Create(garden.ContainerSpec{Network: containerNetwork1})
    45  		Expect(err).ToNot(HaveOccurred())
    46  
    47  		if len(containerNetwork2) > 0 {
    48  			container2, err = client.Create(garden.ContainerSpec{Network: containerNetwork2})
    49  			Expect(err).ToNot(HaveOccurred())
    50  		}
    51  
    52  		containerInterface = "w" + strconv.Itoa(GinkgoParallelNode()) + container1.Handle() + "-1"
    53  	})
    54  
    55  	AfterEach(func() {
    56  		if container1 != nil {
    57  			err := client.Destroy(container1.Handle())
    58  			Expect(err).ToNot(HaveOccurred())
    59  		}
    60  
    61  		if container2 != nil {
    62  			err := client.Destroy(container2.Handle())
    63  			Expect(err).ToNot(HaveOccurred())
    64  		}
    65  	})
    66  
    67  	Context("when the Network parameter is a subnet address", func() {
    68  		BeforeEach(func() {
    69  			containerNetwork1 = fmt.Sprintf("10.%d.0.0/24", GinkgoParallelNode())
    70  		})
    71  
    72  		Describe("container's network interface", func() {
    73  			It("has the correct IP address", func() {
    74  				stdout := gbytes.NewBuffer()
    75  				stderr := gbytes.NewBuffer()
    76  
    77  				process, err := container1.Run(garden.ProcessSpec{
    78  					Path: "/sbin/ifconfig",
    79  					Args: []string{containerInterface},
    80  				}, garden.ProcessIO{
    81  					Stdout: stdout,
    82  					Stderr: stderr,
    83  				})
    84  				Expect(err).ToNot(HaveOccurred())
    85  				rc, err := process.Wait()
    86  				Expect(err).ToNot(HaveOccurred())
    87  				Expect(rc).To(Equal(0))
    88  
    89  				Expect(stdout.Contents()).To(ContainSubstring(fmt.Sprintf(" inet addr:10.%d.0.1 ", GinkgoParallelNode())))
    90  			})
    91  		})
    92  	})
    93  
    94  	Context("when the Network parameter is not a subnet address", func() {
    95  		BeforeEach(func() {
    96  			containerNetwork1 = fmt.Sprintf("10.%d.0.2/24", GinkgoParallelNode())
    97  		})
    98  
    99  		Describe("container's network interface", func() {
   100  			It("has the specified IP address", func() {
   101  				stdout := gbytes.NewBuffer()
   102  				stderr := gbytes.NewBuffer()
   103  
   104  				process, err := container1.Run(garden.ProcessSpec{
   105  					Path: "/sbin/ifconfig",
   106  					Args: []string{containerIfName(container1)},
   107  				}, garden.ProcessIO{
   108  					Stdout: stdout,
   109  					Stderr: stderr,
   110  				})
   111  				Expect(err).ToNot(HaveOccurred())
   112  				rc, err := process.Wait()
   113  				Expect(err).ToNot(HaveOccurred())
   114  				Expect(rc).To(Equal(0))
   115  
   116  				Expect(stdout.Contents()).To(ContainSubstring(fmt.Sprintf(" inet addr:10.%d.0.2 ", GinkgoParallelNode())))
   117  			})
   118  		})
   119  	})
   120  
   121  	Describe("the container's network", func() {
   122  		BeforeEach(func() {
   123  			containerNetwork1 = fmt.Sprintf("10.%d.0.0/24", GinkgoParallelNode())
   124  		})
   125  
   126  		It("is reachable from the host", func() {
   127  			info1, ierr := container1.Info()
   128  			Expect(ierr).ToNot(HaveOccurred())
   129  
   130  			out, err := exec.Command("/bin/ping", "-c 2", info1.ContainerIP).Output()
   131  			Expect(out).To(ContainSubstring(" 0% packet loss"))
   132  			Expect(err).ToNot(HaveOccurred())
   133  		})
   134  	})
   135  
   136  	Describe("another container on the same subnet", func() {
   137  		BeforeEach(func() {
   138  			containerNetwork1 = fmt.Sprintf("10.%d.0.0/24", GinkgoParallelNode())
   139  			containerNetwork2 = containerNetwork1
   140  		})
   141  
   142  		Context("when the first container is deleted", func() {
   143  			JustBeforeEach(func() {
   144  				Expect(client.Destroy(container1.Handle())).To(Succeed())
   145  				container1 = nil
   146  			})
   147  
   148  			Context("the second container", func() {
   149  				It("can still reach external networks", func() {
   150  					Expect(checkInternet(container2)).To(Succeed())
   151  				})
   152  
   153  				It("can still be reached from the host", func() {
   154  					info2, ierr := container2.Info()
   155  					Expect(ierr).ToNot(HaveOccurred())
   156  
   157  					out, err := exec.Command("/bin/ping", "-c 2", info2.ContainerIP).Output()
   158  					Expect(out).To(ContainSubstring(" 0% packet loss"))
   159  					Expect(err).ToNot(HaveOccurred())
   160  				})
   161  			})
   162  
   163  			Context("a newly created container in the same subnet", func() {
   164  				var (
   165  					container3 garden.Container
   166  				)
   167  
   168  				JustBeforeEach(func() {
   169  					var err error
   170  					container3, err = client.Create(garden.ContainerSpec{Network: containerNetwork1})
   171  					Expect(err).ToNot(HaveOccurred())
   172  				})
   173  
   174  				AfterEach(func() {
   175  					err := client.Destroy(container3.Handle())
   176  					Expect(err).ToNot(HaveOccurred())
   177  				})
   178  
   179  				It("can reach the second container", func() {
   180  					info2, err := container2.Info()
   181  					Expect(err).ToNot(HaveOccurred())
   182  
   183  					listener, err := container2.Run(garden.ProcessSpec{
   184  						Path: "sh",
   185  						Args: []string{"-c", "echo hi | nc -l -p 8080"},
   186  					}, garden.ProcessIO{})
   187  					Expect(err).ToNot(HaveOccurred())
   188  
   189  					Expect(checkConnection(container3, info2.ContainerIP, 8080)).To(Succeed())
   190  
   191  					Expect(listener.Wait()).To(Equal(0))
   192  				})
   193  
   194  				It("can be reached from the host", func() {
   195  					info3, ierr := container3.Info()
   196  					Expect(ierr).ToNot(HaveOccurred())
   197  
   198  					out, err := exec.Command("/bin/ping", "-c 2", info3.ContainerIP).Output()
   199  					Expect(out).To(ContainSubstring(" 0% packet loss"))
   200  					Expect(err).ToNot(HaveOccurred())
   201  				})
   202  			})
   203  		})
   204  	})
   205  
   206  	Describe("host's network", func() {
   207  		Context("when host access is explicitly allowed", func() {
   208  			BeforeEach(func() {
   209  				containerNetwork1 = fmt.Sprintf("10.%d.0.8/30", GinkgoParallelNode())
   210  				gardenParms = []string{"-allowHostAccess=true"}
   211  			})
   212  
   213  			It("is reachable from inside the container", func() {
   214  				checkHostAccess(container1, true)
   215  			})
   216  		})
   217  
   218  		Context("when host access is explicitly disallowed", func() {
   219  			BeforeEach(func() {
   220  				containerNetwork1 = fmt.Sprintf("10.%d.0.8/30", GinkgoParallelNode())
   221  				gardenParms = []string{"-allowHostAccess=false"}
   222  			})
   223  
   224  			It("is not reachable from inside the container", func() {
   225  				checkHostAccess(container1, false)
   226  			})
   227  		})
   228  
   229  		Context("when host access is implicitly disallowed", func() {
   230  			BeforeEach(func() {
   231  				containerNetwork1 = fmt.Sprintf("10.%d.0.8/30", GinkgoParallelNode())
   232  			})
   233  
   234  			It("is not reachable from inside the container", func() {
   235  				checkHostAccess(container1, false)
   236  			})
   237  		})
   238  	})
   239  
   240  	Describe("the container's external ip", func() {
   241  		It("is the external IP of its host", func() {
   242  			info1, err := container1.Info()
   243  			Expect(err).ToNot(HaveOccurred())
   244  
   245  			localIP, err := localip.LocalIP()
   246  			Expect(err).ToNot(HaveOccurred())
   247  
   248  			Expect(localIP).To(Equal(info1.ExternalIP))
   249  		})
   250  	})
   251  })
   252  
   253  func checkHostAccess(container garden.Container, permitted bool) {
   254  	info1, ierr := container.Info()
   255  	Expect(ierr).ToNot(HaveOccurred())
   256  
   257  	listener, err := net.Listen("tcp", fmt.Sprintf("%s:0", info1.HostIP))
   258  	Expect(err).ToNot(HaveOccurred())
   259  	defer listener.Close()
   260  
   261  	mux := http.NewServeMux()
   262  	mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
   263  		fmt.Fprintf(w, "Hello")
   264  	})
   265  
   266  	go (&http.Server{Handler: mux}).Serve(listener)
   267  
   268  	port, err := strconv.Atoi(strings.Split(listener.Addr().String(), ":")[1])
   269  	Expect(err).ToNot(HaveOccurred())
   270  	err = checkConnection(container, info1.HostIP, port)
   271  
   272  	if permitted {
   273  		Expect(err).ToNot(HaveOccurred())
   274  	} else {
   275  		Expect(err).To(HaveOccurred())
   276  	}
   277  }