Пример #1
0
func TestPatchOVS(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ovs-vsctl add-br br-test1", true},
		{"ovs-vsctl add-br br-test2", true},
		{"ovs-vsctl add-port br-test1 patch-br-test2 -- set interface patch-br-test2 type=patch", true},
		{"ovs-vsctl add-port br-test2 patch-br-test1 -- set interface patch-br-test1 type=patch", true},
		{"ovs-vsctl set interface patch-br-test2 option:peer=patch-br-test1", true},
		{"ovs-vsctl set interface patch-br-test1 option:peer=patch-br-test2", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
		{"ovs-vsctl del-br br-test2", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 10 && len(g.GetEdges()) >= 9 {
			patch1 := g.LookupFirstNode(graph.Metadata{"Type": "patch", "Name": "patch-br-test1", "Driver": "openvswitch"})
			if patch1 == nil {
				return
			}

			patch2 := g.LookupFirstNode(graph.Metadata{"Type": "patch", "Name": "patch-br-test2", "Driver": "openvswitch"})
			if patch2 == nil {
				return
			}

			if !g.AreLinked(patch1, patch2) {
				return
			}

			testPassed = true

			ws.Close()
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test1", "br-test2", "patch-br-test1", "patch-br-test2"})
}
Пример #2
0
func TestNameSpaceOVSInterface(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip netns add ns1", true},
		{"ovs-vsctl add-br br-test1", true},
		{"ovs-vsctl add-port br-test1 intf1 -- set interface intf1 type=internal", true},
		{"ip l set intf1 netns ns1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
		{"ip netns del ns1", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 2 && len(g.GetEdges()) >= 2 {
			node := g.LookupFirstNode(graph.Metadata{"Name": "ns1", "Type": "netns"})
			if node == nil {
				return
			}

			veth := g.LookupFirstChild(node, graph.Metadata{"Name": "intf1"})
			if veth == nil {
				return
			}

			children := g.LookupNodes(graph.Metadata{"Name": "intf1", "Type": "internal"})
			if len(children) == 1 {
				testPassed = true

				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"ns1", "br-test1"})
}
Пример #3
0
func TestInterfaceOVS(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ovs-vsctl add-br br-test1", true},
		{"ovs-vsctl add-port br-test1 intf1 -- set interface intf1 type=internal", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 5 && len(g.GetEdges()) >= 4 {
			intf := g.LookupFirstNode(graph.Metadata{"Type": "internal", "Name": "intf1", "Driver": "openvswitch"})
			if intf != nil {
				if _, ok := intf.Metadata()["UUID"]; ok {
					// check we don't have another interface potentially added by netlink
					// should only have ovsport and interface
					others := g.LookupNodes(graph.Metadata{"Name": "intf1"})
					if len(others) > 2 {
						return
					}

					if _, ok := intf.Metadata()["MAC"]; !ok {
						return
					}

					testPassed = true

					ws.Close()
				}
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test1", "intf1"})
}
Пример #4
0
func TestBridgeOVS(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ovs-vsctl add-br br-test1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 3 && len(g.GetEdges()) >= 2 {
			ovsbridge := g.LookupFirstNode(graph.Metadata{"Type": "ovsbridge", "Name": "br-test1"})
			if ovsbridge == nil {
				return
			}
			ovsports := g.LookupChildren(ovsbridge, graph.Metadata{"Type": "ovsport"})
			if len(ovsports) != 1 {
				return
			}
			devices := g.LookupChildren(ovsports[0], graph.Metadata{"Type": "internal", "Driver": "openvswitch"})
			if len(devices) != 1 {
				return
			}

			if ovsbridge.Metadata()["Host"] == "" || ovsports[0].Metadata()["Host"] == "" || devices[0].Metadata()["Host"] == "" {
				return
			}

			testPassed = true

			ws.Close()
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test1"})
}
Пример #5
0
func TestBondOVS(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ovs-vsctl add-br br-test1", true},
		{"ip tuntap add mode tap dev intf1", true},
		{"ip tuntap add mode tap dev intf2", true},
		{"ovs-vsctl add-bond br-test1 bond0 intf1 intf2", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
		{"ip link del intf1", true},
		{"ip link del intf2", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 6 && len(g.GetEdges()) >= 5 {
			bond := g.LookupFirstNode(graph.Metadata{"Type": "ovsport", "Name": "bond0"})
			if bond != nil {
				intfs := g.LookupChildren(bond, nil)
				if len(intfs) != 2 {
					return
				}

				testPassed = true

				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test1", "intf1", "intf2"})
}
Пример #6
0
func TestDockerShareNamespace(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"docker run -d -t -i --name test-skydive-docker busybox", false},
		{"docker run -d -t -i --name test-skydive-docker2 --net=container:test-skydive-docker busybox", false},
	}

	tearDownCmds := []helper.Cmd{
		{"docker rm -f test-skydive-docker", false},
		{"docker rm -f test-skydive-docker2", false},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 1 && len(g.GetEdges()) >= 1 {
			nsNodes := g.LookupNodes(graph.Metadata{"Type": "netns", "Manager": "docker"})
			if len(nsNodes) > 1 {
				t.Error("There should be only one namespace managed by Docker")
				ws.Close()
			} else if len(nsNodes) == 1 {
				if node := g.LookupFirstChild(nsNodes[0], graph.Metadata{"Type": "container", "Docker.ContainerName": "/test-skydive-docker"}); node != nil {
					if node := g.LookupFirstChild(nsNodes[0], graph.Metadata{"Type": "container", "Docker.ContainerName": "/test-skydive-docker2"}); node != nil {
						testPassed = true
						ws.Close()
					}
				}
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"test-skydive-docker"})
}
Пример #7
0
func TestVeth(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip l add vm1-veth0 type veth peer name vm1-veth1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ip link del vm1-veth0", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 2 && len(g.GetEdges()) >= 1 {
			veth0 := g.LookupFirstNode(graph.Metadata{"Type": "veth", "Name": "vm1-veth0"})
			if veth0 == nil {
				return
			}
			veth1 := g.LookupFirstNode(graph.Metadata{"Type": "veth", "Name": "vm1-veth1"})
			if veth1 == nil {
				return
			}

			if g.AreLinked(veth0, veth1) {
				testPassed = true

				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"vm1-veth0", "vm1-veth1"})
}
Пример #8
0
func TestNameSpaceVeth(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip netns add ns1", true},
		{"ip l add vm1-veth0 type veth peer name vm1-veth1 netns ns1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ip link del vm1-veth0", true},
		{"ip netns del ns1", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 1 && len(g.GetEdges()) >= 1 {
			node := g.LookupFirstNode(graph.Metadata{"Name": "ns1", "Type": "netns"})
			if node == nil {
				return
			}

			veth := g.LookupFirstChild(node, graph.Metadata{"Name": "vm1-veth1", "Type": "veth"})
			if veth != nil {
				testPassed = true

				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"ns1", "vm1-veth0"})
}
Пример #9
0
func TestMacNameUpdate(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip l add vm1-veth0 type veth peer name vm1-veth1", true},
		{"ip l set vm1-veth1 name vm1-veth2", true},
		{"ip l set vm1-veth2 address 00:00:00:00:00:aa", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ip link del vm1-veth0", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 2 && len(g.GetEdges()) >= 1 {
			node := g.LookupFirstNode(graph.Metadata{"Name": "vm1-veth2"})
			if node == nil {
				return
			}
			if mac, ok := node.Metadata()["MAC"]; ok && mac == "00:00:00:00:00:aa" {
				if g.LookupFirstNode(graph.Metadata{"Name": "vm1-veth1"}) == nil {
					testPassed = true

					ws.Close()
				}
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"vm1-veth0", "vm1-veth1", "vm1-veth2"})
}
Пример #10
0
func TestBridge(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"brctl addbr br-test", true},
		{"ip tuntap add mode tap dev intf1", true},
		{"brctl addif br-test intf1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"brctl delbr br-test", true},
		{"ip link del intf1", true},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 2 && len(g.GetEdges()) >= 1 {
			bridge := g.LookupFirstNode(graph.Metadata{"Type": "bridge", "Name": "br-test"})
			if bridge != nil {
				nodes := g.LookupChildren(bridge, graph.Metadata{"Name": "intf1"})
				if len(nodes) == 1 {
					testPassed = true

					ws.Close()
				}
			}

		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test", "intf1"})
}
Пример #11
0
func TestDockerNetHost(t *testing.T) {
	g := newGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"docker run -d -t -i --net=host --name test-skydive-docker busybox", false},
	}

	tearDownCmds := []helper.Cmd{
		{"docker rm -f test-skydive-docker", false},
	}

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed && len(g.GetNodes()) >= 1 && len(g.GetEdges()) >= 1 {
			if node := g.LookupFirstNode(graph.Metadata{"Docker.ContainerName": "/test-skydive-docker", "Type": "container"}); node != nil {
				if node := g.LookupFirstNode(graph.Metadata{"Type": "netns", "Manager": "docker", "Name": "test-skydive-docker"}); node != nil {
					t.Error("There should be no netns node for container test-skydive-docker")
				} else {
					testPassed = true
				}
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"test-skydive-docker"})
}
Пример #12
0
func TestNeutron(t *testing.T) {
	g := newGraph(t)

	authUrl := os.Getenv("OS_AUTH_URL")
	username := os.Getenv("OS_USERNAME")
	password := os.Getenv("OS_PASSWORD")
	tenantName := os.Getenv("OS_TENANT_NAME")
	regionName := os.Getenv("OS_REGION_NAME")
	ovsdbPort := os.Getenv("SKYDIVE_OVSDB_REMOTE_PORT")

	params := map[string]interface{}{
		"OsAuthUrl":    authUrl,
		"OsUsername":   username,
		"OsPassword":   password,
		"OsTenantName": tenantName,
		"OsRegionName": regionName,
		"OvsdbPort":    ovsdbPort,
	}
	agent := helper.StartAgentWithConfig(t, confNeutron, params)
	defer agent.Stop()

	opts := gophercloud.AuthOptions{
		IdentityEndpoint: authUrl,
		Username:         username,
		Password:         password,
		TenantName:       tenantName,
	}

	provider, err := openstack.AuthenticatedClient(opts)
	if err != nil {
		t.Fatal(err.Error())
	}

	client, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
		Name:         "neutron",
		Region:       regionName,
		Availability: gophercloud.AvailabilityPublic,
	})
	if err != nil {
		t.Fatalf("Failed to create neutron client: %s", err.Error())
	}

	result := networks.Create(client, networks.CreateOpts{Name: "skydive-test-network"})
	if result.Err != nil {
		t.Fatalf("Failed to create neutron network: %s", result.Err.Error())
	}

	network, err := result.Extract()
	if err != nil {
		t.Fatalf("Failed to create neutron network: %s", err.Error())
	}

	defer networks.Delete(client, network.ID)

	setupCmds := []helper.Cmd{
		{fmt.Sprintf("neutron subnet-create --name skydive-test-subnet-%s %s 10.0.0.0/24", network.ID, network.ID), false},
		{fmt.Sprintf("neutron-debug probe-create %s", network.ID), false},
	}

	tearDownCmds := []helper.Cmd{
		{fmt.Sprintf("neutron subnet-delete skydive-test-subnet-%s", network.ID), false},
	}

	var port *ports.Port
	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if port == nil {
			portListOpts := ports.ListOpts{}
			pager := ports.List(client, portListOpts)
			err = pager.EachPage(func(page pagination.Page) (bool, error) {
				portList, err := ports.ExtractPorts(page)
				if err != nil {
					return false, err
				}

				for _, p := range portList {
					if p.DeviceOwner == "network:probe" && p.NetworkID == network.ID {
						port = &p
						return false, nil
					}
				}

				return true, nil
			})

			if port != nil {
				tearDownCmds = append(tearDownCmds, helper.Cmd{})
				copy(tearDownCmds[1:], tearDownCmds[0:])
				tearDownCmds[0] = helper.Cmd{fmt.Sprintf("neutron-debug probe-delete %s", port.ID), false}
			}
		}

		if !testPassed && len(g.GetNodes()) >= 1 && len(g.GetEdges()) >= 1 && port != nil {
			if g.LookupFirstNode(graph.Metadata{"Name": fmt.Sprintf("qdhcp-%s", network.ID), "Type": "netns"}) != nil {
				if g.LookupFirstNode(graph.Metadata{"Name": fmt.Sprintf("qprobe-%s", port.ID), "Type": "netns"}) != nil {
					if g.LookupFirstNode(graph.Metadata{"Type": "internal", "Driver": "openvswitch", "Manager": "neutron", "Neutron.NetworkID": network.ID}) != nil {
						testPassed = true
						ws.Close()
					}
				}
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{fmt.Sprintf("qdhcp-%s", network.ID), fmt.Sprintf("qprobe-%s", port.ID)})
}