Beispiel #1
0
func TestControl(t *testing.T) {
	router := mux.NewRouter()
	registerControlRoutes(router)
	server := httptest.NewServer(router)
	defer server.Close()

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

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

	client.ControlConnection(xfer.ControlHandlerFunc(func(req xfer.Request) xfer.Response {
		if req.NodeID != "nodeid" {
			t.Fatalf("'%s' != 'nodeid'", req.NodeID)
		}

		if req.Control != "control" {
			t.Fatalf("'%s' != 'control'", req.Control)
		}

		return xfer.Response{
			Value: "foo",
		}
	}))

	time.Sleep(100 * time.Millisecond)

	httpClient := http.Client{
		Timeout: 1 * time.Second,
	}
	resp, err := httpClient.Post(server.URL+"/api/control/foo/nodeid/control", "", nil)
	if err != nil {
		t.Fatal(err)
	}

	var response string
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		t.Fatal(err)
	}

	if response != "foo" {
		t.Fatalf("'%s' != 'foo'", response)
	}
}
Beispiel #2
0
func TestMultiClient(t *testing.T) {
	var (
		a1      = &mockClient{id: "1"} // hostname a, app id 1
		a2      = &mockClient{id: "2"} // hostname a, app id 2
		b2      = &mockClient{id: "2"} // hostname b, app id 2 (duplicate)
		b3      = &mockClient{id: "3"} // hostname b, app id 3
		factory = func(_ xfer.ProbeConfig, hostname, target string) (xfer.AppClient, error) {
			switch target {
			case "a1":
				return a1, nil
			case "a2":
				return a2, nil
			case "b2":
				return b2, nil
			case "b3":
				return b3, nil
			}
			t.Fatal(target)
			return a1, nil
		}
		controlHandler = xfer.ControlHandlerFunc(func(_ xfer.Request) xfer.Response {
			return xfer.Response{}
		})
		expect = func(i, j int) {
			if i != j {
				_, file, line, _ := runtime.Caller(1)
				t.Fatalf("%s:%d: %d != %d", file, line, i, j)
			}
		}
	)

	mp := xfer.NewMultiAppClient(xfer.ProbeConfig{}, controlHandler, factory)
	defer mp.Stop()

	// Add two hostnames with overlapping apps, check we don't add the same app twice
	mp.Set("a", []string{"a1", "a2"})
	mp.Set("b", []string{"b2", "b3"})
	expect(a1.count, 1)
	expect(a2.count+b2.count, 1)
	expect(b3.count, 1)

	// Now drop the overlap, check we don't remove the app
	mp.Set("b", []string{"b3"})
	expect(a1.count, 1)
	expect(a2.count+b2.count, 1)
	expect(b3.count, 1)

	// Now check we remove apps
	mp.Set("b", []string{})
	expect(b3.stopped, 1)
}
Beispiel #3
0
func main() {
	var (
		targets            = []string{fmt.Sprintf("localhost:%d", xfer.AppPort), fmt.Sprintf("scope.weave.local:%d", xfer.AppPort)}
		token              = flag.String("token", "default-token", "probe token")
		httpListen         = flag.String("http.listen", "", "listen address for HTTP profiling and instrumentation server")
		publishInterval    = flag.Duration("publish.interval", 3*time.Second, "publish (output) interval")
		spyInterval        = flag.Duration("spy.interval", time.Second, "spy (scan) interval")
		spyProcs           = flag.Bool("processes", true, "report processes (needs root)")
		dockerEnabled      = flag.Bool("docker", false, "collect Docker-related attributes for processes")
		dockerInterval     = flag.Duration("docker.interval", 10*time.Second, "how often to update Docker attributes")
		dockerBridge       = flag.String("docker.bridge", "docker0", "the docker bridge name")
		kubernetesEnabled  = flag.Bool("kubernetes", false, "collect kubernetes-related attributes for containers, should only be enabled on the master node")
		kubernetesAPI      = flag.String("kubernetes.api", "http://localhost:8080", "Address of kubernetes master api")
		kubernetesInterval = flag.Duration("kubernetes.interval", 10*time.Second, "how often to do a full resync of the kubernetes data")
		weaveRouterAddr    = flag.String("weave.router.addr", "", "IP address or FQDN of the Weave router")
		procRoot           = flag.String("proc.root", "/proc", "location of the proc filesystem")
		printVersion       = flag.Bool("version", false, "print version number and exit")
		useConntrack       = flag.Bool("conntrack", true, "also use conntrack to track connections")
		insecure           = flag.Bool("insecure", false, "(SSL) explicitly allow \"insecure\" SSL connections and transfers")
		logPrefix          = flag.String("log.prefix", "<probe>", "prefix for each log line")
	)
	flag.Parse()

	if *printVersion {
		fmt.Println(version)
		return
	}

	// Setup in memory metrics sink
	inm := metrics.NewInmemSink(time.Minute, 2*time.Minute)
	sig := metrics.DefaultInmemSignal(inm)
	defer sig.Stop()
	metrics.NewGlobal(metrics.DefaultConfig("scope-probe"), inm)

	if !strings.HasSuffix(*logPrefix, " ") {
		*logPrefix += " "
	}
	log.SetPrefix(*logPrefix)

	defer log.Print("probe exiting")

	if *spyProcs && os.Getegid() != 0 {
		log.Printf("warning: -process=true, but that requires root to find everything")
	}

	rand.Seed(time.Now().UnixNano())
	probeID := strconv.FormatInt(rand.Int63(), 16)
	var (
		hostName = probe.Hostname()
		hostID   = hostName // TODO(pb): we should sanitize the hostname
	)
	log.Printf("probe starting, version %s, ID %s", version, probeID)

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		log.Fatal(err)
	}
	localNets := report.Networks{}
	for _, addr := range addrs {
		// Not all addrs are IPNets.
		if ipNet, ok := addr.(*net.IPNet); ok {
			localNets = append(localNets, ipNet)
		}
	}

	if len(flag.Args()) > 0 {
		targets = flag.Args()
	}
	log.Printf("publishing to: %s", strings.Join(targets, ", "))

	factory := func(hostname, endpoint string) (string, xfer.Publisher, error) {
		id, publisher, err := xfer.NewHTTPPublisher(hostname, endpoint, *token, probeID, *insecure)
		if err != nil {
			return "", nil, err
		}
		return id, xfer.NewBackgroundPublisher(publisher), nil
	}

	publishers := xfer.NewMultiPublisher(factory)
	defer publishers.Stop()

	clients := xfer.NewMultiAppClient(xfer.ProbeConfig{
		Token:    *token,
		ProbeID:  probeID,
		Insecure: *insecure,
	}, xfer.ControlHandlerFunc(controls.HandleControlRequest), xfer.NewAppClient)
	defer clients.Stop()

	resolver := xfer.NewStaticResolver(targets, publishers.Set, clients.Set)
	defer resolver.Stop()

	endpointReporter := endpoint.NewReporter(hostID, hostName, *spyProcs, *useConntrack)
	defer endpointReporter.Stop()

	processCache := process.NewCachingWalker(process.NewWalker(*procRoot))
	p := probe.New(*spyInterval, *publishInterval, publishers)
	p.AddTicker(processCache)
	p.AddReporter(
		endpointReporter,
		host.NewReporter(hostID, hostName, localNets),
		process.NewReporter(processCache, hostID),
	)
	p.AddTagger(probe.NewTopologyTagger(), host.NewTagger(hostID, probeID))

	if *dockerEnabled {
		if err := report.AddLocalBridge(*dockerBridge); err != nil {
			log.Printf("Docker: problem with bridge %s: %v", *dockerBridge, err)
		}
		if registry, err := docker.NewRegistry(*dockerInterval); err == nil {
			defer registry.Stop()
			p.AddTagger(docker.NewTagger(registry, processCache))
			p.AddReporter(docker.NewReporter(registry, hostID, p))
		} else {
			log.Printf("Docker: failed to start registry: %v", err)
		}
	}

	if *kubernetesEnabled {
		if client, err := kubernetes.NewClient(*kubernetesAPI, *kubernetesInterval); err == nil {
			defer client.Stop()
			p.AddReporter(kubernetes.NewReporter(client))
		} else {
			log.Printf("Kubernetes: failed to start client: %v", err)
		}
	}

	if *weaveRouterAddr != "" {
		weave := overlay.NewWeave(hostID, *weaveRouterAddr)
		defer weave.Stop()
		p.AddTicker(weave)
		p.AddTagger(weave)
		p.AddReporter(weave)
	}

	if *httpListen != "" {
		go func() {
			log.Printf("Profiling data being exported to %s", *httpListen)
			log.Printf("go tool pprof http://%s/debug/pprof/{profile,heap,block}", *httpListen)
			log.Printf("Profiling endpoint %s terminated: %v", *httpListen, http.ListenAndServe(*httpListen, nil))
		}()
	}

	p.Start()
	defer p.Stop()

	log.Printf("%s", <-interrupt())
}
Beispiel #4
0
func main() {
	var (
		targets            = []string{fmt.Sprintf("localhost:%d", xfer.AppPort), fmt.Sprintf("scope.weave.local:%d", xfer.AppPort)}
		token              = flag.String("token", "default-token", "probe token")
		httpListen         = flag.String("http.listen", "", "listen address for HTTP profiling and instrumentation server")
		publishInterval    = flag.Duration("publish.interval", 3*time.Second, "publish (output) interval")
		spyInterval        = flag.Duration("spy.interval", time.Second, "spy (scan) interval")
		prometheusEndpoint = flag.String("prometheus.endpoint", "/metrics", "Prometheus metrics exposition endpoint (requires -http.listen)")
		spyProcs           = flag.Bool("processes", true, "report processes (needs root)")
		dockerEnabled      = flag.Bool("docker", false, "collect Docker-related attributes for processes")
		dockerInterval     = flag.Duration("docker.interval", 10*time.Second, "how often to update Docker attributes")
		dockerBridge       = flag.String("docker.bridge", "docker0", "the docker bridge name")
		kubernetesEnabled  = flag.Bool("kubernetes", false, "collect kubernetes-related attributes for containers, should only be enabled on the master node")
		kubernetesAPI      = flag.String("kubernetes.api", "http://localhost:8080", "Address of kubernetes master api")
		kubernetesInterval = flag.Duration("kubernetes.interval", 10*time.Second, "how often to do a full resync of the kubernetes data")
		weaveRouterAddr    = flag.String("weave.router.addr", "", "IP address or FQDN of the Weave router")
		procRoot           = flag.String("proc.root", "/proc", "location of the proc filesystem")
		printVersion       = flag.Bool("version", false, "print version number and exit")
		useConntrack       = flag.Bool("conntrack", true, "also use conntrack to track connections")
		insecure           = flag.Bool("insecure", false, "(SSL) explicitly allow \"insecure\" SSL connections and transfers")
		logPrefix          = flag.String("log.prefix", "<probe>", "prefix for each log line")
	)
	flag.Parse()

	if *printVersion {
		fmt.Println(version)
		return
	}

	if !strings.HasSuffix(*logPrefix, " ") {
		*logPrefix += " "
	}
	log.SetPrefix(*logPrefix)

	defer log.Print("probe exiting")

	if *spyProcs && os.Getegid() != 0 {
		log.Printf("warning: -process=true, but that requires root to find everything")
	}

	rand.Seed(time.Now().UnixNano())
	probeID := strconv.FormatInt(rand.Int63(), 16)
	var (
		hostName = hostname()
		hostID   = hostName // TODO(pb): we should sanitize the hostname
	)
	log.Printf("probe starting, version %s, ID %s", version, probeID)

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		log.Fatal(err)
	}
	localNets := report.Networks{}
	for _, addr := range addrs {
		// Not all addrs are IPNets.
		if ipNet, ok := addr.(*net.IPNet); ok {
			localNets = append(localNets, ipNet)
		}
	}

	if len(flag.Args()) > 0 {
		targets = flag.Args()
	}
	log.Printf("publishing to: %s", strings.Join(targets, ", "))

	factory := func(hostname, endpoint string) (string, xfer.Publisher, error) {
		id, publisher, err := xfer.NewHTTPPublisher(hostname, endpoint, *token, probeID, *insecure)
		if err != nil {
			return "", nil, err
		}
		return id, xfer.NewBackgroundPublisher(publisher), nil
	}

	publishers := xfer.NewMultiPublisher(factory)
	defer publishers.Stop()

	clients := xfer.NewMultiAppClient(xfer.ProbeConfig{
		Token:    *token,
		ProbeID:  probeID,
		Insecure: *insecure,
	}, xfer.ControlHandlerFunc(controls.HandleControlRequest), xfer.NewAppClient)
	defer clients.Stop()

	resolver := newStaticResolver(targets, publishers.Set, clients.Set)
	defer resolver.Stop()

	endpointReporter := endpoint.NewReporter(hostID, hostName, *spyProcs, *useConntrack)
	defer endpointReporter.Stop()

	processCache := process.NewCachingWalker(process.NewWalker(*procRoot))

	var (
		tickers   = []Ticker{processCache}
		reporters = []Reporter{endpointReporter, host.NewReporter(hostID, hostName, localNets), process.NewReporter(processCache, hostID)}
		taggers   = []Tagger{newTopologyTagger(), host.NewTagger(hostID, probeID)}
	)

	dockerTagger, dockerReporter, dockerRegistry := func() (*docker.Tagger, *docker.Reporter, docker.Registry) {
		if !*dockerEnabled {
			return nil, nil, nil
		}
		if err := report.AddLocalBridge(*dockerBridge); err != nil {
			log.Printf("Docker: problem with bridge %s: %v", *dockerBridge, err)
			return nil, nil, nil
		}
		registry, err := docker.NewRegistry(*dockerInterval)
		if err != nil {
			log.Printf("Docker: failed to start registry: %v", err)
			return nil, nil, nil
		}
		return docker.NewTagger(registry, processCache), docker.NewReporter(registry, hostID), registry
	}()
	if dockerTagger != nil {
		taggers = append(taggers, dockerTagger)
	}
	if dockerReporter != nil {
		reporters = append(reporters, dockerReporter)
	}
	if dockerRegistry != nil {
		defer dockerRegistry.Stop()
	}

	if *kubernetesEnabled {
		if client, err := kubernetes.NewClient(*kubernetesAPI, *kubernetesInterval); err == nil {
			defer client.Stop()
			reporters = append(reporters, kubernetes.NewReporter(client))
		} else {
			log.Printf("Kubernetes: failed to start client: %v", err)
		}
	}

	if *weaveRouterAddr != "" {
		weave := overlay.NewWeave(hostID, *weaveRouterAddr)
		tickers = append(tickers, weave)
		taggers = append(taggers, weave)
		reporters = append(reporters, weave)
	}

	if *httpListen != "" {
		go func() {
			log.Printf("Profiling data being exported to %s", *httpListen)
			log.Printf("go tool pprof http://%s/debug/pprof/{profile,heap,block}", *httpListen)
			if *prometheusEndpoint != "" {
				log.Printf("exposing Prometheus endpoint at %s%s", *httpListen, *prometheusEndpoint)
				http.Handle(*prometheusEndpoint, makePrometheusHandler())
			}
			log.Printf("Profiling endpoint %s terminated: %v", *httpListen, http.ListenAndServe(*httpListen, nil))
		}()
	}

	quit, done := make(chan struct{}), sync.WaitGroup{}
	done.Add(2)
	defer func() { done.Wait() }() // second, wait for the main loops to be killed
	defer close(quit)              // first, kill the main loops

	var rpt syncReport
	rpt.swap(report.MakeReport())

	go func() {
		defer done.Done()
		spyTick := time.Tick(*spyInterval)

		for {
			select {
			case <-spyTick:
				start := time.Now()
				for _, ticker := range tickers {
					if err := ticker.Tick(); err != nil {
						log.Printf("error doing ticker: %v", err)
					}
				}

				localReport := rpt.copy()
				localReport = localReport.Merge(doReport(reporters))
				localReport = Apply(localReport, taggers)
				rpt.swap(localReport)

				if took := time.Since(start); took > *spyInterval {
					log.Printf("report generation took too long (%s)", took)
				}

			case <-quit:
				return
			}
		}
	}()

	go func() {
		defer done.Done()
		var (
			pubTick = time.Tick(*publishInterval)
			p       = xfer.NewReportPublisher(publishers)
		)

		for {
			select {
			case <-pubTick:
				publishTicks.WithLabelValues().Add(1)
				localReport := rpt.swap(report.MakeReport())
				localReport.Window = *publishInterval
				if err := p.Publish(localReport); err != nil {
					log.Printf("publish: %v", err)
				}

			case <-quit:
				return
			}
		}
	}()

	log.Printf("%s", <-interrupt())
}