diff --git a/app/main.go b/app/main.go index 4c8bdf0378..527931f379 100644 --- a/app/main.go +++ b/app/main.go @@ -10,7 +10,6 @@ import ( "os" "os/signal" "strconv" - "strings" "syscall" "time" @@ -24,12 +23,12 @@ func main() { var ( defaultProbes = []string{fmt.Sprintf("localhost:%d", xfer.ProbePort), fmt.Sprintf("scope.weave.local:%d", xfer.ProbePort)} logfile = flag.String("log", "stderr", "stderr, syslog, or filename") - probes = flag.String("probes", strings.Join(defaultProbes, ","), "list of probe endpoints, comma separated") batch = flag.Duration("batch", 1*time.Second, "batch interval") window = flag.Duration("window", 15*time.Second, "window") listen = flag.String("http.address", ":"+strconv.Itoa(xfer.AppPort), "webserver listen address") ) flag.Parse() + probes := append(defaultProbes, flag.Args()...) switch *logfile { case "stderr": @@ -62,7 +61,7 @@ func main() { c := xfer.NewCollector(*batch) defer c.Stop() - r := NewResolver(strings.Split(*probes, ","), c.AddAddress) + r := NewResolver(probes, c.AddAddress) defer r.Stop() lifo := NewReportLIFO(c, *window) diff --git a/app/resolver.go b/app/resolver.go index 036d68310f..d3dbd362d8 100644 --- a/app/resolver.go +++ b/app/resolver.go @@ -3,7 +3,11 @@ package main import ( "log" "net" + "strconv" + "strings" "time" + + "github.com/weaveworks/scope/xfer" ) var ( @@ -42,11 +46,22 @@ func NewResolver(peers []string, add func(string)) Resolver { func prepareNames(strs []string) []peer { var results []peer for _, s := range strs { - hostname, port, err := net.SplitHostPort(s) - if err != nil { - log.Printf("invalid address %s: %v", s, err) - continue + var ( + hostname string + port string + err error + ) + + if strings.Contains(s, ":") { + hostname, port, err = net.SplitHostPort(s) + if err != nil { + log.Printf("invalid address %s: %v", s, err) + continue + } + } else { + hostname, port = s, strconv.Itoa(xfer.ProbePort) } + results = append(results, peer{hostname, port}) } return results @@ -67,10 +82,19 @@ func (r Resolver) loop() { func (r Resolver) resolveHosts() { for _, peer := range r.peers { - addrs, err := lookupIP(peer.hostname) - if err != nil { - log.Printf("lookup %s: %v", peer.hostname, err) - continue + var ( + addrs []net.IP + err error + ) + + if addr := net.ParseIP(peer.hostname); addr != nil { + addrs = []net.IP{addr} + } else { + addrs, err = lookupIP(peer.hostname) + if err != nil { + log.Printf("lookup %s: %v", peer.hostname, err) + continue + } } for _, addr := range addrs { diff --git a/app/resolver_test.go b/app/resolver_test.go index 5c41d7d488..a40d248ec9 100644 --- a/app/resolver_test.go +++ b/app/resolver_test.go @@ -1,10 +1,13 @@ package main import ( + "fmt" "net" "runtime" "testing" "time" + + "github.com/weaveworks/scope/xfer" ) func TestResolver(t *testing.T) { @@ -15,20 +18,21 @@ func TestResolver(t *testing.T) { oldLookupIP := lookupIP defer func() { lookupIP = oldLookupIP }() - ips := []net.IP{} - lookupIP = func(host string) ([]net.IP, error) { return ips, nil } + ips := map[string][]net.IP{} + lookupIP = func(host string) ([]net.IP, error) { + addrs, ok := ips[host] + if !ok { + return nil, fmt.Errorf("Not found") + } + return addrs, nil + } port := ":80" + ip1 := "192.168.0.1" + ip2 := "192.168.0.10" adds := make(chan string) add := func(s string) { adds <- s } - r := NewResolver([]string{"symbolic.name" + port}, add) - - c <- time.Now() // trigger initial resolve, with no endpoints - select { - case <-time.After(time.Millisecond): - case s := <-adds: - t.Errorf("got unexpected add: %q", s) - } + r := NewResolver([]string{"symbolic.name" + port, "namewithnoport", ip1 + port, ip2}, add) assertAdd := func(want string) { select { @@ -42,16 +46,30 @@ func TestResolver(t *testing.T) { } } - ip1 := "1.2.3.4" - ips = makeIPs(ip1) + // Initial resolve should just give us IPs + assertAdd(ip1 + port) + assertAdd(fmt.Sprintf("%s:%d", ip2, xfer.ProbePort)) + + // Trigger another resolve with a tick; again, + // just want ips. + c <- time.Now() + assertAdd(ip1 + port) + assertAdd(fmt.Sprintf("%s:%d", ip2, xfer.ProbePort)) + + ip3 := "1.2.3.4" + ips = map[string][]net.IP{"symbolic.name": makeIPs(ip3)} c <- time.Now() // trigger a resolve - assertAdd(ip1 + port) // we want 1 add + assertAdd(ip3 + port) // we want 1 add + assertAdd(ip1 + port) + assertAdd(fmt.Sprintf("%s:%d", ip2, xfer.ProbePort)) - ip2 := "10.10.10.10" - ips = makeIPs(ip1, ip2) + ip4 := "10.10.10.10" + ips = map[string][]net.IP{"symbolic.name": makeIPs(ip3, ip4)} c <- time.Now() // trigger another resolve, this time with 2 adds - assertAdd(ip1 + port) // first add - assertAdd(ip2 + port) // second add + assertAdd(ip3 + port) // first add + assertAdd(ip4 + port) // second add + assertAdd(ip1 + port) + assertAdd(fmt.Sprintf("%s:%d", ip2, xfer.ProbePort)) done := make(chan struct{}) go func() { r.Stop(); close(done) }() diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 100f009487..788a4a163b 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -31,4 +31,12 @@ if [ -n "$DNS_SERVER" -a -n "$SEARCHPATH" ]; then echo "nameserver $DNS_SERVER" >>/etc/resolv.conf fi +# End of the command line can optionally be some +# addresses of probes to connect to, for people not +# using Weave DNS. We stick these in /etc/weave/probes +# for the run-app script to pick up. +MANUAL_PROBES=$@ +mkdir -p /etc/weave +echo "$MANUAL_PROBES" >/etc/weave/probes + exec /sbin/runsvdir /etc/service diff --git a/docker/run-app b/docker/run-app index 8e7be93318..df910e5f5c 100755 --- a/docker/run-app +++ b/docker/run-app @@ -1,3 +1,3 @@ #!/bin/sh -exec /home/weave/app +exec /home/weave/app $(cat /etc/weave/probes) diff --git a/docs/scope.md b/docs/scope.md new file mode 100644 index 0000000000..0e792dd621 --- /dev/null +++ b/docs/scope.md @@ -0,0 +1,10 @@ + +## Multi host setup + +Weave Scope uses WeaveDNS to automatically discover other instances of Scope running on your network. If you have a running WeaveDNS setup, you do not need any further steps. + +If you do not wish to use WeaveDNS, you can instruct Scope to cluster with other Scope instances on the command line. Hostnames and IP addresses are acceptable, both with and without ports: + +``` +# weave launch scope1:4040 192.168.0.12 192.168.0.11:4040 +``` diff --git a/scope b/scope index 4333be4c9e..f60771abb4 100755 --- a/scope +++ b/scope @@ -1,7 +1,12 @@ #!/bin/bash usage() { - echo "$0 (launch|stop)" + echo "Usage:" + echo "scope launch [ ...]" + echo "scope stop" + echo + echo "scope is of the form [:]" + exit 1 } SCOPE_IMAGE=weaveworks/scope @@ -118,7 +123,6 @@ container_ip() { case "$COMMAND" in launch) - [ $# -eq 0 ] || usage check_not_running $CONTAINER_NAME $IMAGE # If WeaveDNS is running, we want to automatically tell the scope