first commit

This commit is contained in:
Jörg Thalheim 2016-04-13 14:17:46 +02:00
commit 0d7a8e706d
15 changed files with 700 additions and 0 deletions

2
.envrc Normal file
View File

@ -0,0 +1,2 @@
layout python3
. ~/.rancher-credentials

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
selenium-server-standalone-*.jar
callgraph
/.direnv

2
Makefile Normal file
View File

@ -0,0 +1,2 @@
test:
go test ./sysdig -cwd $(CURDIR)

6
README.md Normal file
View File

@ -0,0 +1,6 @@
# Get microservice callgraph
$ go build .
$ wget http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar
$ java -jar selenium-server-standalone-2.53.0.jar
$ ./callgraph http://sharelatex.local/login 192.168.8.33 192.168.8.34 192.168.8.35 192.168.8.36 192.168.8.37 192.168.8.38 192.168.8.17 192.168.8.18 192.168.8.19 | dot -Tpng > graph.png

98
capture-connections.lua Normal file
View File

@ -0,0 +1,98 @@
description = "description";
short_description = "desc";
category = "Net";
args = {}
require "common"
local fields = {}
function on_init()
local mapping = {
isread = "evt.is_io_read",
buflen = "evt.buflen",
proc = "proc.name",
pid = "proc.pid",
tid = "thread.tid",
container = "container.name",
sip = "fd.sip",
sport = "fd.sport",
cip = "fd.cip",
cport = "fd.cport",
evt_type = "evt.type",
proto = "fd.l4proto",
lip = "fd.lip",
}
for k,v in pairs(mapping) do
fields[k] = chisel.request_field(v)
end
key_fields = {fields.container, fields.proc, fields.pid, fields.tid, fields.proto, fields.sip, fields.sport, fields.cip, fields.cport}
sysdig.set_snaplen(0)
chisel.set_filter("evt.is_io=true and (fd.type=ipv4 or fd.type=ipv6) and fd.rip exists and fd.lip exists and container.name!=host")
return true
end
local stats = {}
local DEBUG = false
function on_event()
-- only capture connections of servers
local sip = evt.field(fields.sip)
if not (evt.field(fields.lip) == sip or evt.field(fields.rip) == sip) then
return true
end
local dir
if evt.field(fields.isread) then
dir = "rx"
else
dir = "tx"
end
if DEBUG then
function to_s(v)
return (evt.field(v) or "nil").." "
end
io.write("DEBUG: ",
to_s(fields.container),
to_s(fields.proc),
to_s(fields.pid),
to_s(fields.tid),
to_s(fields.proto),
to_s(fields.sip),
to_s(fields.sport),
to_s(fields.cip),
to_s(fields.cport),
to_s(fields.lip),
dir, "\n")
end
local t = { }
for k,v in ipairs(key_fields) do
t[#t+1] = tostring(evt.field(v))
end
t[#t+1] = dir
local key = table.concat(t, "\t")
stats[key] = (stats[key] or 0) + (evt.field(fields.buflen) or 0)
return true
end
function string.starts(string, prefix)
return string.sub(string, 1, string.len(start)) == prefix
end
function on_capture_start()
hostname = sysdig.get_machine_info().hostname
return true
end
function on_capture_end()
for k, v in pairs(stats) do
io.write(hostname, "\t", k, "\t", v, "\n")
end
end

86
captured-connections.tsv Normal file
View File

@ -0,0 +1,86 @@
macmini4 rancher-agent python 32703 32703 tcp 192.168.8.17 8080 192.168.8.34 59245 rx 3176
macmini4 rancher-agent host-api 526 619 tcp 192.168.8.17 8080 192.168.8.34 59244 rx 12
macmini4 rancher-agent python 32703 32703 tcp 192.168.8.17 8080 192.168.8.34 59247 tx 3304
macmini4 rancher-agent host-api 526 526 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 6
macmini4 rancher-agent python 32703 32703 tcp 192.168.8.17 8080 192.168.8.34 59247 rx 1044
macmini4 rancher-agent host-api 526 531 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 6
macmini4 rancher-agent host-api 526 528 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 6
macmini4 rancher-agent host-api 526 619 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 18
macmini6 rancher-agent host-api 1034 1034 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 6
macmini6 rancher-agent python 753 753 tcp 192.168.8.17 8080 192.168.8.36 40732 tx 3299
macmini6 rancher-agent host-api 1034 1037 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 6
macmini6 rancher-agent host-api 1034 1041 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 12
macmini6 rancher-agent host-api 1034 1039 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 24
macmini6 rancher-agent host-api 1034 1039 tcp 192.168.8.17 8080 192.168.8.36 40729 rx 16
macmini6 rancher-agent python 753 753 tcp 192.168.8.17 8080 192.168.8.36 40730 rx 2795
macmini6 rancher-agent python 753 753 tcp 192.168.8.17 8080 192.168.8.36 40732 rx 1044
macmini3 rancher-agent host-api 31449 31449 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 24
macmini3 rancher-agent host-api 31449 31454 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 6
macmini3 rancher-agent host-api 31449 31506 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 12
macmini3 rancher-agent host-api 31449 31455 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 6
macmini3 rancher-agent python 31167 31167 tcp 192.168.8.17 8080 192.168.8.33 52133 rx 3175
macmini3 rancher-agent python 31167 31167 tcp 192.168.8.17 8080 192.168.8.33 52138 tx 3295
macmini3 rancher-agent host-api 31449 31449 tcp 192.168.8.17 8080 192.168.8.33 52136 rx 16
macmini3 rancher-agent python 31167 31167 tcp 192.168.8.17 8080 192.168.8.33 52138 rx 1044
macmini5 rancher-agent host-api 404 412 tcp 192.168.8.17 8080 192.168.8.35 50962 rx 16
macmini5 rancher-agent host-api 404 418 tcp 192.168.8.17 8080 192.168.8.35 50962 tx 6
macmini5 rancher-agent host-api 404 412 tcp 192.168.8.17 8080 192.168.8.35 50962 tx 24
macmini5 rancher-agent python 32581 32581 tcp 192.168.8.17 8080 192.168.8.35 50964 tx 3299
macmini5 rancher-agent python 32581 32581 tcp 192.168.8.17 8080 192.168.8.35 50964 rx 1040
macmini5 rancher-agent python 32581 32581 tcp 192.168.8.17 8080 192.168.8.35 50958 rx 2794
macmini5 rancher-agent host-api 404 417 tcp 192.168.8.17 8080 192.168.8.35 50962 tx 18
macmini7 rancher-agent python 5674 5674 tcp 192.168.8.17 8080 192.168.8.37 35624 tx 3296
macmini7 rancher-agent host-api 5963 5965 tcp 192.168.8.17 8080 192.168.8.37 35618 tx 12
macmini7 rancher-agent python 5674 5674 tcp 192.168.8.17 8080 192.168.8.37 35624 rx 1044
macmini7 rancher-agent host-api 5963 5963 tcp 192.168.8.17 8080 192.168.8.37 35618 tx 12
macmini7 rancher-agent host-api 5963 6026 tcp 192.168.8.17 8080 192.168.8.37 35618 rx 16
macmini7 rancher-agent host-api 5963 6026 tcp 192.168.8.17 8080 192.168.8.37 35618 tx 24
macmini7 rancher-agent python 5674 5674 tcp 192.168.8.17 8080 192.168.8.37 35619 rx 2795
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60579 tx 493799
slfy79 rangerserver-v1 websocket-proxy 16398 16401 tcp 172.17.0.2 8080 192.168.8.17 50504 rx 553
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60574 tx 800550
slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 2
slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60580 rx 18573
slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 12
slfy79 rangerserver-v1 websocket-proxy 16398 16401 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 4
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60595 tx 311083
slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60579 rx 23733
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60574 rx 32808
slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 6
slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60872 tx 1882
slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 2
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60872 rx 920
slfy79 7461f018-c62e-4b02-9e1b-af6547e9a1e2 charon 13331 13335 udp 192.168.8.18 4500 192.168.8.17 4500 tx 1
slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 50504 tx 522
slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50504 rx 8573
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60578 rx 30589
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60580 tx 265880
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60530 tx 6328
slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50495 tx 1171
slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 8
slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 12
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60595 rx 21729
slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50504 tx 522
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60530 rx 102
slfy79 7461f018-c62e-4b02-9e1b-af6547e9a1e2 charon 13331 13335 udp 192.168.8.19 4500 192.168.8.17 4500 tx 2
slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50495 tx 408
slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50504 rx 1108
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60592 tx 524911
slfy79 rangerserver-v1 websocket-proxy 16398 16401 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 12
slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60592 rx 24020
slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 6
slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 50495 tx 1596
slfy85 rancher-agent host-api 26530 26536 tcp 192.168.8.17 8080 192.168.8.19 52183 rx 16
slfy85 rancher-agent host-api 26530 26550 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 12
slfy85 rancher-agent python 26248 26248 tcp 192.168.8.17 8080 192.168.8.19 52185 tx 9748
slfy85 rancher-agent python 26248 26248 tcp 192.168.8.17 8080 192.168.8.19 52179 rx 19204
slfy85 rancher-agent host-api 26530 26544 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 6
slfy85 9d011c95-bfcd-4880-adc4-2215175de5da charon 3236 3242 udp 192.168.8.17 4500 192.168.8.19 4500 tx 2
slfy85 rancher-agent python 26248 26248 tcp 192.168.8.17 8080 192.168.8.19 52185 rx 1044
slfy85 rancher-agent host-api 26530 26535 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 6
slfy85 rancher-agent host-api 26530 26536 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 24
slfy85 9d011c95-bfcd-4880-adc4-2215175de5da charon 3236 3242 udp 192.168.8.18 4500 192.168.8.19 4500 tx 2
1 macmini4 rancher-agent python 32703 32703 tcp 192.168.8.17 8080 192.168.8.34 59245 rx 3176
2 macmini4 rancher-agent host-api 526 619 tcp 192.168.8.17 8080 192.168.8.34 59244 rx 12
3 macmini4 rancher-agent python 32703 32703 tcp 192.168.8.17 8080 192.168.8.34 59247 tx 3304
4 macmini4 rancher-agent host-api 526 526 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 6
5 macmini4 rancher-agent python 32703 32703 tcp 192.168.8.17 8080 192.168.8.34 59247 rx 1044
6 macmini4 rancher-agent host-api 526 531 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 6
7 macmini4 rancher-agent host-api 526 528 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 6
8 macmini4 rancher-agent host-api 526 619 tcp 192.168.8.17 8080 192.168.8.34 59244 tx 18
9 macmini6 rancher-agent host-api 1034 1034 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 6
10 macmini6 rancher-agent python 753 753 tcp 192.168.8.17 8080 192.168.8.36 40732 tx 3299
11 macmini6 rancher-agent host-api 1034 1037 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 6
12 macmini6 rancher-agent host-api 1034 1041 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 12
13 macmini6 rancher-agent host-api 1034 1039 tcp 192.168.8.17 8080 192.168.8.36 40729 tx 24
14 macmini6 rancher-agent host-api 1034 1039 tcp 192.168.8.17 8080 192.168.8.36 40729 rx 16
15 macmini6 rancher-agent python 753 753 tcp 192.168.8.17 8080 192.168.8.36 40730 rx 2795
16 macmini6 rancher-agent python 753 753 tcp 192.168.8.17 8080 192.168.8.36 40732 rx 1044
17 macmini3 rancher-agent host-api 31449 31449 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 24
18 macmini3 rancher-agent host-api 31449 31454 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 6
19 macmini3 rancher-agent host-api 31449 31506 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 12
20 macmini3 rancher-agent host-api 31449 31455 tcp 192.168.8.17 8080 192.168.8.33 52136 tx 6
21 macmini3 rancher-agent python 31167 31167 tcp 192.168.8.17 8080 192.168.8.33 52133 rx 3175
22 macmini3 rancher-agent python 31167 31167 tcp 192.168.8.17 8080 192.168.8.33 52138 tx 3295
23 macmini3 rancher-agent host-api 31449 31449 tcp 192.168.8.17 8080 192.168.8.33 52136 rx 16
24 macmini3 rancher-agent python 31167 31167 tcp 192.168.8.17 8080 192.168.8.33 52138 rx 1044
25 macmini5 rancher-agent host-api 404 412 tcp 192.168.8.17 8080 192.168.8.35 50962 rx 16
26 macmini5 rancher-agent host-api 404 418 tcp 192.168.8.17 8080 192.168.8.35 50962 tx 6
27 macmini5 rancher-agent host-api 404 412 tcp 192.168.8.17 8080 192.168.8.35 50962 tx 24
28 macmini5 rancher-agent python 32581 32581 tcp 192.168.8.17 8080 192.168.8.35 50964 tx 3299
29 macmini5 rancher-agent python 32581 32581 tcp 192.168.8.17 8080 192.168.8.35 50964 rx 1040
30 macmini5 rancher-agent python 32581 32581 tcp 192.168.8.17 8080 192.168.8.35 50958 rx 2794
31 macmini5 rancher-agent host-api 404 417 tcp 192.168.8.17 8080 192.168.8.35 50962 tx 18
32 macmini7 rancher-agent python 5674 5674 tcp 192.168.8.17 8080 192.168.8.37 35624 tx 3296
33 macmini7 rancher-agent host-api 5963 5965 tcp 192.168.8.17 8080 192.168.8.37 35618 tx 12
34 macmini7 rancher-agent python 5674 5674 tcp 192.168.8.17 8080 192.168.8.37 35624 rx 1044
35 macmini7 rancher-agent host-api 5963 5963 tcp 192.168.8.17 8080 192.168.8.37 35618 tx 12
36 macmini7 rancher-agent host-api 5963 6026 tcp 192.168.8.17 8080 192.168.8.37 35618 rx 16
37 macmini7 rancher-agent host-api 5963 6026 tcp 192.168.8.17 8080 192.168.8.37 35618 tx 24
38 macmini7 rancher-agent python 5674 5674 tcp 192.168.8.17 8080 192.168.8.37 35619 rx 2795
39 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60579 tx 493799
40 slfy79 rangerserver-v1 websocket-proxy 16398 16401 tcp 172.17.0.2 8080 192.168.8.17 50504 rx 553
41 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60574 tx 800550
42 slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 2
43 slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
44 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60580 rx 18573
45 slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
46 slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 12
47 slfy79 rangerserver-v1 websocket-proxy 16398 16401 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 4
48 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60595 tx 311083
49 slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
50 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60579 rx 23733
51 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60574 rx 32808
52 slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 6
53 slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 42695 tx 381
54 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60872 tx 1882
55 slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 2
56 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60872 rx 920
57 slfy79 7461f018-c62e-4b02-9e1b-af6547e9a1e2 charon 13331 13335 udp 192.168.8.18 4500 192.168.8.17 4500 tx 1
58 slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 50504 tx 522
59 slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50504 rx 8573
60 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60578 rx 30589
61 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60580 tx 265880
62 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60530 tx 6328
63 slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50495 tx 1171
64 slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50500 tx 8
65 slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 12
66 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60595 rx 21729
67 slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50504 tx 522
68 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60530 rx 102
69 slfy79 7461f018-c62e-4b02-9e1b-af6547e9a1e2 charon 13331 13335 udp 192.168.8.19 4500 192.168.8.17 4500 tx 2
70 slfy79 rangerserver-v1 websocket-proxy 16398 16403 tcp 172.17.0.2 8080 192.168.8.17 50495 tx 408
71 slfy79 rangerserver-v1 websocket-proxy 16398 16398 tcp 172.17.0.2 8080 192.168.8.17 50504 rx 1108
72 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60592 tx 524911
73 slfy79 rangerserver-v1 websocket-proxy 16398 16401 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 12
74 slfy79 rancher-agent haproxy 21608 21608 tcp 172.17.0.11 80 192.168.8.17 60592 rx 24020
75 slfy79 rangerserver-v1 websocket-proxy 16398 16400 tcp 172.17.0.2 8080 192.168.8.17 50500 rx 6
76 slfy79 rangerserver-v1 websocket-proxy 16398 16402 tcp 172.17.0.2 8080 192.168.8.17 50495 tx 1596
77 slfy85 rancher-agent host-api 26530 26536 tcp 192.168.8.17 8080 192.168.8.19 52183 rx 16
78 slfy85 rancher-agent host-api 26530 26550 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 12
79 slfy85 rancher-agent python 26248 26248 tcp 192.168.8.17 8080 192.168.8.19 52185 tx 9748
80 slfy85 rancher-agent python 26248 26248 tcp 192.168.8.17 8080 192.168.8.19 52179 rx 19204
81 slfy85 rancher-agent host-api 26530 26544 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 6
82 slfy85 9d011c95-bfcd-4880-adc4-2215175de5da charon 3236 3242 udp 192.168.8.17 4500 192.168.8.19 4500 tx 2
83 slfy85 rancher-agent python 26248 26248 tcp 192.168.8.17 8080 192.168.8.19 52185 rx 1044
84 slfy85 rancher-agent host-api 26530 26535 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 6
85 slfy85 rancher-agent host-api 26530 26536 tcp 192.168.8.17 8080 192.168.8.19 52183 tx 24
86 slfy85 9d011c95-bfcd-4880-adc4-2215175de5da charon 3236 3242 udp 192.168.8.18 4500 192.168.8.19 4500 tx 2

122
main.go Normal file
View File

@ -0,0 +1,122 @@
package main
import (
"flag"
"fmt"
"net"
"os"
"os/exec"
"syscall"
"time"
"github.com/mic92/callgraph/rancher"
"github.com/mic92/callgraph/sharelatex"
"github.com/mic92/callgraph/sysdig"
)
var (
rancherHost = flag.String("rancher-host", "localhost:8080", "host of rancher server")
rancherAccessKey = flag.String("rancher-access-key", os.Getenv("RANCHER_ACCESS_KEY"), "api access key")
rancherSecretKey = flag.String("rancher-secret-key", os.Getenv("RANCHER_SECRET_KEY"), "api secret key")
)
func parseArgs() (sharelatexUrl string, hosts []string) {
flag.Parse()
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "USAGE: %s SHARELATEXURL HOSTS...", os.Args[0])
os.Exit(1)
}
if *rancherAccessKey == "" {
fmt.Fprintf(os.Stderr, "Set RANCHER_ACCESS_KEY environment variable")
os.Exit(1)
}
if *rancherSecretKey == "" {
fmt.Fprintf(os.Stderr, "Set RANCHER_SECRET_KEY environment variable")
os.Exit(1)
}
return os.Args[1], os.Args[2:]
}
func rancherServices() ([]sysdig.Service, error) {
c := rancher.New(*rancherHost, *rancherAccessKey, *rancherSecretKey)
var api rancher.Api
err := c.Get(fmt.Sprintf("http://%s/v1", c.Host), &api)
if err != nil {
return nil, fmt.Errorf("failed to request rancher api: %v", err)
}
if api.Links == nil {
return nil, fmt.Errorf("no links object found in api response")
}
val, ok := api.Links["containers"]
if !ok {
return nil, fmt.Errorf("no container link found in api response")
}
var containers rancher.Containers
err = c.Get(val, &containers)
if err != nil {
return nil, fmt.Errorf("could not get container list from api: %s", err)
}
serviceMap := make(map[string][]net.IP)
for _, container := range containers.Data {
var name string
if container.Labels.ProjectServiceName == "" {
name = container.Name
} else {
name = container.Labels.ProjectServiceName
}
ip := net.ParseIP(container.PrimaryIpAddress)
if ip == nil {
return nil, fmt.Errorf("Got invalid IP from api for '%s' container: %s", container.Name, ip)
}
serviceMap[name] = append(serviceMap[name], ip)
}
var services []sysdig.Service
for name, ips := range serviceMap {
services = append(services, sysdig.Service{name, ips})
}
return services, nil
}
func die(message string, args ...interface{}) {
fmt.Fprintf(os.Stderr, message, args...)
fmt.Fprint(os.Stderr, "\n")
os.Exit(1)
}
func main() {
url, hosts := parseArgs()
cmd, err := sysdig.Start(hosts)
if err != nil {
die("failed to start sysdig: %v", err)
}
time.Sleep(4 * time.Second)
err = sharelatex.IntegrationTest(url)
if err != nil {
die("selenium not running?: %v", err)
}
time.Sleep(1 * time.Second)
cmd.SendStopSignal()
var records []sysdig.Record
for range hosts {
select {
case result := <-cmd.Results:
if exitError, ok := result.Error.(*exec.ExitError); ok {
waitStatus := exitError.Sys().(syscall.WaitStatus)
if waitStatus != 130 { // Interrupt
fmt.Printf("[%s] sysdig failed with %v\n", result.Host.Name, result.Error, result.Output)
}
}
r, err := sysdig.ParseOutput(result.Output)
if err != nil {
die("Error parsing results from %s", result.Host.Name)
}
records = append(records, r...)
}
}
services, err := rancherServices()
if err != nil {
die("getting rancher services failed: %s", err)
}
(sysdig.Records(records)).PrintGraph(services)
}

34
rancher/client.go Normal file
View File

@ -0,0 +1,34 @@
package rancher
import (
"encoding/json"
"io/ioutil"
"net/http"
)
type Client struct {
Host, SecretKey, AccessKey string
client http.Client
}
func New(host, secretkey, accesskey string) Client {
return Client{host, secretkey, accesskey, http.Client{}}
}
func (c *Client) Get(url string, result interface{}) error {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
req.SetBasicAuth(c.AccessKey, c.SecretKey)
resp, err := c.client.Do(req)
if err != nil {
return err
}
body, err := ioutil.ReadAll(resp.Body)
json.Unmarshal(body, result)
if err != nil {
return err
}
return nil
}

18
rancher/types.go Normal file
View File

@ -0,0 +1,18 @@
package rancher
type Api struct {
Links map[string]string `json:"links"`
Data []interface{} `json:"data"`
}
type Containers struct {
Data []Container `json:"data"`
}
type Container struct {
Name string `json:"name"`
PrimaryIpAddress string `json:"primaryIpAddress"`
Labels struct {
ProjectServiceName string `json:"io.rancher.project_service.name"`
}
}

82
sharelatex/client.go Normal file
View File

@ -0,0 +1,82 @@
package sharelatex
import (
"fmt"
"math/rand"
"net/http"
"os"
"path/filepath"
"time"
"github.com/tebeka/selenium"
)
func IntegrationTest(url string) error {
_, err := http.Get(url)
if err != nil {
fmt.Printf("failed to get '%s': %s", url, err)
}
caps := selenium.Capabilities{"browserName": "firefox"}
wd, err := selenium.NewRemote(caps, "")
if err != nil {
return err
}
defer wd.Quit()
// Get simple playground interface
wd.Get(url)
e, _ := wd.FindElement(selenium.ByXPATH, "//input[@type='email']")
e.Clear()
e.SendKeys("joerg@higgsboson.tk")
e, _ = wd.FindElement(selenium.ByXPATH, "//input[@type='password']")
e.Clear()
e.SendKeys("password")
e, _ = wd.FindElement(selenium.ByXPATH, "//button[@type='submit']")
e.Click()
for {
_, err = wd.FindElement(selenium.ByLinkText, "Account")
if err == nil {
break
}
time.Sleep(time.Millisecond * 100)
}
time.Sleep(time.Millisecond * 4000)
e, _ = wd.FindElement(selenium.ByLinkText, "New Project")
e.Click()
e, _ = wd.FindElement(selenium.ByLinkText, "Blank Project")
e.Click()
e, _ = wd.FindElement(selenium.ByXPATH, "//input[@type='text']")
e.Clear()
e.SendKeys(fmt.Sprintf("p %d", rand.Int63()))
e, _ = wd.FindElement(selenium.ByCSSSelector, "button.btn-primary") // Create
e.Click()
time.Sleep(time.Millisecond * 3000)
e, _ = wd.FindElement(selenium.ByCSSSelector, `i.fa-comment`)
e.Click()
e, _ = wd.FindElement(selenium.ByCSSSelector, `div.new-message textarea`)
e.SendKeys("hello world" + selenium.EnterKey)
e, _ = wd.FindElement(selenium.ByCSSSelector, "i.fa.fa-upload") // Upload
e.Click()
e, _ = wd.FindElement(selenium.ByName, "file") // Create
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
e.SendKeys(filepath.Join(dir, "./test.txt"))
time.Sleep(time.Millisecond * 500)
e, _ = wd.FindElement(selenium.ByCSSSelector, "textarea") // Latex Doc
e.Clear()
e.SendKeys(`\documentclass{article} \begin{document} ello \end{document}`)
time.Sleep(time.Millisecond * 1000)
return nil
}

5
sysdig.sh Normal file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash -e
t="$(mktemp)"; f() {
rm "$t"
}
trap f EXIT; cat > "$t"; sudo sysdig -c "$t"

41
sysdig/graph.go Normal file
View File

@ -0,0 +1,41 @@
package sysdig
import (
"fmt"
"net"
)
type Records []Record
type Service struct {
Name string
Ips []net.IP
}
type Connection struct {
From string
To string
}
func (records Records) PrintGraph(services []Service) {
serviceMap := make(map[string]string)
for _, service := range services {
for _, ip := range service.Ips {
serviceMap[ip.String()] = service.Name
}
}
connections := make(map[string]Connection)
for _, r := range records {
if clientService, ok := serviceMap[r.ClientIp.String()]; ok {
if serverService, ok := serviceMap[r.ServerIp.String()]; ok {
connections[clientService+":"+serverService] = Connection{clientService, serverService}
}
}
}
fmt.Printf("digraph G {\n")
for _, connection := range connections {
fmt.Printf("\"%s\" -> \"%s\"\n", connection.From, connection.To)
}
fmt.Printf("}\n")
}

62
sysdig/graph_test.go Normal file
View File

@ -0,0 +1,62 @@
package sysdig_test
import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"runtime"
"testing"
"github.com/mic92/callgraph/sysdig"
)
func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
if !condition {
_, file, line, _ := runtime.Caller(1)
fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
tb.FailNow()
}
}
func ok(tb testing.TB, err error) {
if err != nil {
_, file, line, _ := runtime.Caller(1)
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
tb.FailNow()
}
}
func equals(tb testing.TB, exp, act interface{}) {
if !reflect.DeepEqual(exp, act) {
_, file, line, _ := runtime.Caller(1)
fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
tb.FailNow()
}
}
var (
cwd_arg = flag.String("cwd", "", "set cwd")
)
func init() {
flag.Parse()
if *cwd_arg != "" {
if err := os.Chdir(*cwd_arg); err != nil {
fmt.Println("Chdir error:", err)
}
}
}
func TestPrintGraph(t *testing.T) {
f, e := os.Open("./captured-connections.tsv")
ok(t, e)
c, e := ioutil.ReadAll(f)
ok(t, e)
_, e = sysdig.ParseOutput(string(c))
ok(t, e)
//(sysdig.Records(r)).PrintGraph()
//t.Fatal()
}

97
sysdig/records.go Normal file
View File

@ -0,0 +1,97 @@
package sysdig
import (
"encoding/csv"
"fmt"
"io"
"log"
"net"
"strconv"
"strings"
)
const (
RX = iota
TX
)
type Record struct {
Host, Container, Process string
Pid, Tid uint64
Proto string
ServerIp net.IP
ServerPort uint16
ClientIp net.IP
ClientPort uint16
Direction int
Bytes uint64
}
func ParseOutput(result string) ([]Record, error) {
r := csv.NewReader(strings.NewReader(result))
r.Comma = '\t'
var records []Record
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
if record[0] == "host" {
continue
}
pid, err := strconv.ParseUint(record[3], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid pid %s: %v", record[2], err)
}
tid, err := strconv.ParseUint(record[4], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid tid %s: %v", record[3], err)
}
sip := net.ParseIP(record[6])
if sip == nil {
return nil, fmt.Errorf("invalid ip '%s'", record[6])
}
sport, err := strconv.ParseUint(record[7], 10, 16)
if err != nil {
return nil, fmt.Errorf("invalid port %s: %v", record[7], err)
}
cip := net.ParseIP(record[8])
if cip == nil {
return nil, fmt.Errorf("invalid ip '%s'", record[8])
}
cport, err := strconv.ParseUint(record[9], 10, 16)
if err != nil {
return nil, fmt.Errorf("invalid port %s: %v", record[9], err)
}
var direction int
if record[10] == "rx" {
direction = RX
} else {
direction = TX
}
bytes, err := strconv.ParseUint(record[11], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid transmission size %s: %v", record[11], err)
}
records = append(records, Record{
record[0],
record[1],
record[2],
pid,
tid,
record[5],
sip,
uint16(sport),
cip,
uint16(cport),
direction,
bytes,
})
}
return records, nil
}

42
sysdig/start.go Normal file
View File

@ -0,0 +1,42 @@
package sysdig
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/mic92/clusterssh"
)
func Start(hostnames []string) (*clusterssh.Command, error) {
hosts := make([]clusterssh.Host, len(hostnames))
for i, arg := range hostnames {
host, err := clusterssh.ParseHost(arg)
if err != nil {
return nil, fmt.Errorf("invalid host '%s': %v", arg, err)
}
hosts[i] = *host
}
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
f1, err := os.Open(filepath.Join(dir, "capture-connections.lua"))
if err != nil {
return nil, fmt.Errorf("failed to open sysdig plugin")
}
sysdigPlugin, err := ioutil.ReadAll(f1)
if err != nil {
return nil, fmt.Errorf("failed to read sysdig plugin: %v", err)
}
f2, err := os.Open(filepath.Join(dir, "sysdig.sh"))
if err != nil {
return nil, fmt.Errorf("failed to open sysdig plugin: %v", err)
}
sysdigCommand, err := ioutil.ReadAll(f2)
if err != nil {
return nil, fmt.Errorf("failed to read sysdig command: %v", err)
}
cluster := clusterssh.Cluster{hosts}
cmd := cluster.Run(string(sysdigCommand), sysdigPlugin)
return &cmd, nil
}