Skip to content

Commit 966aa47

Browse files
authored
Merge pull request #60 from m-lab/pt-backup
Add new mode -scamper-with-paris-backup
2 parents 03f2db7 + 44e337d commit 966aa47

File tree

4 files changed

+105
-23
lines changed

4 files changed

+105
-23
lines changed

caller.go

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var (
3434
waitTime = flag.Duration("waitTime", 5*time.Second, "how long to wait between subsequent listings of open connections")
3535
poll = flag.Bool("poll", true, "Whether the polling method should be used to see new connections.")
3636
tracerType = flagx.Enum{
37-
Options: []string{"paris-traceroute", "scamper"},
37+
Options: []string{"paris-traceroute", "scamper", "scamper-with-paris-backup"},
3838
Value: "scamper",
3939
}
4040

@@ -63,34 +63,46 @@ func main() {
6363
promSrv := prometheusx.MustServeMetrics()
6464
defer promSrv.Shutdown(ctx)
6565

66-
var trace ipcache.Tracer
66+
scamperDaemon := &tracer.ScamperDaemon{
67+
Binary: *scamperBin,
68+
AttachBinary: *scattachBin,
69+
Warts2JSONBinary: *scwarts2jsonBin,
70+
OutputPath: *outputPath,
71+
ControlSocket: *scamperCtrlSocket,
72+
ScamperTimeout: *scamperTimeout,
73+
}
74+
parisTracer := &tracer.Paris{
75+
Binary: *parisBin,
76+
OutputPath: *outputPath,
77+
Timeout: *parisTimeout,
78+
}
79+
80+
var cache *ipcache.RecentIPCache
81+
82+
// Set up the cache three different ways, depending on the trace method requested.
6783
switch tracerType.Value {
6884
case "scamper":
69-
daemon := &tracer.ScamperDaemon{
70-
Binary: *scamperBin,
71-
AttachBinary: *scattachBin,
72-
Warts2JSONBinary: *scwarts2jsonBin,
73-
OutputPath: *outputPath,
74-
ControlSocket: *scamperCtrlSocket,
75-
ScamperTimeout: *scamperTimeout,
76-
}
85+
cache = ipcache.New(ctx, scamperDaemon, *ipcache.IPCacheTimeout, *ipcache.IPCacheUpdatePeriod)
7786
wg.Add(1)
7887
go func() {
79-
daemon.MustStart(ctx)
88+
scamperDaemon.MustStart(ctx)
89+
// When the scamper daemon dies, cancel main() and exit.
8090
cancel()
8191
wg.Done()
8292
}()
83-
trace = daemon
8493
case "paris-traceroute":
85-
trace = &tracer.Paris{
86-
Binary: *parisBin,
87-
OutputPath: *outputPath,
88-
Timeout: *parisTimeout,
89-
}
94+
cache = ipcache.New(ctx, parisTracer, *ipcache.IPCacheTimeout, *ipcache.IPCacheUpdatePeriod)
95+
case "scamper-with-paris-backup":
96+
cache = ipcache.New(ctx, scamperDaemon, *ipcache.IPCacheTimeout, *ipcache.IPCacheUpdatePeriod)
97+
wg.Add(1)
98+
go func() {
99+
scamperDaemon.MustStart(ctx)
100+
// When the scamper daemon dies, switch to paris-traceroute.
101+
cache.UpdateTracer(parisTracer)
102+
wg.Done()
103+
}()
90104
}
91105

92-
cache := ipcache.New(ctx, trace, *ipcache.IPCacheTimeout, *ipcache.IPCacheUpdatePeriod)
93-
94106
if *poll {
95107
wg.Add(1)
96108
go func(c *ipcache.RecentIPCache) {

caller_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func TestMain(t *testing.T) {
3232
*waitTime = time.Nanosecond // Run through the loop a few times.
3333
*outputPath = dir
3434
*poll = true
35+
*scamperBin = "scamper"
3536
tracerType.Value = "scamper"
3637
ctx, cancel = context.WithCancel(context.Background())
3738
go func() {
@@ -49,7 +50,6 @@ func TestMainWithConnectionListener(t *testing.T) {
4950
rtx.Must(srv.Listen(), "Could not start the empty server")
5051

5152
*prometheusx.ListenAddress = ":0"
52-
*scamperCtrlSocket = dir + "/scamper.sock"
5353
*eventsocket.Filename = dir + "/events.sock"
5454
*outputPath = dir
5555
*poll = false
@@ -64,6 +64,30 @@ func TestMainWithConnectionListener(t *testing.T) {
6464
main()
6565
}
6666

67+
func TestMainWithBackupPT(t *testing.T) {
68+
dir, err := ioutil.TempDir("", "TestMainWithBackupPT")
69+
rtx.Must(err, "Could not create temp dir")
70+
defer os.RemoveAll(dir)
71+
srv := eventsocket.New(dir + "/events.sock")
72+
rtx.Must(srv.Listen(), "Could not start the empty server")
73+
74+
*prometheusx.ListenAddress = ":0"
75+
*eventsocket.Filename = dir + "/events.sock"
76+
*outputPath = dir
77+
*poll = false
78+
*scamperCtrlSocket = dir + "/scamper.sock"
79+
*scamperBin = "false"
80+
tracerType.Value = "scamper-with-paris-backup"
81+
82+
ctx, cancel = context.WithCancel(context.Background())
83+
go srv.Serve(ctx)
84+
go func() {
85+
time.Sleep(1 * time.Second)
86+
cancel()
87+
}()
88+
main()
89+
}
90+
6791
func TestMainWithBadArgs(t *testing.T) {
6892
tracerType.Value = "paris-traceroute"
6993
*eventsocket.Filename = ""

ipcache/ipcache.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,28 @@ func (rc *RecentIPCache) getEntry(ip string) (*cachedTest, bool) {
5656
return rc.cache[ip], existed
5757
}
5858

59+
func (rc *RecentIPCache) getTracer() Tracer {
60+
rc.mu.Lock()
61+
defer rc.mu.Unlock()
62+
return rc.tracer
63+
}
64+
5965
// Trace performs a trace and adds it to the cache. It calls the methods of the
6066
// tracer, so if those create files on disk, then files on disk will be created
6167
// as a side effect.
6268
func (rc *RecentIPCache) Trace(conn connection.Connection) (string, error) {
6369
c, cached := rc.getEntry(conn.RemoteIP)
70+
t := rc.getTracer()
6471
if cached {
6572
<-c.dataReady
6673
if c.err == nil {
67-
rc.tracer.TraceFromCachedTrace(conn, time.Now(), c.data)
74+
t.TraceFromCachedTrace(conn, time.Now(), c.data)
6875
return c.data, nil
6976
}
70-
rc.tracer.DontTrace(conn, c.err)
77+
t.DontTrace(conn, c.err)
7178
return "", c.err
7279
}
73-
c.data, c.err = rc.tracer.Trace(conn, c.timeStamp)
80+
c.data, c.err = t.Trace(conn, c.timeStamp)
7481
close(c.dataReady)
7582
return c.data, c.err
7683
}
@@ -84,6 +91,14 @@ func (rc *RecentIPCache) GetCacheLength() int {
8491
return len(rc.cache)
8592
}
8693

94+
// UpdateTracer switches the Tracer being used. This allows us to dynamically
95+
// switch between scamper and paris-traceroute.
96+
func (rc *RecentIPCache) UpdateTracer(t Tracer) {
97+
rc.mu.Lock()
98+
defer rc.mu.Unlock()
99+
rc.tracer = t
100+
}
101+
87102
// New creates and returns a RecentIPCache. It also starts up a background
88103
// goroutine that scrubs the cache.
89104
func New(ctx context.Context, trace Tracer, ipCacheTimeout, ipCacheUpdatePeriod time.Duration) *RecentIPCache {

ipcache/ipcache_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"testing"
1212
"time"
1313

14+
"github.com/m-lab/go/rtx"
1415
"github.com/m-lab/traceroute-caller/connection"
1516
"github.com/m-lab/traceroute-caller/ipcache"
1617
pipe "gopkg.in/m-lab/pipe.v3"
@@ -23,6 +24,7 @@ type testTracer struct {
2324
}
2425

2526
func (tf *testTracer) Trace(conn connection.Connection, t time.Time) (string, error) {
27+
tf.calls++
2628
return "Fake trace test " + conn.RemoteIP, nil
2729
}
2830

@@ -82,6 +84,35 @@ func TestTrace(t *testing.T) {
8284
}
8385
}
8486

87+
func TestUpdateTracer(t *testing.T) {
88+
ctx, cancel := context.WithCancel(context.Background())
89+
defer cancel()
90+
var tt, tt2 testTracer
91+
testCache := ipcache.New(ctx, &tt, 100*time.Second, time.Second)
92+
conn1 := connection.Connection{
93+
RemoteIP: "1.1.1.2",
94+
RemotePort: 5034,
95+
LocalIP: "1.1.1.3",
96+
LocalPort: 58790,
97+
Cookie: "10f3d"}
98+
_, err := testCache.Trace(conn1)
99+
rtx.Must(err, "Could not trace using tt")
100+
101+
testCache.UpdateTracer(&tt2)
102+
conn2 := connection.Connection{
103+
RemoteIP: "1.1.1.5",
104+
RemotePort: 5034,
105+
LocalIP: "1.1.1.3",
106+
LocalPort: 58790,
107+
Cookie: "aaaa"}
108+
_, err = testCache.Trace(conn2)
109+
rtx.Must(err, "Could not trace using tt2")
110+
111+
if tt.calls != 1 || tt2.calls != 1 {
112+
t.Error("Each tracer should have been called once, not", tt.calls, tt2.calls)
113+
}
114+
}
115+
85116
func TestRecentIPCache(t *testing.T) {
86117
ctx, cancel := context.WithCancel(context.Background())
87118
defer cancel()

0 commit comments

Comments
 (0)