github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/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/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	"github.com/onsi/gomega/gbytes"
    15  	"github.com/pivotal-golang/localip"
    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  					User: "alice",
    79  					Path: "ifconfig",
    80  					Args: []string{containerInterface},
    81  				}, garden.ProcessIO{
    82  					Stdout: stdout,
    83  					Stderr: stderr,
    84  				})
    85  				Expect(err).ToNot(HaveOccurred())
    86  				rc, err := process.Wait()
    87  				Expect(err).ToNot(HaveOccurred())
    88  				Expect(rc).To(Equal(0))
    89  
    90  				Expect(stdout.Contents()).To(ContainSubstring(fmt.Sprintf(" inet addr:10.%d.0.2 ", GinkgoParallelNode())))
    91  			})
    92  		})
    93  
    94  		Describe("container's info", func() {
    95  			It("has the correct host IP address", func() {
    96  				info, err := container1.Info()
    97  				Expect(err).ToNot(HaveOccurred())
    98  
    99  				Expect(info.HostIP).To(Equal(fmt.Sprintf("10.%d.0.1", GinkgoParallelNode())))
   100  			})
   101  		})
   102  	})
   103  
   104  	Context("when the Network parameter is not a subnet address", func() {
   105  		BeforeEach(func() {
   106  			containerNetwork1 = fmt.Sprintf("10.%d.0.2/24", GinkgoParallelNode())
   107  		})
   108  
   109  		Describe("container's network interface", func() {
   110  			It("has the specified IP address", func() {
   111  				stdout := gbytes.NewBuffer()
   112  				stderr := gbytes.NewBuffer()
   113  
   114  				process, err := container1.Run(garden.ProcessSpec{
   115  					User: "alice",
   116  					Path: "ifconfig",
   117  					Args: []string{containerIfName(container1)},
   118  				}, garden.ProcessIO{
   119  					Stdout: stdout,
   120  					Stderr: stderr,
   121  				})
   122  				Expect(err).ToNot(HaveOccurred())
   123  				rc, err := process.Wait()
   124  				Expect(err).ToNot(HaveOccurred())
   125  				Expect(rc).To(Equal(0))
   126  
   127  				Expect(stdout.Contents()).To(ContainSubstring(fmt.Sprintf(" inet addr:10.%d.0.2 ", GinkgoParallelNode())))
   128  			})
   129  		})
   130  	})
   131  
   132  	Describe("the container's network", func() {
   133  		BeforeEach(func() {
   134  			containerNetwork1 = fmt.Sprintf("10.%d.0.0/24", GinkgoParallelNode())
   135  		})
   136  
   137  		It("is reachable from the host", func() {
   138  			info1, ierr := container1.Info()
   139  			Expect(ierr).ToNot(HaveOccurred())
   140  
   141  			out, err := exec.Command("/bin/ping", "-c 2", info1.ContainerIP).Output()
   142  			Expect(out).To(ContainSubstring(" 0% packet loss"))
   143  			Expect(err).ToNot(HaveOccurred())
   144  		})
   145  	})
   146  
   147  	Describe("another container on the same subnet", func() {
   148  		BeforeEach(func() {
   149  			containerNetwork1 = fmt.Sprintf("10.%d.0.0/24", GinkgoParallelNode())
   150  			containerNetwork2 = containerNetwork1
   151  		})
   152  
   153  		Context("when the first container is deleted", func() {
   154  			JustBeforeEach(func() {
   155  				Expect(client.Destroy(container1.Handle())).To(Succeed())
   156  				container1 = nil
   157  			})
   158  
   159  			Context("the second container", func() {
   160  				It("can still reach external networks", func() {
   161  					Expect(checkInternet(container2)).To(Succeed())
   162  				})
   163  
   164  				It("can still be reached from the host", func() {
   165  					info2, ierr := container2.Info()
   166  					Expect(ierr).ToNot(HaveOccurred())
   167  
   168  					out, err := exec.Command("/bin/ping", "-c 2", info2.ContainerIP).Output()
   169  					Expect(out).To(ContainSubstring(" 0% packet loss"))
   170  					Expect(err).ToNot(HaveOccurred())
   171  				})
   172  			})
   173  
   174  			Context("a newly created container in the same subnet", func() {
   175  				var (
   176  					container3 garden.Container
   177  				)
   178  
   179  				JustBeforeEach(func() {
   180  					var err error
   181  					container3, err = client.Create(garden.ContainerSpec{Network: containerNetwork1})
   182  					Expect(err).ToNot(HaveOccurred())
   183  				})
   184  
   185  				AfterEach(func() {
   186  					err := client.Destroy(container3.Handle())
   187  					Expect(err).ToNot(HaveOccurred())
   188  				})
   189  
   190  				It("can reach the second container", func() {
   191  					info2, err := container2.Info()
   192  					Expect(err).ToNot(HaveOccurred())
   193  
   194  					listener, err := container2.Run(garden.ProcessSpec{
   195  						User: "alice",
   196  						Path: "sh",
   197  						Args: []string{"-c", "echo hi | nc -l -p 8080"},
   198  					}, garden.ProcessIO{})
   199  					Expect(err).ToNot(HaveOccurred())
   200  
   201  					Eventually(func() error { return checkConnection(container3, info2.ContainerIP, 8080) }).Should(Succeed())
   202  
   203  					Expect(listener.Wait()).To(Equal(0))
   204  				})
   205  
   206  				It("can be reached from the host", func() {
   207  					info3, ierr := container3.Info()
   208  					Expect(ierr).ToNot(HaveOccurred())
   209  
   210  					out, err := exec.Command("/bin/ping", "-c 2", info3.ContainerIP).Output()
   211  					Expect(out).To(ContainSubstring(" 0% packet loss"))
   212  					Expect(err).ToNot(HaveOccurred())
   213  				})
   214  			})
   215  		})
   216  	})
   217  
   218  	Describe("host's network", func() {
   219  		Context("when host access is explicitly allowed", func() {
   220  			BeforeEach(func() {
   221  				containerNetwork1 = fmt.Sprintf("10.%d.0.8/30", GinkgoParallelNode())
   222  				gardenParms = []string{"-allowHostAccess=true"}
   223  			})
   224  
   225  			It("is reachable from inside the container", func() {
   226  				checkHostAccess(container1, true)
   227  			})
   228  		})
   229  
   230  		Context("when host access is explicitly disallowed", func() {
   231  			BeforeEach(func() {
   232  				containerNetwork1 = fmt.Sprintf("10.%d.0.8/30", GinkgoParallelNode())
   233  				gardenParms = []string{"-allowHostAccess=false"}
   234  			})
   235  
   236  			It("is not reachable from inside the container", func() {
   237  				checkHostAccess(container1, false)
   238  			})
   239  		})
   240  
   241  		Context("when host access is implicitly disallowed", func() {
   242  			BeforeEach(func() {
   243  				containerNetwork1 = fmt.Sprintf("10.%d.0.8/30", GinkgoParallelNode())
   244  			})
   245  
   246  			It("is not reachable from inside the container", func() {
   247  				checkHostAccess(container1, false)
   248  			})
   249  		})
   250  	})
   251  
   252  	Describe("the container's external ip", func() {
   253  		It("is the external IP of its host", func() {
   254  			info1, err := container1.Info()
   255  			Expect(err).ToNot(HaveOccurred())
   256  
   257  			localIP, err := localip.LocalIP()
   258  			Expect(err).ToNot(HaveOccurred())
   259  
   260  			Expect(localIP).To(Equal(info1.ExternalIP))
   261  		})
   262  	})
   263  })
   264  
   265  func checkHostAccess(container garden.Container, permitted bool) {
   266  	info1, ierr := container.Info()
   267  	Expect(ierr).ToNot(HaveOccurred())
   268  
   269  	listener, err := net.Listen("tcp", fmt.Sprintf("%s:0", info1.HostIP))
   270  	Expect(err).ToNot(HaveOccurred())
   271  	defer listener.Close()
   272  
   273  	mux := http.NewServeMux()
   274  	mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
   275  		fmt.Fprintf(w, "Hello")
   276  	})
   277  
   278  	go (&http.Server{Handler: mux}).Serve(listener)
   279  
   280  	port, err := strconv.Atoi(strings.Split(listener.Addr().String(), ":")[1])
   281  	Expect(err).ToNot(HaveOccurred())
   282  	err = checkConnection(container, info1.HostIP, port)
   283  
   284  	if permitted {
   285  		Expect(err).ToNot(HaveOccurred())
   286  	} else {
   287  		Expect(err).To(HaveOccurred())
   288  	}
   289  }