diff --git a/README.md b/README.md index 53ac9e33..22092da7 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,35 @@ each other but not the containers of our first application... This isolation-through-subnets scheme is an example of carrying over a well-known technique from the 'on metal' days to containers. +### Dynamic network attachment + +In some scenarios containers are started independently, e.g. via some +existing tool chain, or require more complex startup sequences than +provided by `weave run`. And sometimes the decision which application +network a container should be part of is made post startup. For these +situation, weave allows an existing, running container to be attached +to the weave network. To illustrate, we can achieve the same effect as +the first example with + + host1# C=$(docker run -d -t -i ubuntu) + host1# weave attach 10.0.1.1/24 $C + +There is a matching `weave detach` command: + + host1# weave detach 10.0.1.1/24 $C + +You can detach a container from one application network and attach it +to another: + + host1# weave detach 10.0.1.1/24 $C + host1# weave attach 10.0.2.1/24 $C + +or attach a container to multiple application networks, effectively +sharing it between applications: + + host1# weave attach 10.0.1.1/24 $C + host1# weave attach 10.0.2.1/24 $C + ### Security In order to connect containers across untrusted networks, weave peers @@ -221,30 +250,6 @@ will work. And, more interestingly, will work too, which is talking to a container that resides on $HOST1. -### Attach to already-running containers - -If you don't want to start containers via the `weave` script, e.g. because -you are controlling them as part of some larger orchestration scheme, you can -attach the weave network to an already-running container. To illustrate, we -can achieve the same effect as the first example like this: - - host1# C=$(docker run -d -t -i ubuntu) - host1# weave attach 10.0.1.1/24 $C - -There is a matching `weave detach` command: - - host1# weave detach 10.0.1.1/24 $C - -You can detach a container from one subnet and re-attach it to another: - - host1# weave detach 10.0.1.1/24 $C - host1# weave attach 10.0.2.1/24 $C - -or attach a container to multiple subnets: - - host1# weave attach 10.0.1.1/24 $C - host1# weave attach 10.0.2.1/24 $C - ### Service export Services running in containers on a weave network can be made @@ -419,13 +424,8 @@ quickly enough. ## Troubleshooting -Check what version of weave you are running: - - weave version - -and compare against -https://registry.hub.docker.com/u/zettio/weave/tags/manage/. If you -do not have the latest released version you can download it with: +Make sure you are running the latest version - you can download it +with docker pull zettio/weave @@ -537,7 +537,8 @@ More details on the inner workings of weave can be found in the Found a bug, want to suggest a feature, or have a question? [File an issue](https://github.com/zettio/weave/issues), or email -weave@zett.io. +weave@zett.io. When reporting a bug, please include what version of +weave you are running, as shown by `weave version`. Follow weave on Twitter: [@weavenetwork](https://twitter.com/weavenetwork). diff --git a/connection.go b/connection.go index 014183b3..61ced2b0 100644 --- a/connection.go +++ b/connection.go @@ -182,14 +182,14 @@ func (conn *LocalConnection) queryLoop(queryChan <-chan *ConnectionInteraction, if !ok { break } - switch { - case query.code == CShutdown: + switch query.code { + case CShutdown: terminate = true - case query.code == CSetEstablished: + case CSetEstablished: err = conn.handleSetEstablished() - case query.code == CSetRemoteUDPAddr: + case CSetRemoteUDPAddr: err = conn.handleSetRemoteUDPAddr(query.payload.(*net.UDPAddr)) - case query.code == CSendTCP: + case CSendTCP: err = conn.handleSendTCP(query.payload.([]byte)) } } diff --git a/connection_maker.go b/connection_maker.go index 8c259bd5..94064646 100644 --- a/connection_maker.go +++ b/connection_maker.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "log" + "math" "math/rand" "net" "time" @@ -16,8 +17,9 @@ const ( const ( CMInitiate = iota - CMStatus = iota CMTerminated = iota + CMRefresh = iota + CMStatus = iota ) func StartConnectionMaker(router *Router) *ConnectionMaker { @@ -43,6 +45,11 @@ func (cm *ConnectionMaker) ConnectionTerminated(address string) { address: address} } +func (cm *ConnectionMaker) Refresh() { + cm.queryChan <- &ConnectionMakerInteraction{ + Interaction: Interaction{code: CMRefresh}} +} + func (cm *ConnectionMaker) String() string { resultChan := make(chan interface{}, 0) cm.queryChan <- &ConnectionMakerInteraction{ @@ -52,44 +59,38 @@ func (cm *ConnectionMaker) String() string { } func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) { - var tick <-chan time.Time - maybeTick := func() { - // would be nice to optimise this to stop ticking when there is nothing worth trying - if tick == nil { - tick = time.After(5 * time.Second) - } - } + timer := time.NewTimer(math.MaxInt64) + run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) } for { select { case query, ok := <-queryChan: if !ok { return } - switch { - case query.code == CMInitiate: + switch query.code { + case CMInitiate: cm.cmdLineAddress[NormalisePeerAddr(query.address)] = true - cm.checkStateAndAttemptConnections(time.Now()) - maybeTick() - case query.code == CMStatus: - query.resultChan <- cm.status() - case query.code == CMTerminated: + run() + case CMTerminated: if target, found := cm.targets[query.address]; found { target.attempting = false target.tryAfter, target.tryInterval = tryAfter(target.tryInterval) - maybeTick() } + run() + case CMRefresh: + run() + case CMStatus: + query.resultChan <- cm.status() default: log.Fatal("Unexpected connection maker query:", query) } - case now := <-tick: - cm.checkStateAndAttemptConnections(now) - tick = nil - maybeTick() + case <-timer.C: + run() } } } -func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) { +func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration { ourself := cm.router.Ourself validTarget := make(map[string]bool) @@ -129,7 +130,8 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) { }) }) - now = time.Now() // make sure we catch items just added + now := time.Now() // make sure we catch items just added + after := time.Duration(math.MaxInt64) for address, target := range cm.targets { if our_connected_targets[address] { delete(cm.targets, address) @@ -142,11 +144,15 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections(now time.Time) { delete(cm.targets, address) continue } - if now.After(target.tryAfter) { + switch duration := target.tryAfter.Sub(now); { + case duration <= 0: target.attempting = true go cm.attemptConnection(address, cm.cmdLineAddress[address]) + case duration < after: + after = duration } } + return after } func (cm *ConnectionMaker) addTarget(address string) { diff --git a/pcap.go b/pcap.go index 354ec818..912d0fba 100644 --- a/pcap.go +++ b/pcap.go @@ -40,9 +40,6 @@ func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *Pca if err = inactive.SetSnapLen(snaplen); err != nil { return } - if err = inactive.SetTimeout(-1); err != nil { - return - } if err = inactive.SetImmediateMode(true); err != nil { return } diff --git a/peer.go b/peer.go index b62e8b27..80dc3d2a 100644 --- a/peer.go +++ b/peer.go @@ -259,15 +259,15 @@ func (peer *Peer) queryLoop(queryChan <-chan *PeerInteraction) { if !ok { return } - switch { - case query.code == PAddConnection: + switch query.code { + case PAddConnection: peer.handleAddConnection(query.payload.(*LocalConnection)) - case query.code == PDeleteConnection: + case PDeleteConnection: peer.handleDeleteConnection(query.payload.(*LocalConnection)) query.resultChan <- nil - case query.code == PConnectionEstablished: + case PConnectionEstablished: peer.handleConnectionEstablished(query.payload.(*LocalConnection)) - case query.code == PBroadcastTCP: + case PBroadcastTCP: peer.handleBroadcastTCP(query.payload.([]byte)) } } diff --git a/peer_cache.go b/peer_cache.go index a499d5ae..a5d9f956 100644 --- a/peer_cache.go +++ b/peer_cache.go @@ -77,6 +77,10 @@ func (cache *PeerCache) ApplyUpdate(update []byte, router *Router) ([]byte, erro // Don't need to hold cache lock any longer cache.Unlock() + if len(newUpdate) > 0 { + router.ConnectionMaker.Refresh() + } + return encodePeersMap(newUpdate), nil } diff --git a/topology.go b/topology.go index c0db270c..fe3a9323 100644 --- a/topology.go +++ b/topology.go @@ -81,15 +81,15 @@ func (topo *Topology) queryLoop(queryChan <-chan *Interaction) { if !ok { return } - switch { - case query.code == TRebuildRoutes: + switch query.code { + case TRebuildRoutes: unicast := topo.buildUnicastRoutes() broadcast := topo.buildBroadcastRoutes() topo.Lock() topo.unicast = unicast topo.broadcast = broadcast topo.Unlock() - case query.code == TFetchAll: + case TFetchAll: query.resultChan <- topo.router.Peers.EncodeAllPeers() default: log.Fatal("Unexpected topology query:", query) diff --git a/weaver/Makefile b/weaver/Makefile index 96a251a4..a776a2ee 100644 --- a/weaver/Makefile +++ b/weaver/Makefile @@ -15,7 +15,8 @@ docker-image: /tmp/weave.tar publish: docker-image sudo docker tag zettio/weave zettio/weave:git-`git rev-parse --short=12 HEAD` - sudo docker push zettio/weave + sudo docker push zettio/weave:latest + sudo docker push zettio/weave:git-`git rev-parse --short=12 HEAD` clean: -sudo docker rmi zettio/weave