diff --git a/router/connection_maker.go b/router/connection_maker.go index d8e34e55..64db9e6b 100644 --- a/router/connection_maker.go +++ b/router/connection_maker.go @@ -48,30 +48,39 @@ func (cm *ConnectionMaker) Start() { go cm.queryLoop(actionChan) } -func (cm *ConnectionMaker) InitiateConnection(peer string) error { - host, port, err := net.SplitHostPort(peer) - if err != nil { - host = peer - port = "0" // we use that as an indication that "no port was supplied" - } - addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%s", host, port)) - if err != nil { - return err +func (cm *ConnectionMaker) InitiateConnections(peers []string) []error { + errors := []error{} + addrs := make(map[string]*net.TCPAddr) + for _, peer := range peers { + host, port, err := net.SplitHostPort(peer) + if err != nil { + host = peer + port = "0" // we use that as an indication that "no port was supplied" + } + if addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%s", host, port)); err != nil { + errors = append(errors, err) + } else { + addrs[peer] = addr + } } cm.actionChan <- func() bool { - cm.cmdLinePeers[peer] = addr - // curtail any existing reconnect interval - if target, found := cm.targets[addr.String()]; found { - target.tryAfter, target.tryInterval = tryImmediately() + for peer, addr := range addrs { + cm.cmdLinePeers[peer] = addr + // curtail any existing reconnect interval + if target, found := cm.targets[addr.String()]; found { + target.tryAfter, target.tryInterval = tryImmediately() + } } return true } - return nil + return errors } -func (cm *ConnectionMaker) ForgetConnection(peer string) { +func (cm *ConnectionMaker) ForgetConnections(peers []string) { cm.actionChan <- func() bool { - delete(cm.cmdLinePeers, peer) + for _, peer := range peers { + delete(cm.cmdLinePeers, peer) + } return false } } diff --git a/test/150_connect_forget_test.sh b/test/150_connect_forget_test.sh new file mode 100755 index 00000000..63777282 --- /dev/null +++ b/test/150_connect_forget_test.sh @@ -0,0 +1,26 @@ +#! /bin/bash + +. ./config.sh + +C1=10.2.1.4 +C2=10.2.1.7 + +start_suite "Connecting and forgetting routers after launch" + +weave_on $HOST1 launch +weave_on $HOST2 launch + +start_container $HOST1 $C1/24 --name=c1 +start_container $HOST2 $C2/24 --name=c2 + +assert_raises "exec_on $HOST1 c1 $PING $C2" 1 +assert_raises "weave_on $HOST2 connect $HOST1 $HOST2" +assert_raises "exec_on $HOST1 c1 $PING $C2" + +assert_raises "weave_on $HOST2 forget $HOST1 $HOST2" +assert_raises "weave_on $HOST1 stop" +assert_raises "weave_on $HOST1 launch" + +assert_raises "exec_on $HOST1 c1 $PING $C2" 1 + +end_suite diff --git a/weave b/weave index 8aeab6f4..b443989c 100755 --- a/weave +++ b/weave @@ -28,8 +28,8 @@ usage() { echo "weave launch [-password ] [-nickname ] [-iprange ] ..." echo "weave launch-dns " echo "weave launch-proxy [-H ] [--with-dns] [--with-ipam]" - echo "weave connect " - echo "weave forget " + echo "weave connect ..." + echo "weave forget ..." echo "weave run [--with-dns] [ ...] ..." echo "weave start [ ...] " echo "weave attach [ ...] " @@ -562,6 +562,16 @@ echo_addresses() { echo $1 $2 $3 } +peer_args() { + res='' + sep='' + for p in "$@" ; do + res="$res${sep}peer=$p" + sep="&" + done + echo "$res" +} + ###################################################################### # weaveDNS helpers ###################################################################### @@ -878,12 +888,12 @@ case "$COMMAND" in echo $PROXY_CONTAINER ;; connect) - [ $# -eq 1 ] || usage - http_call $CONTAINER_NAME $HTTP_PORT POST /connect -d "peer=$1" + [ $# -gt 0 ] || usage + http_call $CONTAINER_NAME $HTTP_PORT POST /connect -d $(peer_args "$@") ;; forget) - [ $# -eq 1 ] || usage - http_call $CONTAINER_NAME $HTTP_PORT POST /forget -d "peer=$1" + [ $# -gt 0 ] || usage + http_call $CONTAINER_NAME $HTTP_PORT POST /forget -d $(peer_args "$@") ;; status) http_call $CONTAINER_NAME $HTTP_PORT GET /status || true diff --git a/weaver/main.go b/weaver/main.go index 94567ab4..cf7fdae4 100644 --- a/weaver/main.go +++ b/weaver/main.go @@ -1,10 +1,17 @@ package main import ( - "code.google.com/p/gopacket/layers" "crypto/sha256" "flag" "fmt" + "log" + "net" + "net/http" + "os" + "runtime" + "strings" + + "code.google.com/p/gopacket/layers" "github.com/davecheney/profile" "github.com/gorilla/mux" . "github.com/weaveworks/weave/common" @@ -12,12 +19,6 @@ import ( "github.com/weaveworks/weave/ipam" weavenet "github.com/weaveworks/weave/net" weave "github.com/weaveworks/weave/router" - "log" - "net" - "net/http" - "os" - "runtime" - "strings" ) var version = "(unreleased version)" @@ -143,7 +144,9 @@ func main() { } router.Start() - initiateConnections(router, peers) + if errors := router.ConnectionMaker.InitiateConnections(peers); len(errors) > 0 { + log.Fatal(errorMessages(errors)) + } // The weave script always waits for a status call to succeed, // so there is no point in doing "weave launch -httpaddr ''". @@ -155,6 +158,14 @@ func main() { SignalHandlerLoop(router) } +func errorMessages(errors []error) string { + var result []string + for _, err := range errors { + result = append(result, err.Error()) + } + return strings.Join(result, "\n") +} + func options() map[string]string { options := make(map[string]string) flag.Visit(func(f *flag.Flag) { @@ -181,14 +192,6 @@ func logFrameFunc(debug bool) weave.LogFrameFunc { } } -func initiateConnections(router *weave.Router, peers []string) { - for _, peer := range peers { - if err := router.ConnectionMaker.InitiateConnection(peer); err != nil { - log.Fatal(err) - } - } -} - func createAllocator(router *weave.Router, apiPath string, iprangeCIDR string, quorum uint) *ipam.Allocator { allocator, err := ipam.NewAllocator(router.Ourself.Peer.Name, router.Ourself.Peer.UID, router.Ourself.Peer.NickName, iprangeCIDR, quorum) if err != nil { @@ -250,13 +253,19 @@ func handleHTTP(router *weave.Router, httpAddr string, allocator *ipam.Allocator }) muxRouter.Methods("POST").Path("/connect").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if err := router.ConnectionMaker.InitiateConnection(r.FormValue("peer")); err != nil { - http.Error(w, fmt.Sprint("invalid peer address: ", err), http.StatusBadRequest) + if err := r.ParseForm(); err != nil { + http.Error(w, fmt.Sprint("unable to parse form: ", err), http.StatusBadRequest) + } + if errors := router.ConnectionMaker.InitiateConnections(r.Form["peer"]); len(errors) > 0 { + http.Error(w, errorMessages(errors), http.StatusBadRequest) } }) muxRouter.Methods("POST").Path("/forget").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - router.ConnectionMaker.ForgetConnection(r.FormValue("peer")) + if err := r.ParseForm(); err != nil { + http.Error(w, fmt.Sprint("unable to parse form: ", err), http.StatusBadRequest) + } + router.ConnectionMaker.ForgetConnections(r.Form["peer"]) }) http.Handle("/", muxRouter)