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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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"}) }
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)}) }