Merge pull request #141 from tomwilkie/139-multi-host

Yet More Plumbing for multi-host setup.
This commit is contained in:
Tom Wilkie
2015-06-01 13:32:44 +01:00
7 changed files with 92 additions and 32 deletions

View File

@@ -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)

View File

@@ -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
)
if strings.Contains(s, ":") {
var err error
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,16 @@ 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
if addr := net.ParseIP(peer.hostname); addr != nil {
addrs = []net.IP{addr}
} else {
var err error
addrs, err = lookupIP(peer.hostname)
if err != nil {
log.Printf("lookup %s: %v", peer.hostname, err)
continue
}
}
for _, addr := range addrs {

View File

@@ -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)
c <- time.Now() // trigger a resolve
assertAdd(ip1 + port) // we want 1 add
// Initial resolve should just give us IPs
assertAdd(ip1 + port)
assertAdd(fmt.Sprintf("%s:%d", ip2, xfer.ProbePort))
ip2 := "10.10.10.10"
ips = makeIPs(ip1, ip2)
// 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(ip3 + port) // we want 1 add
assertAdd(ip1 + port)
assertAdd(fmt.Sprintf("%s:%d", ip2, xfer.ProbePort))
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) }()

View File

@@ -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

View File

@@ -1,3 +1,3 @@
#!/bin/sh
exec /home/weave/app
exec /home/weave/app $(cat /etc/weave/probes)

10
docs/scope.md Normal file
View File

@@ -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:4030 192.168.0.12 192.168.0.11:4030
```

8
scope
View File

@@ -1,7 +1,12 @@
#!/bin/bash
usage() {
echo "$0 (launch|stop)"
echo "Usage:"
echo "scope launch [<peer> ...]"
echo "scope stop"
echo
echo "scope <peer> is of the form <ip_address_or_fqdn>[:<port>]"
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