예제 #1
0
func TestPipes(t *testing.T) {
	oldNewPipe := controls.NewPipe
	defer func() { controls.NewPipe = oldNewPipe }()
	controls.NewPipe = func(_ controls.PipeClient, _ string) (string, xfer.Pipe, error) {
		return "pipeid", mockPipe{}, nil
	}

	mdc := newMockClient()
	setupStubs(mdc, func() {
		registry, _ := docker.NewRegistry(10*time.Second, nil, false, "")
		defer registry.Stop()

		test.Poll(t, 100*time.Millisecond, true, func() interface{} {
			_, ok := registry.GetContainer("ping")
			return ok
		})

		for _, tc := range []string{
			docker.AttachContainer,
			docker.ExecContainer,
		} {
			result := controls.HandleControlRequest(xfer.Request{
				Control: tc,
				NodeID:  report.MakeContainerNodeID("ping"),
			})
			want := xfer.Response{
				Pipe:   "pipeid",
				RawTTY: true,
			}
			if !reflect.DeepEqual(result, want) {
				t.Errorf("diff %s: %s", tc, test.Diff(want, result))
			}
		}
	})
}
예제 #2
0
func TestReverseResolver(t *testing.T) {
	tests := map[string][]string{
		"1.2.3.4": {"test.domain.name"},
		"4.3.2.1": {"im.a.little.tea.pot"},
	}

	revRes := newReverseResolver()
	defer revRes.stop()

	// Use a mocked resolver function.
	revRes.Resolver = func(addr string) (names []string, err error) {
		if names, ok := tests[addr]; ok {
			return names, nil
		}
		return []string{}, errors.New("invalid IP")
	}

	// Up the rate limit so the test runs faster.
	revRes.Throttle = time.Tick(time.Millisecond)

	for ip, names := range tests {
		test.Poll(t, 100*time.Millisecond, names, func() interface{} {
			ns, _ := revRes.get(ip)
			return ns
		})
	}
}
예제 #3
0
func TestWeave(t *testing.T) {
	weaveClient := &mockWeaveClient{
		published: map[string]entry{},
	}
	dockerClient := mockDockerClient{}
	interfaces := func() ([]app.Interface, error) {
		return []app.Interface{
			{
				Name: "eth0",
				Addrs: []net.Addr{
					&net.IPAddr{
						IP: ip,
					},
				},
			},
			{
				Name: "docker0",
				Addrs: []net.Addr{
					&net.IPAddr{
						IP: net.ParseIP("4.3.2.1"),
					},
				},
			},
		}, nil
	}
	publisher := app.NewWeavePublisher(
		weaveClient, dockerClient, interfaces,
		hostname, containerName)
	defer publisher.Stop()

	want := map[string]entry{
		hostname: {containerID, ip},
	}
	test.Poll(t, 100*time.Millisecond, want, func() interface{} {
		weaveClient.Lock()
		defer weaveClient.Unlock()
		result := map[string]entry{}
		for k, v := range weaveClient.published {
			result[k] = v
		}
		return result
	})
}
예제 #4
0
func TestProbe(t *testing.T) {
	// marshalling->unmarshaling is not idempotent due to `json:"omitempty"`
	// tags, transforming empty slices into nils. So, we make DeepEqual
	// happy by setting empty `json:"omitempty"` entries to nil
	const probeID = "probeid"
	now := time.Now()
	mtime.NowForce(now)
	defer mtime.NowReset()

	want := report.MakeReport()
	node := report.MakeNodeWith("a", map[string]string{"b": "c"})
	node.Metrics = nil // omitempty
	// omitempty
	want.Endpoint.Controls = nil
	want.Process.Controls = nil
	want.Container.Controls = nil
	want.ContainerImage.Controls = nil
	want.Pod.Controls = nil
	want.Service.Controls = nil
	want.Deployment.Controls = nil
	want.ReplicaSet.Controls = nil
	want.Host.Controls = nil
	want.Overlay.Controls = nil
	want.Endpoint.AddNode(node)

	pub := mockPublisher{make(chan report.Report, 10)}

	p := New(10*time.Millisecond, 100*time.Millisecond, pub)
	p.AddReporter(mockReporter{want})
	p.Start()
	defer p.Stop()

	test.Poll(t, 300*time.Millisecond, want, func() interface{} {
		return <-pub.have
	})
}
예제 #5
0
func TestContainer(t *testing.T) {
	log.SetOutput(ioutil.Discard)

	oldDialStub, oldNewClientConnStub := docker.DialStub, docker.NewClientConnStub
	defer func() { docker.DialStub, docker.NewClientConnStub = oldDialStub, oldNewClientConnStub }()

	docker.DialStub = func(network, address string) (net.Conn, error) {
		return nil, nil
	}

	reader, writer := io.Pipe()
	connection := &mockConnection{reader}

	docker.NewClientConnStub = func(c net.Conn, r *bufio.Reader) docker.ClientConn {
		return connection
	}

	now := time.Unix(12345, 67890).UTC()
	mtime.NowForce(now)
	defer mtime.NowReset()

	const hostID = "scope"
	c := docker.NewContainer(container1, hostID)
	err := c.StartGatheringStats()
	if err != nil {
		t.Errorf("%v", err)
	}
	defer c.StopGatheringStats()

	// Send some stats to the docker container
	stats := &client.Stats{}
	stats.Read = now
	stats.MemoryStats.Usage = 12345
	stats.MemoryStats.Limit = 45678
	encoder := codec.NewEncoder(writer, &codec.JsonHandle{})
	if err = encoder.Encode(&stats); err != nil {
		t.Error(err)
	}

	// Now see if we go them
	{
		uptime := (now.Sub(startTime) / time.Second) * time.Second
		want := report.MakeNodeWith("ping;<container>", map[string]string{
			"docker_container_command":     " ",
			"docker_container_created":     "01 Jan 01 00:00 UTC",
			"docker_container_id":          "ping",
			"docker_container_name":        "pong",
			"docker_image_id":              "baz",
			"docker_label_foo1":            "bar1",
			"docker_label_foo2":            "bar2",
			"docker_container_state":       "running",
			"docker_container_state_human": "Up 6 years",
			"docker_container_uptime":      uptime.String(),
		}).
			WithControls(
				docker.RestartContainer, docker.StopContainer, docker.PauseContainer,
				docker.AttachContainer, docker.ExecContainer,
			).WithMetrics(report.Metrics{
			"docker_cpu_total_usage": report.MakeMetric(),
			"docker_memory_usage":    report.MakeMetric().Add(now, 12345).WithMax(45678),
		}).WithParents(report.EmptySets.
			Add(report.ContainerImage, report.MakeStringSet(report.MakeContainerImageNodeID("baz"))),
		)

		test.Poll(t, 100*time.Millisecond, want, func() interface{} {
			node := c.GetNode()
			node.Latest.ForEach(func(k, v string) {
				if v == "0" || v == "" {
					node.Latest = node.Latest.Delete(k)
				}
			})
			return node
		})
	}

	{
		want := report.EmptySets.
			Add("docker_container_ports", report.MakeStringSet("1.2.3.4:80->80/tcp", "81/tcp")).
			Add("docker_container_ips", report.MakeStringSet("1.2.3.4")).
			Add("docker_container_ips_with_scopes", report.MakeStringSet(";1.2.3.4"))

		test.Poll(t, 100*time.Millisecond, want, func() interface{} {
			return c.NetworkInfo([]net.IP{})
		})
	}

	if c.Image() != "baz" {
		t.Errorf("%s != baz", c.Image())
	}
	if c.PID() != 2 {
		t.Errorf("%d != 2", c.PID())
	}
	node := c.GetNode().WithSets(c.NetworkInfo([]net.IP{}))
	if have := docker.ExtractContainerIPs(node); !reflect.DeepEqual(have, []string{"1.2.3.4"}) {
		t.Errorf("%v != %v", have, []string{"1.2.3.4"})
	}
}
예제 #6
0
func TestConntracker(t *testing.T) {
	oldExecCmd, oldConntrackPresent := exec.Command, ConntrackModulePresent
	defer func() { exec.Command, ConntrackModulePresent = oldExecCmd, oldConntrackPresent }()

	ConntrackModulePresent = func() bool {
		return true
	}

	first := true
	existingConnectionsReader, existingConnectionsWriter := io.Pipe()
	reader, writer := io.Pipe()
	exec.Command = func(name string, args ...string) exec.Cmd {
		if first {
			first = false
			return testexec.NewMockCmd(existingConnectionsReader)
		}
		return testexec.NewMockCmd(reader)
	}

	flowWalker := newConntrackFlowWalker(true)
	defer flowWalker.stop()

	// First write out some empty xml for the existing connections
	ecbw := bufio.NewWriter(existingConnectionsWriter)
	if _, err := ecbw.WriteString(xmlHeader); err != nil {
		t.Fatal(err)
	}
	if _, err := ecbw.WriteString(conntrackOpenTag); err != nil {
		t.Fatal(err)
	}
	if _, err := ecbw.WriteString(conntrackCloseTag); err != nil {
		t.Fatal(err)
	}
	if err := ecbw.Flush(); err != nil {
		t.Fatal(err)
	}

	// Then write out eventa
	bw := bufio.NewWriter(writer)
	if _, err := bw.WriteString(xmlHeader); err != nil {
		t.Fatal(err)
	}
	if _, err := bw.WriteString(conntrackOpenTag); err != nil {
		t.Fatal(err)
	}
	if err := bw.Flush(); err != nil {
		t.Fatal(err)
	}

	have := func() interface{} {
		result := []flow{}
		flowWalker.walkFlows(func(f flow) {
			f.Original = nil
			f.Reply = nil
			f.Independent = nil
			result = append(result, f)
		})
		return result
	}
	ts := 100 * time.Millisecond

	// First, assert we have no flows
	test.Poll(t, ts, []flow{}, have)

	// Now add some flows
	xmlEncoder := xml.NewEncoder(bw)
	writeFlow := func(f flow) {
		if err := xmlEncoder.Encode(f); err != nil {
			t.Fatal(err)
		}
		if _, err := bw.WriteString("\n"); err != nil {
			t.Fatal(err)
		}
		if err := bw.Flush(); err != nil {
			t.Fatal(err)
		}
	}

	flow1 := makeFlow(updateType)
	addMeta(&flow1, "original", "1.2.3.4", "2.3.4.5", 2, 3)
	addIndependant(&flow1, 1, "")
	writeFlow(flow1)
	test.Poll(t, ts, []flow{flow1}, have)

	// Now check when we remove the flow, we still get it in the next Walk
	flow2 := makeFlow(destroyType)
	addMeta(&flow2, "original", "1.2.3.4", "2.3.4.5", 2, 3)
	addIndependant(&flow2, 1, "")
	writeFlow(flow2)
	test.Poll(t, ts, []flow{flow1}, have)
	test.Poll(t, ts, []flow{}, have)

	// This time we're not going to remove it, but put it in state TIME_WAIT
	flow1.Type = updateType
	writeFlow(flow1)
	test.Poll(t, ts, []flow{flow1}, have)

	flow1.Metas[1].State = timeWait
	writeFlow(flow1)
	test.Poll(t, ts, []flow{flow1}, have)
	test.Poll(t, ts, []flow{}, have)
}
예제 #7
0
func TestWeaveTaggerOverlayTopology(t *testing.T) {
	w := overlay.NewWeave(mockHostID, weave.MockClient{})
	defer w.Stop()

	// Wait until the reporter reports some nodes
	test.Poll(t, 300*time.Millisecond, 1, func() interface{} {
		have, _ := w.Report()
		return len(have.Overlay.Nodes)
	})

	{
		// Overlay node should include peer name and nickname
		have, err := w.Report()
		if err != nil {
			t.Fatal(err)
		}

		nodeID := report.MakeOverlayNodeID(weave.MockWeavePeerName)
		node, ok := have.Overlay.Nodes[nodeID]
		if !ok {
			t.Errorf("Expected overlay node %q, but not found", nodeID)
		}
		if peerName, ok := node.Latest.Lookup(overlay.WeavePeerName); !ok || peerName != weave.MockWeavePeerName {
			t.Errorf("Expected weave peer name %q, got %q", weave.MockWeavePeerName, peerName)
		}
		if peerNick, ok := node.Latest.Lookup(overlay.WeavePeerNickName); !ok || peerNick != weave.MockWeavePeerNickName {
			t.Errorf("Expected weave peer nickname %q, got %q", weave.MockWeavePeerNickName, peerNick)
		}
		if localNetworks, ok := node.Sets.Lookup(host.LocalNetworks); !ok || !reflect.DeepEqual(localNetworks, report.MakeStringSet(weave.MockWeaveDefaultSubnet)) {
			t.Errorf("Expected weave node local_networks %q, got %q", report.MakeStringSet(weave.MockWeaveDefaultSubnet), localNetworks)
		}
	}

	{
		// Container nodes should be tagged with their overlay info
		nodeID := report.MakeContainerNodeID(weave.MockContainerID)
		have, err := w.Tag(report.Report{
			Container: report.MakeTopology().AddNode(report.MakeNodeWith(nodeID, map[string]string{
				docker.ContainerID: weave.MockContainerID,
			})),
		})
		if err != nil {
			t.Fatal(err)
		}

		node, ok := have.Container.Nodes[nodeID]
		if !ok {
			t.Errorf("Expected container node %q, but not found", nodeID)
		}

		// Should have Weave DNS Hostname
		if have, ok := node.Latest.Lookup(overlay.WeaveDNSHostname); !ok || have != weave.MockHostname {
			t.Errorf("Expected weave dns hostname %q, got %q", weave.MockHostname, have)
		}
		// Should have Weave MAC Address
		if have, ok := node.Latest.Lookup(overlay.WeaveMACAddress); !ok || have != weave.MockContainerMAC {
			t.Errorf("Expected weave mac address %q, got %q", weave.MockContainerMAC, have)
		}
		// Should have Weave container ip
		if have, ok := node.Sets.Lookup(docker.ContainerIPs); !ok || !have.Contains(weave.MockContainerIP) {
			t.Errorf("Expected container ips to include the weave IP %q, got %q", weave.MockContainerIP, have)
		}
		// Should have Weave container ip (with scope)
		if have, ok := node.Sets.Lookup(docker.ContainerIPsWithScopes); !ok || !have.Contains(mockContainerIPWithScope) {
			t.Errorf("Expected container ips to include the weave IP (with scope) %q, got %q", mockContainerIPWithScope, have)
		}
	}
}
예제 #8
0
func TestPipeClose(t *testing.T) {
	router := mux.NewRouter()
	pr := NewLocalPipeRouter()
	RegisterPipeRoutes(router, pr)
	defer pr.Stop()

	server := httptest.NewServer(router)
	defer server.Close()

	ip, port, err := net.SplitHostPort(strings.TrimPrefix(server.URL, "http://"))
	if err != nil {
		t.Fatal(err)
	}

	probeConfig := appclient.ProbeConfig{
		ProbeID: "foo",
	}
	client, err := appclient.NewAppClient(probeConfig, ip+":"+port, ip+":"+port, nil)
	if err != nil {
		t.Fatal(err)
	}
	defer client.Stop()

	// this is the probe end of the pipe
	pipeID, pipe, err := controls.NewPipe(adapter{client}, "appid")
	if err != nil {
		t.Fatal(err)
	}

	// this is a client to the app
	pipeURL := fmt.Sprintf("ws://%s:%s/api/pipe/%s", ip, port, pipeID)
	conn, _, err := websocket.DefaultDialer.Dial(pipeURL, http.Header{})
	if err != nil {
		t.Fatal(err)
	}

	// Send something from pipe -> app -> conn
	local, _ := pipe.Ends()
	msg := []byte("hello world")
	if _, err := local.Write(msg); err != nil {
		t.Fatal(err)
	}

	if _, buf, err := conn.ReadMessage(); err != nil {
		t.Fatal(err)
	} else if !bytes.Equal(buf, msg) {
		t.Fatalf("%v != %v", buf, msg)
	}

	// Send something from conn -> app -> probe
	msg = []byte("goodbye, cruel world")
	if err := conn.WriteMessage(websocket.BinaryMessage, msg); err != nil {
		t.Fatal(err)
	}

	buf := make([]byte, 1024)
	if n, err := local.Read(buf); err != nil {
		t.Fatal(err)
	} else if !bytes.Equal(msg, buf[:n]) {
		t.Fatalf("%v != %v", buf, msg)
	}

	// Now delete the pipe
	if err := pipe.Close(); err != nil {
		t.Fatal(err)
	}

	// the client backs off for 1 second before trying to reconnect the pipe,
	// so we need to wait for longer.
	test.Poll(t, 2*time.Second, true, func() interface{} {
		return pipe.Closed()
	})
}