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 }