/* * Default-restricted net * --- * Container launches http server on all its interfaces * Host must be able to connects to container's http server via container's * eth0's IPv4 * TODO: verify that the container isn't NATed */ func TestNetDefaultRestrictedConnectivity(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() f := func(argument string) { httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) iface := "eth0" testImageArgs := []string{fmt.Sprintf("--exec=/inspect --print-ipv4=%v --serve-http=%v", iface, httpServeAddr)} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run %s --mds-register=false %s", ctx.cmd(), argument, testImage) child := spawnOrFail(t, cmd) expectedRegex := `IPv4: (.*)\r` result, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { t.Fatalf("Error: %v\nOutput: %v", err, out) } httpGetAddr := fmt.Sprintf("http://%v:%v", result[1], httpPort) ga := testutils.NewGoroutineAssistant(t) // Child opens the server ga.Add(1) go func() { defer ga.Done() waitOrFail(t, child, true) }() // Host connects to the child ga.Add(1) go func() { defer ga.Done() expectedRegex := `serving on` _, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } body, err := testutils.HttpGet(httpGetAddr) if err != nil { ga.Fatalf("%v\n", err) return } log.Printf("HTTP-Get received: %s", body) if err != nil { ga.Fatalf("%v\n", err) } }() ga.Wait() } f("--net=default-restricted") f("--net=none") }
/* * No private net * --- * Container launches http server which must be reachable by the host via the * localhost address */ func TestPrivateNetOmittedConnectivity(t *testing.T) { httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) httpGetAddr := fmt.Sprintf("http://127.0.0.1:%v", httpPort) testImageArgs := []string{"--exec=/inspect --serve-http=" + httpServeAddr} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ctx := newRktRunCtx() defer ctx.cleanup() defer ctx.reset() cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --mds-register=false %s", ctx.cmd(), testImage) t.Logf("Command: %v\n", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } ga := testutils.NewGoroutineAssistant(t) // Child opens the server ga.Add(1) go func() { defer ga.Done() err = child.Wait() if err != nil { ga.Fatalf("rkt didn't terminate correctly: %v", err) return } }() // Host connects to the child ga.Add(1) go func() { defer ga.Done() expectedRegex := `serving on` _, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } body, err := testutils.HttpGet(httpGetAddr) if err != nil { ga.Fatalf("%v\n", err) return } log.Printf("HTTP-Get received: %s", body) }() ga.Wait() }
/* * Host networking * --- * Container launches http server which must be reachable by the host via the * localhost address */ func NewNetHostConnectivityTest() testutils.Test { return testutils.TestFunc(func(t *testing.T) { logger.SetLogger(t) httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) httpGetAddr := fmt.Sprintf("http://127.0.0.1:%v", httpPort) testImageArgs := []string{"--exec=/inspect --serve-http=" + httpServeAddr} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() cmd := fmt.Sprintf("%s --net=host --debug --insecure-options=image run --mds-register=false %s", ctx.Cmd(), testImage) child := spawnOrFail(t, cmd) ctx.RegisterChild(child) ga := testutils.NewGoroutineAssistant(t) ga.Add(2) // Child opens the server go func() { defer ga.Done() ga.WaitOrFail(child) }() // Host connects to the child go func() { defer ga.Done() expectedRegex := `serving on` _, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) } body, err := testutils.HTTPGet(httpGetAddr) if err != nil { ga.Fatalf("%v\n", err) } t.Logf("HTTP-Get received: %s", body) }() ga.Wait() }) }
/* * Host launches http server on all interfaces in the host netns * Container must be able to connect via any IP address of the host in the * macvlan network, which is NAT * TODO: test connection to host on an outside interface */ func testNetCustomNatConnectivity(t *testing.T, nt networkTemplateT) { ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() prepareTestNet(t, ctx, nt) httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) httpServeTimeout := 30 nonLoIPv4, err := testutils.GetNonLoIfaceIPv4() if err != nil { t.Fatalf("%v", err) } if nonLoIPv4 == "" { t.Skipf("Can not find any NAT'able IPv4 on the host, skipping..") } httpGetAddr := fmt.Sprintf("http://%v:%v", nonLoIPv4, httpPort) t.Log("Telling the child to connect via", httpGetAddr) ga := testutils.NewGoroutineAssistant(t) ga.Add(2) // Host opens the server go func() { defer ga.Done() err := testutils.HTTPServe(httpServeAddr, httpServeTimeout) if err != nil { ga.Fatalf("Error during HTTPServe: %v", err) } }() // Child connects to host hostname, err := os.Hostname() if err != nil { panic(err) } go func() { defer ga.Done() testImageArgs := []string{fmt.Sprintf("--exec=/inspect --get-http=%v", httpGetAddr)} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false %s", ctx.Cmd(), nt.Name, testImage) child := ga.SpawnOrFail(cmd) defer ga.WaitOrFail(child) expectedRegex := `HTTP-Get received: (.*?)\r` result, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) } if result[1] != hostname { ga.Fatalf("Hostname received by client `%v` doesn't match `%v`", result[1], hostname) } }() ga.Wait() }
/* * Two containers spawn in the same custom network. * --- * Container 1 opens the http server * Container 2 fires a HTTPGet on it * The body of the HTTPGet is Container 1's hostname, which must match */ func testNetCustomDual(t *testing.T, nt networkTemplateT) { httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } ctx := testutils.NewRktRunCtx() defer ctx.Cleanup() prepareTestNet(t, ctx, nt) container1IPv4, container1Hostname := make(chan string), make(chan string) ga := testutils.NewGoroutineAssistant(t) ga.Add(2) go func() { defer ga.Done() httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) testImageArgs := []string{"--exec=/inspect --print-ipv4=eth0 --serve-http=" + httpServeAddr} testImage := patchTestACI("rkt-inspect-networking1.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false %s", ctx.Cmd(), nt.Name, testImage) child := ga.SpawnOrFail(cmd) defer ga.WaitOrFail(child) expectedRegex := `IPv4: (\d+\.\d+\.\d+\.\d+)` result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) } container1IPv4 <- result[1] expectedRegex = ` ([a-zA-Z0-9\-]*): serving on` result, out, err = expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) } container1Hostname <- result[1] }() go func() { defer ga.Done() var httpGetAddr string httpGetAddr = fmt.Sprintf("http://%v:%v", <-container1IPv4, httpPort) testImageArgs := []string{"--exec=/inspect --get-http=" + httpGetAddr} testImage := patchTestACI("rkt-inspect-networking2.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false %s", ctx.Cmd(), nt.Name, testImage) child := ga.SpawnOrFail(cmd) defer ga.WaitOrFail(child) expectedHostname := <-container1Hostname expectedRegex := `HTTP-Get received: (.*?)\r` result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 20*time.Second) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) } t.Logf("HTTP-Get received: %s", result[1]) receivedHostname := result[1] if receivedHostname != expectedHostname { ga.Fatalf("Received hostname `%v` doesn't match `%v`", receivedHostname, expectedHostname) } }() ga.Wait() }
/* * Host launches http server on all interfaces in the host netns * Container must be able to connect via any IP address of the host in the * macvlan network, which is NAT * TODO: test connection to host on an outside interface */ func testPrivateNetCustomNatConnectivity(t *testing.T, nt networkTemplateT) { ctx := newRktRunCtx() defer ctx.cleanup() defer ctx.reset() netdir := prepareTestNet(t, ctx, nt) defer os.RemoveAll(netdir) httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) httpServeTimeout := 30 nonLoIPv4, err := testutils.GetNonLoIfaceIPv4() if err != nil { t.Fatalf("%v", err) } if nonLoIPv4 == "" { t.Skipf("Can not find any NAT'able IPv4 on the host, skipping..") } httpGetAddr := fmt.Sprintf("http://%v:%v", nonLoIPv4, httpPort) t.Log("Telling the child to connect via", httpGetAddr) ga := testutils.NewGoroutineAssistant(t) // Host opens the server ga.Add(1) go func() { defer ga.Done() err := testutils.HttpServe(httpServeAddr, httpServeTimeout) if err != nil { t.Fatalf("Error during HttpServe: %v", err) } }() // Child connects to host ga.Add(1) hostname, err := os.Hostname() go func() { defer ga.Done() testImageArgs := []string{fmt.Sprintf("--exec=/inspect --get-http=%v", httpGetAddr)} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --private-net=%v --mds-register=false %s", ctx.cmd(), nt.Name, testImage) t.Logf("Command: %v\n", cmd) child, err := gexpect.Spawn(cmd) if err != nil { ga.Fatalf("Cannot exec rkt: %v", err) return } expectedRegex := `HTTP-Get received: (.*)\r` result, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } if result[1] != hostname { ga.Fatalf("Hostname received by client `%v` doesn't match `%v`", result[1], hostname) return } err = child.Wait() if err != nil { ga.Fatalf("rkt didn't terminate correctly: %v", err) } }() ga.Wait() }
/* * Two containers spawn in the same custom network. * --- * Container 1 opens the http server * Container 2 fires a HttpGet on it * The body of the HttpGet is Container 1's hostname, which must match */ func testPrivateNetCustomDual(t *testing.T, nt networkTemplateT) { httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } ctx := newRktRunCtx() defer ctx.cleanup() defer ctx.reset() netdir := prepareTestNet(t, ctx, nt) defer os.RemoveAll(netdir) container1IPv4, container1Hostname := make(chan string), make(chan string) ga := testutils.NewGoroutineAssistant(t) ga.Add(1) go func() { defer ga.Done() httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) testImageArgs := []string{"--exec=/inspect --print-ipv4=eth0 --serve-http=" + httpServeAddr} testImage := patchTestACI("rkt-inspect-networking1.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --private-net=%v --mds-register=false %s", ctx.cmd(), nt.Name, testImage) fmt.Printf("Command: %v\n", cmd) child, err := gexpect.Spawn(cmd) if err != nil { ga.Fatalf("Cannot exec rkt: %v", err) return } expectedRegex := `IPv4: (\d+\.\d+\.\d+\.\d+)` result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } container1IPv4 <- result[1] expectedRegex = `(rkt-.*): serving on` result, out, err = expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } container1Hostname <- result[1] err = child.Wait() if err != nil { ga.Fatalf("rkt didn't terminate correctly: %v", err) } }() ga.Add(1) go func() { defer ga.Done() var httpGetAddr string httpGetAddr = fmt.Sprintf("http://%v:%v", <-container1IPv4, httpPort) testImageArgs := []string{"--exec=/inspect --get-http=" + httpGetAddr} testImage := patchTestACI("rkt-inspect-networking2.aci", testImageArgs...) defer os.Remove(testImage) cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --private-net=%v --mds-register=false %s", ctx.cmd(), nt.Name, testImage) fmt.Printf("Command: %v\n", cmd) child, err := gexpect.Spawn(cmd) if err != nil { t.Fatalf("Cannot exec rkt: %v", err) } expectedHostname := <-container1Hostname expectedRegex := `HTTP-Get received: (.*)\r` result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 20*time.Second) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } t.Logf("HTTP-Get received: %s", result[1]) receivedHostname := result[1] if receivedHostname != expectedHostname { ga.Fatalf("Received hostname `%v` doesn't match `%v`", receivedHostname, expectedHostname) return } err = child.Wait() if err != nil { ga.Fatalf("rkt didn't terminate correctly: %v", err) } }() ga.Wait() }
/* * Default net * --- * Host launches http server on all interfaces in the host netns * Container must be able to connect via any IP address of the host in the * default network, which is NATed * TODO: test connection to host on an outside interface */ func TestNetDefaultConnectivity(t *testing.T) { ctx := newRktRunCtx() defer ctx.cleanup() f := func(argument string) { httpPort, err := testutils.GetNextFreePort4() if err != nil { t.Fatalf("%v", err) } httpServeAddr := fmt.Sprintf("0.0.0.0:%v", httpPort) httpServeTimeout := 30 nonLoIPv4, err := testutils.GetNonLoIfaceIPv4() if err != nil { t.Fatalf("%v", err) } if nonLoIPv4 == "" { t.Skipf("Can not find any NAT'able IPv4 on the host, skipping..") } httpGetAddr := fmt.Sprintf("http://%v:%v", nonLoIPv4, httpPort) t.Log("Telling the child to connect via", httpGetAddr) testImageArgs := []string{fmt.Sprintf("--exec=/inspect --get-http=%v", httpGetAddr)} testImage := patchTestACI("rkt-inspect-networking.aci", testImageArgs...) defer os.Remove(testImage) ga := testutils.NewGoroutineAssistant(t) // Host opens the server ga.Add(1) go func() { defer ga.Done() err := testutils.HttpServe(httpServeAddr, httpServeTimeout) if err != nil { ga.Fatalf("Error during HttpServe: %v", err) } }() // Child connects to host ga.Add(1) hostname, err := os.Hostname() if err != nil { ga.Fatalf("Error getting hostname: %v", err) } go func() { defer ga.Done() cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run %s --mds-register=false %s", ctx.cmd(), argument, testImage) child := spawnOrFail(t, cmd) defer waitOrFail(t, child, true) expectedRegex := `HTTP-Get received: (.*)\r` result, out, err := expectRegexWithOutput(child, expectedRegex) if err != nil { ga.Fatalf("Error: %v\nOutput: %v", err, out) return } if result[1] != hostname { ga.Fatalf("Hostname received by client `%v` doesn't match `%v`", result[1], hostname) return } }() ga.Wait() } f("--net=default") f("") }