Example #1
0
func NewNetCustomBridgeTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
		if err != nil {
			t.Fatalf("Error while getting non-lo host interface: %v\n", err)
		}
		if iface.Name == "" {
			t.Skipf("Cannot run test without non-lo host interface")
		}

		nt := networkTemplateT{
			Name:      "bridge0",
			Type:      "bridge",
			IpMasq:    true,
			IsGateway: true,
			Master:    iface.Name,
			Ipam: &ipamTemplateT{
				Type:   "host-local",
				Subnet: "11.11.3.0/24",
				Routes: []map[string]string{
					{"dst": "0.0.0.0/0"},
				},
			},
		}
		testNetCustomNatConnectivity(t, nt)
		testNetCustomDual(t, nt)
	})
}
Example #2
0
func TestPrivateNetOverride(t *testing.T) {
	ctx := newRktRunCtx()
	defer ctx.cleanup()
	defer ctx.reset()

	iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
	if err != nil {
		t.Fatalf("Error while getting non-lo host interface: %v\n", err)
	}
	if iface.Name == "" {
		t.Skipf("Cannot run test without non-lo host interface")
	}

	nt := networkTemplateT{
		Name:   "overridemacvlan",
		Type:   "macvlan",
		Master: iface.Name,
		Ipam: ipamTemplateT{
			Type:   "host-local",
			Subnet: "10.1.4.0/24",
		},
	}

	netdir := prepareTestNet(t, ctx, nt)
	defer os.RemoveAll(netdir)

	testImageArgs := []string{"--exec=/inspect --print-ipv4=eth0"}
	testImage := patchTestACI("rkt-inspect-networking1.aci", testImageArgs...)
	defer os.Remove(testImage)

	expectedIP := "10.1.4.244"

	cmd := fmt.Sprintf("%s --debug --insecure-skip-verify run --private-net=all --private-net=\"%s:IP=%s\" --mds-register=false %s", ctx.cmd(), nt.Name, expectedIP, testImage)
	fmt.Printf("Command: %v\n", cmd)
	child, err := gexpect.Spawn(cmd)
	if err != nil {
		t.Fatalf("Cannot exec rkt: %v", err)
		return
	}

	defer func() {
		err = child.Wait()
		if err != nil {
			t.Fatalf("rkt didn't terminate correctly: %v", err)
		}
	}()

	expectedRegex := `IPv4: (\d+\.\d+\.\d+\.\d+)`
	result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second)
	if err != nil {
		t.Fatalf("Error: %v\nOutput: %v", err, out)
		return
	}

	containerIP := result[1]
	if expectedIP != containerIP {
		t.Fatalf("overriding IP did not work: Got %q but expected %q", containerIP, expectedIP)
	}
}
Example #3
0
// Test that CNI invocations which return DNS information are carried through to /etc/resolv.conf
func NewNetCNIDNSTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		ctx := testutils.NewRktRunCtx()
		defer ctx.Cleanup()

		iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
		if err != nil {
			t.Fatalf("Error while getting non-lo host interface: %v\n", err)
		}
		if iface.Name == "" {
			t.Skipf("Cannot run test without non-lo host interface")
		}

		nt := networkTemplateT{
			Name:      "bridge0",
			Type:      "cniproxy",
			Args:      []string{"X_LOG=output.json", "X_REAL_PLUGIN=bridge", "X_ADD_DNS=1"},
			IpMasq:    true,
			IsGateway: true,
			Master:    iface.Name,
			Ipam: &ipamTemplateT{
				Type:   "host-local",
				Subnet: "11.11.3.0/24",
				Routes: []map[string]string{
					{"dst": "0.0.0.0/0"},
				},
			},
		}

		// bring the networking up, copy the proxy
		netdir := prepareTestNet(t, ctx, nt)
		defer os.RemoveAll(netdir)

		ga := testutils.NewGoroutineAssistant(t)
		ga.Add(1)

		go func() {
			defer ga.Done()

			appCmd := "--exec=/inspect -- --read-file --file-name=/etc/resolv.conf"
			cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false %s %s",
				ctx.Cmd(), nt.NetParameter(), getInspectImagePath(), appCmd)
			child := ga.SpawnOrFail(cmd)
			defer ga.WaitOrFail(child)

			expectedRegex := "nameserver 1.2.3.4"

			_, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second)
			if err != nil {
				ga.Fatalf("Error: %v\nOutput: %v", err, out)
			}
		}()

		ga.Wait()
	})
}
Example #4
0
func NewNetOverrideTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		ctx := testutils.NewRktRunCtx()
		defer ctx.Cleanup()

		iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
		if err != nil {
			t.Fatalf("Error while getting non-lo host interface: %v\n", err)
		}
		if iface.Name == "" {
			t.Skipf("Cannot run test without non-lo host interface")
		}

		nt := networkTemplateT{
			Name:   "overridemacvlan",
			Type:   "macvlan",
			Master: iface.Name,
			Ipam: &ipamTemplateT{
				Type:   "host-local",
				Subnet: "11.11.4.0/24",
			},
		}

		netdir := prepareTestNet(t, ctx, nt)
		defer os.RemoveAll(netdir)

		testImageArgs := []string{"--exec=/inspect --print-ipv4=eth0"}
		testImage := patchTestACI("rkt-inspect-networking1.aci", testImageArgs...)
		defer os.Remove(testImage)

		expectedIP := "11.11.4.244"

		cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=all --net=\"%s:IP=%s\" --mds-register=false %s", ctx.Cmd(), nt.Name, expectedIP, testImage)
		child := spawnOrFail(t, cmd)
		defer waitOrFail(t, child, 0)

		expectedRegex := `IPv4: (\d+\.\d+\.\d+\.\d+)`
		result, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second)
		if err != nil {
			t.Fatalf("Error: %v\nOutput: %v", err, out)
			return
		}

		containerIP := result[1]
		if expectedIP != containerIP {
			t.Fatalf("overriding IP did not work: Got %q but expected %q", containerIP, expectedIP)
		}
	})
}
Example #5
0
// Test that `rkt run --dns=none` means no resolv.conf is created, even when
// CNI returns DNS informationparseHostsEntries(flagHosts)
func NewNetCNIDNSArgNoneTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		ctx := testutils.NewRktRunCtx()
		defer ctx.Cleanup()

		iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
		if err != nil {
			t.Fatalf("Error while getting non-lo host interface: %v\n", err)
		}
		if iface.Name == "" {
			t.Skipf("Cannot run test without non-lo host interface")
		}

		nt := networkTemplateT{
			Name:      "bridge0",
			Type:      "cniproxy",
			Args:      []string{"X_LOG=output.json", "X_REAL_PLUGIN=bridge", "X_ADD_DNS=1"},
			IpMasq:    true,
			IsGateway: true,
			Master:    iface.Name,
			Ipam: &ipamTemplateT{
				Type:   "host-local",
				Subnet: "11.11.3.0/24",
				Routes: []map[string]string{
					{"dst": "0.0.0.0/0"},
				},
			},
		}

		// bring the networking up, copy the proxy
		prepareTestNet(t, ctx, nt)

		appCmd := "--exec=/inspect -- --stat-file --file-name=/etc/resolv.conf"
		cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false --dns=none %s %s",
			ctx.Cmd(), nt.NetParameter(), getInspectImagePath(), appCmd)
		child := spawnOrFail(t, cmd)
		ctx.RegisterChild(child)
		defer waitOrFail(t, child, 254)

		expectedRegex := `Cannot stat file "/etc/resolv.conf": stat /etc/resolv.conf: no such file or directory`

		_, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second)
		if err != nil {
			t.Fatalf("Error: %v\nOutput: %v", err, out)
		}
	})
}
Example #6
0
func TestNetCustomMacvlan(t *testing.T) {
	iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
	if err != nil {
		t.Fatalf("Error while getting non-lo host interface: %v\n", err)
	}
	if iface.Name == "" {
		t.Skipf("Cannot run test without non-lo host interface")
	}

	nt := networkTemplateT{
		Name:   "macvlan0",
		Type:   "macvlan",
		Master: iface.Name,
		Ipam: ipamTemplateT{
			Type:   "host-local",
			Subnet: "11.11.2.0/24",
		},
	}
	testNetCustomDual(t, nt)
}
Example #7
0
//Test that the CNI execution environment matches the spec
func NewNetCNIEnvTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		ctx := testutils.NewRktRunCtx()
		defer ctx.Cleanup()

		iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
		if err != nil {
			t.Fatalf("Error while getting non-lo host interface: %v\n", err)
		}
		if iface.Name == "" {
			t.Skipf("Cannot run test without non-lo host interface")
		}

		// Declares a network of type cniproxy, which will record state and
		// proxy through to $X_REAL_PLUGIN
		nt := networkTemplateT{
			Name:      "bridge0",
			Type:      "cniproxy",
			Args:      []string{"X_LOG=output.json", "X_REAL_PLUGIN=bridge"},
			IpMasq:    true,
			IsGateway: true,
			Master:    iface.Name,
			Ipam: &ipamTemplateT{
				Type:   "host-local",
				Subnet: "11.11.3.0/24",
				Routes: []map[string]string{
					{"dst": "0.0.0.0/0"},
				},
			},
		}

		// bring the networking up, copy the proxy
		netdir := prepareTestNet(t, ctx, nt)

		appCmd := "--exec=/inspect -- --print-defaultgwv4 "
		cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false %s %s",
			ctx.Cmd(), nt.NetParameter(), getInspectImagePath(), appCmd)
		child := spawnOrFail(t, cmd)

		expectedRegex := "DefaultGWv4: 11.11.3.1"

		_, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second)
		if err != nil {
			t.Fatalf("Error: %v\nOutput: %v", err, out)
		}
		waitOrFail(t, child, 0)

		// Parse the log file
		cniLogFilename := filepath.Join(netdir, "output.json")
		proxyLog, err := parseCNIProxyLog(cniLogFilename)
		if err != nil {
			t.Fatal("Failed to read cniproxy ADD log", err)
		}
		os.Remove(cniLogFilename)

		// Check that the stdin matches the network config file
		expectedConfig, err := ioutil.ReadFile(filepath.Join(netdir, nt.Name+".conf"))
		if err != nil {
			t.Fatal("Failed to read network configuration", err)
		}

		if string(expectedConfig) != proxyLog.Stdin {
			t.Fatalf("CNI plugin stdin incorrect, expected <<%v>>, actual <<%v>>", expectedConfig, proxyLog.Stdin)
		}

		// compare the CNI env against a set of regexes
		checkEnv := func(step string, expectedEnv, actualEnv map[string]string) {
			for k, v := range expectedEnv {
				actual, exists := actualEnv[k]
				if !exists {
					t.Fatalf("Step %s, expected proxy CNI arg %s but not found", step, k)
				}

				re, err := regexp.Compile(v)
				if err != nil {
					t.Fatalf("Step %s, invalid CNI env regex for key %s %v", step, k, err)
				}
				found := re.FindString(actual)
				if found == "" {
					t.Fatalf("step %s cni environment %s was %s but expected pattern %s", step, k, actual, v)
				}
			}
		}

		expectedEnv := map[string]string{
			"CNI_VERSION":     `^0\.1\.0$`,
			"CNI_COMMAND":     `^ADD$`,
			"CNI_IFNAME":      `^eth\d$`,
			"CNI_PATH":        "^" + netdir + ":/usr/lib/rkt/plugins/net:stage1/rootfs/usr/lib/rkt/plugins/net$",
			"CNI_NETNS":       `^/var/run/netns/cni-`,
			"CNI_CONTAINERID": `^[a-fA-F0-9-]{36}$`, //UUID, close enough
		}
		checkEnv("add", expectedEnv, proxyLog.EnvMap)

		/*
			Run rkt GC, ensure the CNI invocation looks sane
		*/
		ctx.RunGC()
		proxyLog, err = parseCNIProxyLog(cniLogFilename)
		if err != nil {
			t.Fatal("Failed to read cniproxy DEL log", err)
		}
		os.Remove(cniLogFilename)

		expectedEnv["CNI_COMMAND"] = `^DEL$`
		checkEnv("del", expectedEnv, proxyLog.EnvMap)

	})
}
func TestSocketProxyd(t *testing.T) {
	if !sd_util.IsRunningSystemd() {
		t.Skip("Systemd is not running on the host.")
	}

	socketProxydPath := "/lib/systemd/systemd-socket-proxyd"
	if _, err := os.Stat(socketProxydPath); os.IsNotExist(err) {
		t.Skip("systemd-socket-proxyd is not installed.")
	}

	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
	if err != nil {
		t.Fatalf("Error while getting non-lo host interface: %v\n", err)
	}
	if iface.Name == "" {
		t.Skipf("Cannot run test without non-lo host interface")
	}

	nt := networkTemplateT{
		Name:   "ptp0",
		Type:   "ptp",
		IpMasq: true,
		Master: iface.Name,
		Ipam: &ipamTemplateT{
			Type:   "host-local",
			Subnet: "192.168.0.0/24",
			Routes: []map[string]string{
				{"dst": "0.0.0.0/0"},
			},
		},
	}

	netDir := prepareTestNet(t, ctx, nt)
	defer os.RemoveAll(netDir)

	port, err := randomFreePort(t)
	if err != nil {
		t.Fatal(err)
	}

	echoImage := patchTestACI("rkt-inspect-echo.aci",
		"--exec=/echo-socket-activated",
		"--ports=test-port,protocol=tcp,port=80,socketActivated=true")
	defer os.Remove(echoImage)

	conn, err := sd_dbus.New()
	if err != nil {
		t.Fatal(err)
	}

	rktTestingEchoService := `
	[Unit]
	Description=Socket-activated echo server

	[Service]
	ExecStart=%s
	KillMode=process
	`

	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	rnd := r.Int()

	// Write unit files directly to runtime system units directory
	// (/run/systemd/system) to avoid calling LinkUnitFiles - it is buggy in
	// systemd v219 as it does not work with absolute paths.
	unitsDir := "/run/systemd/system"
	containerIP := "192.168.0.101"

	cmd := fmt.Sprintf("%s --insecure-options=image --debug run --net=%s:IP=%s --port=test-port:%d --mds-register=false %s",
		ctx.Cmd(), nt.Name, containerIP, port, echoImage)

	serviceContent := fmt.Sprintf(rktTestingEchoService, cmd)
	serviceTargetBase := fmt.Sprintf("rkt-testing-socket-activation-%d.service", rnd)
	serviceTarget := filepath.Join(unitsDir, serviceTargetBase)

	if err := ioutil.WriteFile(serviceTarget, []byte(serviceContent), 0666); err != nil {
		t.Fatal(err)
	}
	defer os.Remove(serviceTarget)

	rktTestingEchoSocket := `
	[Unit]
	Description=Socket-activated netcat server socket

	[Socket]
	ListenStream=%d

	[Install]
	WantedBy=sockets.target
	`

	socketContent := fmt.Sprintf(rktTestingEchoSocket, port)
	socketTargetBase := fmt.Sprintf("proxy-to-rkt-testing-socket-activation-%d.socket", rnd)
	socketTarget := filepath.Join(unitsDir, socketTargetBase)

	if err := ioutil.WriteFile(socketTarget, []byte(socketContent), 0666); err != nil {
		t.Fatal(err)
	}
	defer os.Remove(socketTarget)

	proxyToRktTestingEchoService := `
	[Unit]
	Requires=%s
	After=%s

	[Service]
	ExecStart=%s %s:%d
	`

	proxyContent := fmt.Sprintf(proxyToRktTestingEchoService, serviceTargetBase, serviceTargetBase,
		socketProxydPath, containerIP, port)
	proxyContentBase := fmt.Sprintf("proxy-to-rkt-testing-socket-activation-%d.service", rnd)
	proxyTarget := filepath.Join(unitsDir, proxyContentBase)

	if err := ioutil.WriteFile(proxyTarget, []byte(proxyContent), 0666); err != nil {
		t.Fatal(err)
	}
	defer os.Remove(proxyTarget)

	reschan := make(chan string)
	doJob := func() {
		job := <-reschan
		if job != "done" {
			t.Fatal("Job is not done:", job)
		}
	}

	if _, err := conn.StartUnit(socketTargetBase, "replace", reschan); err != nil {
		t.Fatal(err)
	}
	doJob()

	defer func() {
		if _, err := conn.StopUnit(socketTargetBase, "replace", reschan); err != nil {
			t.Fatal(err)
		}
		doJob()

		if _, err := conn.StopUnit(serviceTargetBase, "replace", reschan); err != nil {
			t.Fatal(err)
		}
		doJob()

		if _, err := conn.StopUnit(proxyContentBase, "replace", reschan); err != nil {
			t.Fatal(err)
		}
		doJob()
	}()

	expected := "HELO\n"
	sockConn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", port))
	if err != nil {
		t.Fatal(err)
	}

	if _, err := fmt.Fprintf(sockConn, expected); err != nil {
		t.Fatal(err)
	}

	answer, err := bufio.NewReader(sockConn).ReadString('\n')
	if err != nil {
		t.Fatal(err)
	}

	if answer != expected {
		t.Fatalf("Expected %q, Got %q", expected, answer)
	}

	return
}
Example #9
0
//Test that the CNI execution environment matches the spec
func NewNetCNIEnvTest() testutils.Test {
	return testutils.TestFunc(func(t *testing.T) {
		ctx := testutils.NewRktRunCtx()
		defer ctx.Cleanup()

		iface, _, err := testutils.GetNonLoIfaceWithAddrs(netlink.FAMILY_V4)
		if err != nil {
			t.Fatalf("Error while getting non-lo host interface: %v\n", err)
		}
		if iface.Name == "" {
			t.Skipf("Cannot run test without non-lo host interface")
		}

		// Declares a network of type cniproxy, which will record state and
		// proxy through to $X_REAL_PLUGIN
		nt := networkTemplateT{
			Name:      "bridge0",
			Type:      "cniproxy",
			Args:      []string{"X_LOG=output.json", "X_REAL_PLUGIN=bridge"},
			IpMasq:    true,
			IsGateway: true,
			Master:    iface.Name,
			Ipam: &ipamTemplateT{
				Type:   "host-local",
				Subnet: "11.11.3.0/24",
				Routes: []map[string]string{
					{"dst": "0.0.0.0/0"},
				},
			},
		}

		// bring the networking up, copy the proxy
		netdir := prepareTestNet(t, ctx, nt)
		defer os.RemoveAll(netdir)

		ga := testutils.NewGoroutineAssistant(t)
		ga.Add(1)

		go func() {
			defer ga.Done()
			appCmd := "--exec=/inspect -- --print-defaultgwv4 "
			cmd := fmt.Sprintf("%s --debug --insecure-options=image run --net=%v --mds-register=false %s %s",
				ctx.Cmd(), nt.NetParameter(), getInspectImagePath(), appCmd)
			child := ga.SpawnOrFail(cmd)
			defer ga.WaitOrFail(child)

			expectedRegex := "DefaultGWv4: 11.11.3.1"

			_, out, err := expectRegexTimeoutWithOutput(child, expectedRegex, 30*time.Second)
			if err != nil {
				ga.Fatalf("Error: %v\nOutput: %v", err, out)
			}
		}()

		ga.Wait()

		// Parse the log file
		proxyLog, err := parseCNIProxyLog(filepath.Join(netdir, "output.json"))
		if err != nil {
			t.Fatal("Failed to read cniproxy log", err)
		}

		// Check that the stdin matches the network config file
		expectedConfig, err := ioutil.ReadFile(filepath.Join(netdir, nt.Name+".conf"))
		if err != nil {
			t.Fatal("Failed to read network configuration", err)
		}

		if string(expectedConfig) != proxyLog.Stdin {
			t.Fatalf("CNI plugin stdin incorrect, expected <<%v>>, actual <<%v>>", expectedConfig, proxyLog.Stdin)
		}

		// Check that the environment is sane - these are regexes
		expectedEnv := map[string]string{
			"CNI_VERSION":     "0.3.0",
			"CNI_COMMAND":     "ADD",
			"CNI_IFNAME":      `eth\d`,
			"CNI_PATH":        netdir,
			"CNI_NETNS":       `/var/run/netns/cni-`,
			"CNI_CONTAINERID": `^[a-fA-F0-9-]{36}`, //UUID, close enough
		}

		for k, v := range expectedEnv {
			actual, exists := proxyLog.EnvMap[k]
			if !exists {
				t.Fatalf("Expected proxy CNI arg %s but not found", k)
			}

			re, err := regexp.Compile(v)
			if err != nil {
				t.Fatal("Invalid CNI env regex", v, err)
			}
			found := re.FindString(actual)
			if found == "" {
				t.Fatalf("CNI_ARG %s was %s but expected pattern %s", k, actual, v)
			}
		}
	})
}