From 928a693491248d2c724fc1419c2911e1fee98d1c Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Tue, 5 Apr 2016 17:25:19 +0100 Subject: [PATCH 1/2] Extend version summary in the `weave status` report The extended version summary includes info about a new available version in the case the checkpoint is enabled. --- README.md | 6 ++- prog/weaver/http.go | 47 +++++++++++++++++++--- prog/weaver/main.go | 16 +++++--- site/troubleshooting.md | 6 ++- test/700_status_and_report_test.sh | 15 +++++++ test/config.sh | 4 +- vendor/github.com/weaveworks/go-checkpoint | 2 +- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 97c2eadd..f046ca5a 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,10 @@ Weave Net respects the environment variable `DOCKER_HOST`, so you can run it locally to control a weave network on a remote host. Weave Net -[periodically contacts Weaveworks servers for available versions](https://github.com/weaveworks/go-checkpoint) -and announces new versions in the log. To disable this check, run: +[periodically contacts Weaveworks servers for available versions](https://github.com/weaveworks/go-checkpoint). +New versions are announced in the log and in +[the status summary](http://docs.weave.works/weave/latest_release/troubleshooting.html#weave-status). +To disable this check, run: ``` export CHECKPOINT_DISABLE=1 diff --git a/prog/weaver/http.go b/prog/weaver/http.go index cf9254ac..28d11893 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -7,10 +7,12 @@ import ( "net/http" "strings" "text/template" + "time" "github.com/gorilla/mux" "github.com/weaveworks/mesh" + "github.com/weaveworks/go-checkpoint" "github.com/weaveworks/weave/ipam" "github.com/weaveworks/weave/nameserver" "github.com/weaveworks/weave/net/address" @@ -138,7 +140,7 @@ func defTemplate(name string, text string) *template.Template { } var statusTemplate = defTemplate("status", `\ - Version: {{.Version}} + Version: {{.Version}} ({{.VersionCheck}}) Service: router Protocol: {{.Router.Protocol}} \ @@ -221,17 +223,51 @@ var dnsEntriesTemplate = defTemplate("dnsEntries", `\ var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}}`) +type VersionCheck struct { + Enabled bool + NewVersion string + NextCheckAt time.Time +} + +func versionCheck() *VersionCheck { + v := &VersionCheck{} + if checkpoint.IsCheckDisabled() { + return v + } + + v.Enabled = true + v.NewVersion = newVersion.Load().(string) + v.NextCheckAt = checker.NextCheckAt() + + return v +} + +func (v *VersionCheck) String() string { + switch { + case !v.Enabled: + return "version check update disabled" + case v.NewVersion != "": + return fmt.Sprintf("version %s available - please upgrade!", + v.NewVersion) + default: + return fmt.Sprintf("up to date; next check at %s", + v.NextCheckAt.Format("2006/01/02 15:04:05")) + } +} + type WeaveStatus struct { - Version string - Router *weave.NetworkRouterStatus `json:"Router,omitempty"` - IPAM *ipam.Status `json:"IPAM,omitempty"` - DNS *nameserver.Status `json:"DNS,omitempty"` + Version string + VersionCheck *VersionCheck `json:"VersionCheck,omitempty"` + Router *weave.NetworkRouterStatus `json:"Router,omitempty"` + IPAM *ipam.Status `json:"IPAM,omitempty"` + DNS *nameserver.Status `json:"DNS,omitempty"` } func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) { status := func() WeaveStatus { return WeaveStatus{ version, + versionCheck(), weave.NewNetworkRouterStatus(router), ipam.NewStatus(allocator, defaultSubnet), nameserver.NewStatus(ns, dnsserver)} @@ -283,5 +319,4 @@ func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRout defHandler("/status/peers", peersTemplate) defHandler("/status/dns", dnsEntriesTemplate) defHandler("/status/ipam", ipamTemplate) - } diff --git a/prog/weaver/main.go b/prog/weaver/main.go index cb297117..2f6a86b4 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -8,6 +8,7 @@ import ( "os" "runtime" "strings" + "sync/atomic" "time" "github.com/davecheney/profile" @@ -27,6 +28,8 @@ import ( ) var version = "(unreleased version)" +var checker *checkpoint.Checker +var newVersion atomic.Value var Log = common.Log @@ -51,10 +54,15 @@ const ( ) func checkForUpdates() { + newVersion.Store("") + handleResponse := func(r *checkpoint.CheckResponse, err error) { if err != nil { Log.Printf("Error checking version: %v", err) - } else if r.Outdated { + return + } + if r.Outdated { + newVersion.Store(r.CurrentVersion) Log.Printf("Weave version %s is available; please update at %s", r.CurrentVersion, r.CurrentDownloadURL) } @@ -66,9 +74,7 @@ func checkForUpdates() { Version: version, SignatureFile: "", } - resp, err := checkpoint.Check(¶ms) - handleResponse(resp, err) - checkpoint.CheckInterval(¶ms, updateCheckPeriod, handleResponse) + checker = checkpoint.CheckInterval(¶ms, updateCheckPeriod, handleResponse) } func (c ipamConfig) Enabled() bool { @@ -183,7 +189,7 @@ func main() { Log.Println("Command line options:", options()) - go checkForUpdates() + checkForUpdates() if prof != "" { p := *profile.CPUProfile diff --git a/site/troubleshooting.md b/site/troubleshooting.md index 4e7a3168..5c9d089b 100644 --- a/site/troubleshooting.md +++ b/site/troubleshooting.md @@ -48,7 +48,7 @@ A status summary can be obtained using `weave status`: ```` $ weave status - Version: 1.1.0 + Version: 1.1.0 (up to date; next check at 2016/04/06 12:30:00) Service: router Protocol: weave 1..2 @@ -80,7 +80,9 @@ $ weave status The terms used here are explained further at [How Weave Net Works](/site/router-topology.md). - * **Version** - shows the Weave Net version. + * **Version** - shows the Weave Net version. If checkpoint is enabled (i.e. +`CHECKPOINT_DISABLE` is not set), information about existence of a new version +will be shown. * **Protocol**- indicates the Weave Router inter-peer communication protocol name and supported versions (min..max). diff --git a/test/700_status_and_report_test.sh b/test/700_status_and_report_test.sh index 1e0ee154..4fe64750 100755 --- a/test/700_status_and_report_test.sh +++ b/test/700_status_and_report_test.sh @@ -26,4 +26,19 @@ weave_on $HOST1 connect 10.2.2.1 assert "weave_on $HOST1 status targets" "10.2.2.1" assert "weave_on $HOST1 status connections | tr -s ' ' | cut -d ' ' -f 2" "10.2.2.1:6783" +assert "weave_on $HOST1 report -f '{{.VersionCheck.Enabled}}'" "false" +assert_raises "weave_on $HOST1 status | grep 'version check update disabled'" + +weave_on $HOST1 reset + +CHECKPOINT_DISABLE="" weave_on $HOST1 launch +assert "weave_on $HOST1 report -f '{{.VersionCheck.Enabled}}'" "true" + +NEW_VSN=$(weave_on $HOST1 report -f "{{.VersionCheck.NewVersion}}") +if [ -z "$NEW_VSN" ]; then + assert_raises "weave_on $HOST1 status | grep 'up to date; next check at '" +else + assert_raises "weave_on $HOST1 status | grep \"version $NEW_VSN available - please upgrade!\"" +fi + end_suite diff --git a/test/config.sh b/test/config.sh index cf302556..52681674 100644 --- a/test/config.sh +++ b/test/config.sh @@ -44,6 +44,8 @@ CHECK_ETHWE_MISSING="test ! -d /sys/class/net/ethwe" DOCKER_PORT=2375 +CHECKPOINT_DISABLE=true + upload_executable() { host=$1 file=$2 @@ -118,7 +120,7 @@ weave_on() { host=$1 shift 1 [ -z "$DEBUG" ] || greyly echo "Weave on $host:$DOCKER_PORT: $@" >&2 - CHECKPOINT_DISABLE=true DOCKER_HOST=tcp://$host:$DOCKER_PORT $WEAVE "$@" + CHECKPOINT_DISABLE="$CHECKPOINT_DISABLE" DOCKER_HOST=tcp://$host:$DOCKER_PORT $WEAVE "$@" } stop_weave_on() { diff --git a/vendor/github.com/weaveworks/go-checkpoint b/vendor/github.com/weaveworks/go-checkpoint index d99cc14f..b6cc8365 160000 --- a/vendor/github.com/weaveworks/go-checkpoint +++ b/vendor/github.com/weaveworks/go-checkpoint @@ -1 +1 @@ -Subproject commit d99cc14f13e7845b370a7dc81d47cafb29cdc97f +Subproject commit b6cc8365a31bccd0b19591ba4a68704082a17141 From 66393535682c906b780b47d13e0eaa32b252dab9 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 12 Apr 2016 14:40:22 +0100 Subject: [PATCH 2/2] Lock round TestRouter map accesses, and copy the set where we may block. --- testing/gossip/mocks.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/testing/gossip/mocks.go b/testing/gossip/mocks.go index 124afe30..8cafd89d 100644 --- a/testing/gossip/mocks.go +++ b/testing/gossip/mocks.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "math/rand" + "sync" "time" "github.com/weaveworks/mesh" @@ -32,22 +33,34 @@ type flushMessage struct { } type TestRouter struct { + sync.Mutex gossipChans map[mesh.PeerName]chan interface{} loss float32 // 0.0 means no loss } func NewTestRouter(loss float32) *TestRouter { - return &TestRouter{make(map[mesh.PeerName]chan interface{}, 100), loss} + return &TestRouter{gossipChans: make(map[mesh.PeerName]chan interface{}, 100), loss: loss} +} + +// Copy so we can access outside of a lock +func (grouter *TestRouter) copyGossipChans() map[mesh.PeerName]chan interface{} { + ret := make(map[mesh.PeerName]chan interface{}) + grouter.Lock() + defer grouter.Unlock() + for p, c := range grouter.gossipChans { + ret[p] = c + } + return ret } func (grouter *TestRouter) Stop() { - for peer := range grouter.gossipChans { + for peer := range grouter.copyGossipChans() { grouter.RemovePeer(peer) } } func (grouter *TestRouter) gossipBroadcast(sender mesh.PeerName, update mesh.GossipData) { - for _, gossipChan := range grouter.gossipChans { + for _, gossipChan := range grouter.copyGossipChans() { select { case gossipChan <- broadcastMessage{sender: sender, data: update}: default: // drop the message if we cannot send it @@ -57,8 +70,9 @@ func (grouter *TestRouter) gossipBroadcast(sender mesh.PeerName, update mesh.Gos } func (grouter *TestRouter) gossip(sender mesh.PeerName, update mesh.GossipData) error { - count := int(math.Log2(float64(len(grouter.gossipChans)))) - for dest, gossipChan := range grouter.gossipChans { + gossipChans := grouter.copyGossipChans() + count := int(math.Log2(float64(len(gossipChans)))) + for dest, gossipChan := range gossipChans { if dest == sender { continue } @@ -76,7 +90,7 @@ func (grouter *TestRouter) gossip(sender mesh.PeerName, update mesh.GossipData) } func (grouter *TestRouter) Flush() { - for _, gossipChan := range grouter.gossipChans { + for _, gossipChan := range grouter.copyGossipChans() { flushChan := make(chan struct{}) gossipChan <- flushMessage{flushChan: flushChan} <-flushChan @@ -84,11 +98,15 @@ func (grouter *TestRouter) Flush() { } func (grouter *TestRouter) RemovePeer(peer mesh.PeerName) { + grouter.Lock() gossipChan := grouter.gossipChans[peer] + grouter.Unlock() resultChan := make(chan struct{}) gossipChan <- exitMessage{exitChan: resultChan} <-resultChan + grouter.Lock() delete(grouter.gossipChans, peer) + grouter.Unlock() } type TestRouterClient struct { @@ -160,13 +178,18 @@ func (grouter *TestRouter) Connect(sender mesh.PeerName, gossiper mesh.Gossiper) go grouter.run(sender, gossiper, gossipChan) + grouter.Lock() grouter.gossipChans[sender] = gossipChan + grouter.Unlock() return TestRouterClient{grouter, sender} } func (client TestRouterClient) GossipUnicast(dstPeerName mesh.PeerName, buf []byte) error { + client.router.Lock() + gossipChan := client.router.gossipChans[dstPeerName] + client.router.Unlock() select { - case client.router.gossipChans[dstPeerName] <- unicastMessage{sender: client.sender, buf: buf}: + case gossipChan <- unicastMessage{sender: client.sender, buf: buf}: default: // drop the message if we cannot send it common.Log.Errorf("Dropping message") }