func main() { var ( publish = flag.String("publish", fmt.Sprintf("localhost:%d", xfer.AppPort), "publish target") publishInterval = flag.Duration("publish.interval", 1*time.Second, "publish (output) interval") ) flag.Parse() if len(flag.Args()) != 1 { log.Fatal("usage: fixprobe [--args] report.json") } f, err := os.Open(flag.Arg(0)) if err != nil { log.Fatal(err) } var fixedReport report.Report if err := json.NewDecoder(f).Decode(&fixedReport); err != nil { log.Fatal(err) } f.Close() client, err := appclient.NewAppClient(appclient.ProbeConfig{ Token: "fixprobe", ProbeID: "fixprobe", Insecure: false, }, *publish, *publish, nil) if err != nil { log.Fatal(err) } rp := appclient.NewReportPublisher(client) for range time.Tick(*publishInterval) { rp.Publish(fixedReport) } }
func main() { var ( publish = flag.String("publish", fmt.Sprintf("localhost:%d", xfer.AppPort), "publish target") publishInterval = flag.Duration("publish.interval", 1*time.Second, "publish (output) interval") hostCount = flag.Int("hostcount", 10, "Number of demo hosts to generate") ) flag.Parse() client, err := appclient.NewAppClient(appclient.ProbeConfig{ Token: "demoprobe", ProbeID: "demoprobe", Insecure: false, }, *publish, *publish, nil) if err != nil { log.Fatal(err) } rp := appclient.NewReportPublisher(client) rand.Seed(time.Now().UnixNano()) for range time.Tick(*publishInterval) { if err := rp.Publish(demoReport(*hostCount)); err != nil { log.Print(err) } } }
func TestControl(t *testing.T) { router := mux.NewRouter() app.RegisterControlRoutes(router, app.NewLocalControlRouter()) 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", } controlHandler := 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", } }) client, err := appclient.NewAppClient(probeConfig, ip+":"+port, ip+":"+port, controlHandler) if err != nil { t.Fatal(err) } client.ControlConnection() defer client.Stop() 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) } defer resp.Body.Close() var response xfer.Response decoder := codec.NewDecoder(resp.Body, &codec.JsonHandle{}) if err := decoder.Decode(&response); err != nil { t.Fatal(err) } if response.Value != "foo" { t.Fatalf("'%s' != 'foo'", response.Value) } }
func main() { var ( publish = flag.String("publish", fmt.Sprintf("localhost:%d", xfer.AppPort), "publish target") publishInterval = flag.Duration("publish.interval", 1*time.Second, "publish (output) interval") publishToken = flag.String("publish.token", "fixprobe", "publish token, for if we are talking to the service") publishID = flag.String("publish.id", "fixprobe", "publisher ID used to identify publishers") useFixture = flag.Bool("fixture", false, "Use the embedded fixture report.") ) flag.Parse() if len(flag.Args()) != 1 && !*useFixture { log.Fatal("usage: fixprobe [--args] report.json") } var fixedReport report.Report if *useFixture { fixedReport = fixture.Report } else { b, err := ioutil.ReadFile(flag.Arg(0)) if err != nil { log.Fatal(err) } decoder := codec.NewDecoderBytes(b, &codec.JsonHandle{}) if err := decoder.Decode(&fixedReport); err != nil { log.Fatal(err) } } client, err := appclient.NewAppClient(appclient.ProbeConfig{ Token: *publishToken, ProbeID: *publishID, Insecure: false, }, *publish, *publish, nil) if err != nil { log.Fatal(err) } rp := appclient.NewReportPublisher(client) for range time.Tick(*publishInterval) { rp.Publish(fixedReport) } }
// Main runs the probe func probeMain() { var ( targets = []string{fmt.Sprintf("localhost:%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)") procRoot = flag.String("proc.root", "/proc", "location of the proc filesystem") 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") logLevel = flag.String("log.level", "info", "logging threshold level: debug|info|warn|error|fatal|panic") 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", "", "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", "127.0.0.1:6784", "IP address & port of the Weave router") weaveDNSTarget = flag.String("weave.hostname", fmt.Sprintf("scope.weave.local:%d", xfer.AppPort), "Hostname to lookup in weaveDNS") ) flag.Parse() setLogLevel(*logLevel) setLogFormatter(*logPrefix) // 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) defer log.Info("probe exiting") if *spyProcs && os.Getegid() != 0 { log.Warn("-process=true, but that requires root to find everything") } rand.Seed(time.Now().UnixNano()) probeID := strconv.FormatInt(rand.Int63(), 16) var ( hostName = hostname.Get() hostID = hostName // TODO(pb): we should sanitize the hostname ) log.Infof("probe starting, version %s, ID %s", version, probeID) go check() if len(flag.Args()) > 0 { targets = flag.Args() } log.Infof("publishing to: %s", strings.Join(targets, ", ")) probeConfig := appclient.ProbeConfig{ Token: *token, ProbeID: probeID, Insecure: *insecure, } clients := appclient.NewMultiAppClient(func(hostname, endpoint string) (appclient.AppClient, error) { return appclient.NewAppClient( probeConfig, hostname, endpoint, xfer.ControlHandlerFunc(controls.HandleControlRequest), ) }) defer clients.Stop() resolver := appclient.NewResolver(targets, net.LookupIP, clients.Set) defer resolver.Stop() processCache := process.NewCachingWalker(process.NewWalker(*procRoot)) scanner := procspy.NewConnectionScanner(processCache) endpointReporter := endpoint.NewReporter(hostID, hostName, *spyProcs, *useConntrack, scanner) defer endpointReporter.Stop() p := probe.New(*spyInterval, *publishInterval, clients) p.AddTicker(processCache) p.AddReporter( endpointReporter, host.NewReporter(hostID, hostName), process.NewReporter(processCache, hostID, process.GetDeltaTotalJiffies), ) p.AddTagger(probe.NewTopologyTagger(), host.NewTagger(hostID, probeID)) if *dockerEnabled { if err := report.AddLocalBridge(*dockerBridge); err != nil { log.Errorf("Docker: problem with bridge %s: %v", *dockerBridge, err) } if registry, err := docker.NewRegistry(*dockerInterval, clients); err == nil { defer registry.Stop() p.AddTagger(docker.NewTagger(registry, processCache)) p.AddReporter(docker.NewReporter(registry, hostID, p)) } else { log.Errorf("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.Errorf("Kubernetes: failed to start client: %v", err) log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide a valid kubernetes.api url") } } if *weaveRouterAddr != "" { client := weave.NewClient(sanitize.URL("http://", 6784, "")(*weaveRouterAddr)) weave := overlay.NewWeave(hostID, client) defer weave.Stop() p.AddTagger(weave) p.AddReporter(weave) dockerBridgeIP, err := getFirstAddressOf(*dockerBridge) if err != nil { log.Println("Error getting docker bridge ip:", err) } else { weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53") weaveResolver := appclient.NewResolver([]string{*weaveDNSTarget}, weaveDNSLookup, clients.Set) defer weaveResolver.Stop() } } if *httpListen != "" { go func() { log.Infof("Profiling data being exported to %s", *httpListen) log.Infof("go tool pprof http://%s/debug/pprof/{profile,heap,block}", *httpListen) log.Infof("Profiling endpoint %s terminated: %v", *httpListen, http.ListenAndServe(*httpListen, nil)) }() } p.Start() defer p.Stop() common.SignalHandlerLoop() }
func TestPipeClose(t *testing.T) { router := mux.NewRouter() pr := RegisterPipeRoutes(router) 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() }) }
// Main runs the probe func probeMain(flags probeFlags) { setLogLevel(flags.logLevel) setLogFormatter(flags.logPrefix) // 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) defer log.Info("probe exiting") if flags.spyProcs && os.Getegid() != 0 { log.Warn("--probe.process=true, but that requires root to find everything") } rand.Seed(time.Now().UnixNano()) var ( probeID = strconv.FormatInt(rand.Int63(), 16) hostName = hostname.Get() hostID = hostName // TODO(pb): we should sanitize the hostname ) log.Infof("probe starting, version %s, ID %s", version, probeID) log.Infof("command line: %v", os.Args) checkpointFlags := map[string]string{} if flags.kubernetesEnabled { checkpointFlags["kubernetes_enabled"] = "true" } go check(checkpointFlags) var targets = []string{} if flags.token != "" { // service mode if len(flag.Args()) == 0 { targets = append(targets, defaultServiceHost) } } else if !flags.noApp { targets = append(targets, fmt.Sprintf("localhost:%d", xfer.AppPort)) } targets = append(targets, flag.Args()...) log.Infof("publishing to: %s", strings.Join(targets, ", ")) probeConfig := appclient.ProbeConfig{ Token: flags.token, ProbeVersion: version, ProbeID: probeID, Insecure: flags.insecure, } clients := appclient.NewMultiAppClient(func(hostname, endpoint string) (appclient.AppClient, error) { return appclient.NewAppClient( probeConfig, hostname, endpoint, xfer.ControlHandlerFunc(controls.HandleControlRequest), ) }) defer clients.Stop() dnsLookupFn := net.LookupIP if flags.resolver != "" { dnsLookupFn = appclient.LookupUsing(flags.resolver) } resolver := appclient.NewResolver(targets, dnsLookupFn, clients.Set) defer resolver.Stop() p := probe.New(flags.spyInterval, flags.publishInterval, clients) hostReporter := host.NewReporter(hostID, hostName, probeID, version, clients) defer hostReporter.Stop() p.AddReporter(hostReporter) p.AddTagger(probe.NewTopologyTagger(), host.NewTagger(hostID)) var processCache *process.CachingWalker var scanner procspy.ConnectionScanner if flags.procEnabled { processCache = process.NewCachingWalker(process.NewWalker(flags.procRoot)) scanner = procspy.NewConnectionScanner(processCache) p.AddTicker(processCache) p.AddReporter(process.NewReporter(processCache, hostID, process.GetDeltaTotalJiffies)) } endpointReporter := endpoint.NewReporter(hostID, hostName, flags.spyProcs, flags.useConntrack, flags.procEnabled, scanner) defer endpointReporter.Stop() p.AddReporter(endpointReporter) if flags.dockerEnabled { // Don't add the bridge in Kubernetes since container IPs are global and // shouldn't be scoped if !flags.kubernetesEnabled { if err := report.AddLocalBridge(flags.dockerBridge); err != nil { log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err) } } if registry, err := docker.NewRegistry(flags.dockerInterval, clients, true, hostID); err == nil { defer registry.Stop() if flags.procEnabled { p.AddTagger(docker.NewTagger(registry, processCache)) } p.AddReporter(docker.NewReporter(registry, hostID, probeID, p)) } else { log.Errorf("Docker: failed to start registry: %v", err) } } if flags.kubernetesEnabled { if client, err := kubernetes.NewClient(flags.kubernetesAPI, flags.kubernetesInterval); err == nil { defer client.Stop() reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p) defer reporter.Stop() p.AddReporter(reporter) p.AddTagger(reporter) } else { log.Errorf("Kubernetes: failed to start client: %v", err) log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide a valid kubernetes.api url") } } if flags.weaveAddr != "" { client := weave.NewClient(sanitize.URL("http://", 6784, "")(flags.weaveAddr)) weave := overlay.NewWeave(hostID, client) defer weave.Stop() p.AddTagger(weave) p.AddReporter(weave) dockerBridgeIP, err := network.GetFirstAddressOf(flags.dockerBridge) if err != nil { log.Println("Error getting docker bridge ip:", err) } else { weaveDNSLookup := appclient.LookupUsing(dockerBridgeIP + ":53") weaveResolver := appclient.NewResolver([]string{flags.weaveHostname}, weaveDNSLookup, clients.Set) defer weaveResolver.Stop() } } pluginRegistry, err := plugins.NewRegistry( flags.pluginsRoot, pluginAPIVersion, map[string]string{ "probe_id": probeID, "api_version": pluginAPIVersion, }, ) if err != nil { log.Errorf("plugins: problem loading: %v", err) } else { defer pluginRegistry.Close() p.AddReporter(pluginRegistry) } if flags.httpListen != "" { go func() { log.Infof("Profiling data being exported to %s", flags.httpListen) log.Infof("go tool pprof http://%s/debug/pprof/{profile,heap,block}", flags.httpListen) log.Infof("Profiling endpoint %s terminated: %v", flags.httpListen, http.ListenAndServe(flags.httpListen, nil)) }() } p.Start() defer p.Stop() common.SignalHandlerLoop() }