From 34e7996f2f70c7d0ad14744a83ccb021155d86c6 Mon Sep 17 00:00:00 2001 From: Alvaro Saurin Date: Mon, 16 Nov 2015 11:26:48 +0100 Subject: [PATCH 01/10] Show some IPAM status at /status/ipam --- ipam/ring/ring.go | 20 +++++++++ ipam/status.go | 17 ++++++++ prog/weaver/http.go | 98 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 132 insertions(+), 3 deletions(-) diff --git a/ipam/ring/ring.go b/ipam/ring/ring.go index 30f32b8d..e992dd43 100644 --- a/ipam/ring/ring.go +++ b/ipam/ring/ring.go @@ -316,6 +316,26 @@ func (r *Ring) OwnedRanges() (result []address.Range) { return r.splitRangesOverZero(result) } +func (r *Ring) OwnedRangesByPeer() map[mesh.PeerName][]address.Range { + r.assertInvariants() + + result := make(map[mesh.PeerName][]address.Range) + for i, entry := range r.Entries { + nextEntry := r.Entries.entry(i + 1) + resultPeer, found := result[entry.Peer] + r := address.Range{Start: entry.Token, End: nextEntry.Token} + if !found { + result[entry.Peer] = []address.Range{r} + } else { + result[entry.Peer] = append(resultPeer, r) + } + } + for peer, resultPeer := range result { + result[peer] = r.splitRangesOverZero(resultPeer) + } + return result +} + // ClaimForPeers claims the entire ring for the array of peers passed // in. Only works for empty rings. func (r *Ring) ClaimForPeers(peers []mesh.PeerName) { diff --git a/ipam/status.go b/ipam/status.go index 72df8d3e..39bc4588 100644 --- a/ipam/status.go +++ b/ipam/status.go @@ -2,13 +2,23 @@ package ipam import ( "github.com/weaveworks/weave/ipam/paxos" + "github.com/weaveworks/weave/ipam/ring" + "github.com/weaveworks/weave/ipam/space" + "github.com/weaveworks/weave/mesh" "github.com/weaveworks/weave/net/address" ) type Status struct { Paxos *paxos.Status Range string + RangeNumIPs int DefaultSubnet string + Ring *ring.Ring // information on ranges owned by all peers + Space space.Space // more detail on ranges owned by us + Owned map[string][]address.Address // addresses by container-ID + OurName mesh.PeerName + Nicknames map[mesh.PeerName]string `json:"-"` + IsKnownPeer func(mesh.PeerName) bool `json:"-"` Entries []EntryStatus PendingClaims []ClaimStatus PendingAllocates []string @@ -40,7 +50,14 @@ func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status { resultChan <- &Status{ paxosStatus, allocator.universe.String(), + int(allocator.universe.Size()), defaultSubnet.String(), + allocator.ring, + allocator.space, + allocator.owned, + allocator.ourName, + allocator.nicknames, + allocator.isKnownPeer, newEntryStatusSlice(allocator), newClaimStatusSlice(allocator), newAllocateIdentSlice(allocator)} diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 6794967e..848afbc5 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -1,8 +1,13 @@ package main import ( + "bytes" "encoding/json" "fmt" + "net/http" + "strings" + "text/template" + "github.com/gorilla/mux" . "github.com/weaveworks/weave/common" "github.com/weaveworks/weave/ipam" @@ -10,9 +15,6 @@ import ( "github.com/weaveworks/weave/nameserver" "github.com/weaveworks/weave/net/address" weave "github.com/weaveworks/weave/router" - "net/http" - "strings" - "text/template" ) var rootTemplate = template.New("root").Funcs(map[string]interface{}{ @@ -31,6 +33,76 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ } return strings.Join(servers, ", ") }, + "printIPAMRanges": func(status ipam.Status) string { + var buffer bytes.Buffer + + type NicknameStats struct { + Ranges []address.Range + Addresses []address.Address + Reachable bool + } + + nicknameStats := make(map[string]*NicknameStats) + getNickName := func(peer mesh.PeerName) string { + name, found := status.Nicknames[peer] + if !found { + return fmt.Sprintf("%s", peer) + } + return name + } + getOrCreateNicknameStats := func(peer mesh.PeerName) *NicknameStats { + peerName := getNickName(peer) + stats, found := nicknameStats[peerName] + if !found { + stats = &NicknameStats{ + Ranges: []address.Range{}, + Addresses: []address.Address{}, + Reachable: status.IsKnownPeer(peer), + } + nicknameStats[peerName] = stats + } + return stats + } + + for _, entry := range status.Ring.Entries { + stats := getOrCreateNicknameStats(entry.Peer) + stats.Addresses = append(stats.Addresses, entry.Token) + } + + for peer, ranges := range status.Ring.OwnedRangesByPeer() { + stats := getOrCreateNicknameStats(peer) + stats.Ranges = append(stats.Ranges, ranges...) + } + + appendAddresses := func(displayName string, reachable bool, addresses []address.Address, ranges []address.Range) { + reachableStr := "" + if !reachable { + reachableStr = "- unreachable!" + } + ipsInRange := 0 + for _, chunk := range ranges { + ipsInRange += int(chunk.Size()) + } + percentageRanges := float32(ipsInRange) * 100.0 / float32(status.RangeNumIPs) + + fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of universe, in %3d ranges) - used: %8d IPs %s\n", + displayName, ipsInRange, percentageRanges, len(ranges), len(addresses), reachableStr) + } + + // print the local addresses + ourNickname := getNickName(status.OurName) + ourStats := nicknameStats[ourNickname] + appendAddresses("(local)", true, ourStats.Addresses, ourStats.Ranges) + + // and then the rest + for nickname, stats := range nicknameStats { + if nickname != ourNickname { + appendAddresses(nickname, stats.Reachable, stats.Addresses, stats.Ranges) + } + } + + return buffer.String() + }, "printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string { counts := make(map[string]int) for _, conn := range conns { @@ -152,6 +224,25 @@ var dnsEntriesTemplate = defTemplate("dnsEntries", `\ {{end}}\ `) +var ipamTemplate = defTemplate("ipamTemplate", `\ + Universe: {{.IPAM.Range}} ({{.IPAM.RangeNumIPs}} IPs) + DefaultSubnet: {{.IPAM.DefaultSubnet}} +{{if .IPAM.Owned}}\ + Containers: +{{range $id, $addresses := .IPAM.Owned}}\ + {{printf "%-12s" $id}}: {{$addresses}} +{{end}}\ +{{end}}\ + Ownerships: +{{printIPAMRanges .IPAM}} +{{if .IPAM.PendingClaims}}\ + Claims: +{{range .IPAM.PendingClaims}} + {{printf "%-15v" .Ident}} {{.Address}} +{{end}}\ +{{end}}\ +`) + type WeaveStatus struct { Version string Router *weave.NetworkRouterStatus `json:"Router,omitempty"` @@ -207,5 +298,6 @@ func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRout defHandler("/status/connections", connectionsTemplate) defHandler("/status/peers", peersTemplate) defHandler("/status/dns", dnsEntriesTemplate) + defHandler("/status/ipam", ipamTemplate) } From 6d3fd6da07241a955e70cd8ca18177afa5b310ab Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 20 Nov 2015 18:04:12 +0000 Subject: [PATCH 02/10] Simplify ipam status format Don't use the word "universe" in user-visible output; it is an internal term. Removed everything but owned ranges from 'weave status ipam' results, for consistency with similar functions --- prog/weaver/http.go | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 848afbc5..52bd5d3f 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -46,7 +46,7 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ getNickName := func(peer mesh.PeerName) string { name, found := status.Nicknames[peer] if !found { - return fmt.Sprintf("%s", peer) + return peer.String() } return name } @@ -54,11 +54,7 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ peerName := getNickName(peer) stats, found := nicknameStats[peerName] if !found { - stats = &NicknameStats{ - Ranges: []address.Range{}, - Addresses: []address.Address{}, - Reachable: status.IsKnownPeer(peer), - } + stats = &NicknameStats{Reachable: status.IsKnownPeer(peer)} nicknameStats[peerName] = stats } return stats @@ -85,8 +81,8 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ } percentageRanges := float32(ipsInRange) * 100.0 / float32(status.RangeNumIPs) - fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of universe, in %3d ranges) - used: %8d IPs %s\n", - displayName, ipsInRange, percentageRanges, len(ranges), len(addresses), reachableStr) + fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of total) - used: %d %s\n", + displayName, ipsInRange, percentageRanges, len(addresses), reachableStr) } // print the local addresses @@ -224,24 +220,7 @@ var dnsEntriesTemplate = defTemplate("dnsEntries", `\ {{end}}\ `) -var ipamTemplate = defTemplate("ipamTemplate", `\ - Universe: {{.IPAM.Range}} ({{.IPAM.RangeNumIPs}} IPs) - DefaultSubnet: {{.IPAM.DefaultSubnet}} -{{if .IPAM.Owned}}\ - Containers: -{{range $id, $addresses := .IPAM.Owned}}\ - {{printf "%-12s" $id}}: {{$addresses}} -{{end}}\ -{{end}}\ - Ownerships: -{{printIPAMRanges .IPAM}} -{{if .IPAM.PendingClaims}}\ - Claims: -{{range .IPAM.PendingClaims}} - {{printf "%-15v" .Ident}} {{.Address}} -{{end}}\ -{{end}}\ -`) +var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .IPAM}}`) type WeaveStatus struct { Version string From 5f42a4d95edf431bbdf7979f43d3a00e7a48a0c8 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 23 Nov 2015 15:11:56 +0000 Subject: [PATCH 03/10] Hold stats by peer identity not nickname so we can print the peer name for each ownership. Also avoid crashing if we don't own anything --- prog/weaver/http.go | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 52bd5d3f..c1474901 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -36,41 +36,33 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ "printIPAMRanges": func(status ipam.Status) string { var buffer bytes.Buffer - type NicknameStats struct { + type stats struct { Ranges []address.Range Addresses []address.Address Reachable bool } - nicknameStats := make(map[string]*NicknameStats) - getNickName := func(peer mesh.PeerName) string { - name, found := status.Nicknames[peer] + peerStats := make(map[mesh.PeerName]*stats) + getOrCreateStats := func(peer mesh.PeerName) *stats { + s, found := peerStats[peer] if !found { - return peer.String() + s = &stats{Reachable: status.IsKnownPeer(peer)} + peerStats[peer] = s } - return name - } - getOrCreateNicknameStats := func(peer mesh.PeerName) *NicknameStats { - peerName := getNickName(peer) - stats, found := nicknameStats[peerName] - if !found { - stats = &NicknameStats{Reachable: status.IsKnownPeer(peer)} - nicknameStats[peerName] = stats - } - return stats + return s } for _, entry := range status.Ring.Entries { - stats := getOrCreateNicknameStats(entry.Peer) + stats := getOrCreateStats(entry.Peer) stats.Addresses = append(stats.Addresses, entry.Token) } for peer, ranges := range status.Ring.OwnedRangesByPeer() { - stats := getOrCreateNicknameStats(peer) + stats := getOrCreateStats(peer) stats.Ranges = append(stats.Ranges, ranges...) } - appendAddresses := func(displayName string, reachable bool, addresses []address.Address, ranges []address.Range) { + appendAddresses := func(peer mesh.PeerName, nickName string, reachable bool, addresses []address.Address, ranges []address.Range) { reachableStr := "" if !reachable { reachableStr = "- unreachable!" @@ -81,19 +73,24 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ } percentageRanges := float32(ipsInRange) * 100.0 / float32(status.RangeNumIPs) + displayName := peer.String() + "(" + nickName + ")" fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of total) - used: %d %s\n", displayName, ipsInRange, percentageRanges, len(addresses), reachableStr) } // print the local addresses - ourNickname := getNickName(status.OurName) - ourStats := nicknameStats[ourNickname] - appendAddresses("(local)", true, ourStats.Addresses, ourStats.Ranges) + if ourStats := peerStats[status.OurName]; ourStats != nil { + appendAddresses(status.OurName, "local", true, ourStats.Addresses, ourStats.Ranges) + } // and then the rest - for nickname, stats := range nicknameStats { - if nickname != ourNickname { - appendAddresses(nickname, stats.Reachable, stats.Addresses, stats.Ranges) + for peer, stats := range peerStats { + if peer != status.OurName { + nickname, found := status.Nicknames[peer] + if !found { + nickname = peer.String() + } + appendAddresses(peer, nickname, stats.Reachable, stats.Addresses, stats.Ranges) } } From 044c6474b21bf4fc94b22daeecae6c84af979dc0 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 23 Nov 2015 17:23:49 +0000 Subject: [PATCH 04/10] Remove counting of ring tokens, since it isn't useful to end-user. Previously the count of tokens was claimed to be a count of addresses in use, which is incorrect. Also rename `appendAddresses` to `appendOwned` since it doesn't involve addresses. --- prog/weaver/http.go | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index c1474901..dbf64c75 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -38,31 +38,21 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ type stats struct { Ranges []address.Range - Addresses []address.Address Reachable bool } peerStats := make(map[mesh.PeerName]*stats) - getOrCreateStats := func(peer mesh.PeerName) *stats { + + for peer, ranges := range status.Ring.OwnedRangesByPeer() { s, found := peerStats[peer] if !found { s = &stats{Reachable: status.IsKnownPeer(peer)} peerStats[peer] = s } - return s + s.Ranges = append(s.Ranges, ranges...) } - for _, entry := range status.Ring.Entries { - stats := getOrCreateStats(entry.Peer) - stats.Addresses = append(stats.Addresses, entry.Token) - } - - for peer, ranges := range status.Ring.OwnedRangesByPeer() { - stats := getOrCreateStats(peer) - stats.Ranges = append(stats.Ranges, ranges...) - } - - appendAddresses := func(peer mesh.PeerName, nickName string, reachable bool, addresses []address.Address, ranges []address.Range) { + appendOwned := func(peer mesh.PeerName, nickName string, reachable bool, ranges []address.Range) { reachableStr := "" if !reachable { reachableStr = "- unreachable!" @@ -74,13 +64,13 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ percentageRanges := float32(ipsInRange) * 100.0 / float32(status.RangeNumIPs) displayName := peer.String() + "(" + nickName + ")" - fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of total) - used: %d %s\n", - displayName, ipsInRange, percentageRanges, len(addresses), reachableStr) + fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of total) %s\n", + displayName, ipsInRange, percentageRanges, reachableStr) } // print the local addresses if ourStats := peerStats[status.OurName]; ourStats != nil { - appendAddresses(status.OurName, "local", true, ourStats.Addresses, ourStats.Ranges) + appendOwned(status.OurName, "local", true, ourStats.Ranges) } // and then the rest @@ -90,7 +80,7 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ if !found { nickname = peer.String() } - appendAddresses(peer, nickname, stats.Reachable, stats.Addresses, stats.Ranges) + appendOwned(peer, nickname, stats.Reachable, stats.Ranges) } } From e38018ab1ec8d2ab89200aab22871fd98f0f48a2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 23 Nov 2015 18:06:18 +0000 Subject: [PATCH 05/10] Add warning to main ipam status if all IPs owned by unreachable peers --- prog/weaver/http.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index dbf64c75..8db1d425 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -86,6 +86,20 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ return buffer.String() }, + "printIPAMWarning": func(status ipam.Status) string { + ipsReachable := 0 + for peer, ranges := range status.Ring.OwnedRangesByPeer() { + if status.IsKnownPeer(peer) { + for _, chunk := range ranges { + ipsReachable += int(chunk.Size()) + } + } + } + if ipsReachable == 0 { + return "- all IPs owned by unreachable peers!" + } + return "" + }, "printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string { counts := make(map[string]int) for _, conn := range conns { @@ -156,7 +170,7 @@ var statusTemplate = defTemplate("status", `\ Service: ipam {{if .IPAM.Entries}}\ - Consensus: achieved + Consensus: achieved {{printIPAMWarning .IPAM}} {{else if .IPAM.Paxos}}\ Consensus: waiting (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}}) {{else}}\ From 3a9bcbcf6b7a20403a55de44928cf778a2e634a2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 23 Nov 2015 17:54:27 +0000 Subject: [PATCH 06/10] Remove specialised knowledge of IPAM from weave status formatter and unnecessary info from `weave report` output --- ipam/ring/ring.go | 25 ++++++++-------- ipam/status.go | 35 ++++++++++------------ prog/weaver/http.go | 71 ++++++++++++++++++++------------------------- 3 files changed, 59 insertions(+), 72 deletions(-) diff --git a/ipam/ring/ring.go b/ipam/ring/ring.go index e992dd43..b7b948c3 100644 --- a/ipam/ring/ring.go +++ b/ipam/ring/ring.go @@ -316,24 +316,25 @@ func (r *Ring) OwnedRanges() (result []address.Range) { return r.splitRangesOverZero(result) } -func (r *Ring) OwnedRangesByPeer() map[mesh.PeerName][]address.Range { +// For printing status +type RangeInfo struct { + Peer mesh.PeerName + address.Range + Version uint32 +} + +func (r *Ring) AllRangeInfo() (result []RangeInfo) { r.assertInvariants() - result := make(map[mesh.PeerName][]address.Range) for i, entry := range r.Entries { nextEntry := r.Entries.entry(i + 1) - resultPeer, found := result[entry.Peer] - r := address.Range{Start: entry.Token, End: nextEntry.Token} - if !found { - result[entry.Peer] = []address.Range{r} - } else { - result[entry.Peer] = append(resultPeer, r) + ranges := []address.Range{{Start: entry.Token, End: nextEntry.Token}} + ranges = r.splitRangesOverZero(ranges) + for _, r := range ranges { + result = append(result, RangeInfo{entry.Peer, r, entry.Version}) } } - for peer, resultPeer := range result { - result[peer] = r.splitRangesOverZero(resultPeer) - } - return result + return } // ClaimForPeers claims the entire ring for the array of peers passed diff --git a/ipam/status.go b/ipam/status.go index 39bc4588..57af14a9 100644 --- a/ipam/status.go +++ b/ipam/status.go @@ -2,9 +2,6 @@ package ipam import ( "github.com/weaveworks/weave/ipam/paxos" - "github.com/weaveworks/weave/ipam/ring" - "github.com/weaveworks/weave/ipam/space" - "github.com/weaveworks/weave/mesh" "github.com/weaveworks/weave/net/address" ) @@ -13,21 +10,18 @@ type Status struct { Range string RangeNumIPs int DefaultSubnet string - Ring *ring.Ring // information on ranges owned by all peers - Space space.Space // more detail on ranges owned by us - Owned map[string][]address.Address // addresses by container-ID - OurName mesh.PeerName - Nicknames map[mesh.PeerName]string `json:"-"` - IsKnownPeer func(mesh.PeerName) bool `json:"-"` Entries []EntryStatus PendingClaims []ClaimStatus PendingAllocates []string } type EntryStatus struct { - Token string - Peer string - Version uint32 + Token string + Size uint32 + Peer string + Nickname string + IsKnownPeer bool + Version uint32 } type ClaimStatus struct { @@ -52,12 +46,6 @@ func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status { allocator.universe.String(), int(allocator.universe.Size()), defaultSubnet.String(), - allocator.ring, - allocator.space, - allocator.owned, - allocator.ourName, - allocator.nicknames, - allocator.isKnownPeer, newEntryStatusSlice(allocator), newClaimStatusSlice(allocator), newAllocateIdentSlice(allocator)} @@ -73,8 +61,15 @@ func newEntryStatusSlice(allocator *Allocator) []EntryStatus { return slice } - for _, entry := range allocator.ring.Entries { - slice = append(slice, EntryStatus{entry.Token.String(), entry.Peer.String(), entry.Version}) + for _, r := range allocator.ring.AllRangeInfo() { + slice = append(slice, EntryStatus{ + Token: r.Start.String(), + Size: uint32(r.Size()), + Peer: r.Peer.String(), + Nickname: allocator.nicknames[r.Peer], + IsKnownPeer: allocator.isKnownPeer(r.Peer), + Version: r.Version, + }) } return slice diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 8db1d425..10b542d4 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -33,72 +33,59 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ } return strings.Join(servers, ", ") }, - "printIPAMRanges": func(status ipam.Status) string { + "printIPAMRanges": func(router weave.NetworkRouterStatus, status ipam.Status) string { var buffer bytes.Buffer type stats struct { - Ranges []address.Range - Reachable bool + ips uint32 + nickname string + reachable bool } - peerStats := make(map[mesh.PeerName]*stats) + peerStats := make(map[string]*stats) - for peer, ranges := range status.Ring.OwnedRangesByPeer() { - s, found := peerStats[peer] + for _, entry := range status.Entries { + s, found := peerStats[entry.Peer] if !found { - s = &stats{Reachable: status.IsKnownPeer(peer)} - peerStats[peer] = s + s = &stats{nickname: entry.Nickname, reachable: entry.IsKnownPeer} + peerStats[entry.Peer] = s } - s.Ranges = append(s.Ranges, ranges...) + s.ips += entry.Size } - appendOwned := func(peer mesh.PeerName, nickName string, reachable bool, ranges []address.Range) { + printOwned := func(name string, nickName string, reachable bool, ips uint32) { reachableStr := "" if !reachable { reachableStr = "- unreachable!" } - ipsInRange := 0 - for _, chunk := range ranges { - ipsInRange += int(chunk.Size()) - } - percentageRanges := float32(ipsInRange) * 100.0 / float32(status.RangeNumIPs) + percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs) - displayName := peer.String() + "(" + nickName + ")" - fmt.Fprintf(&buffer, "%20s: %8d IPs (%04.1f%% of total) %s\n", - displayName, ipsInRange, percentageRanges, reachableStr) + displayName := name + " (" + nickName + ")" + fmt.Fprintf(&buffer, "%30s: %8d IPs (%04.1f%% of total) %s\n", + displayName, ips, percentageRanges, reachableStr) } - // print the local addresses - if ourStats := peerStats[status.OurName]; ourStats != nil { - appendOwned(status.OurName, "local", true, ourStats.Ranges) + // print the local info first + if ourStats := peerStats[router.Name]; ourStats != nil { + printOwned(router.Name, "local", true, ourStats.ips) } // and then the rest for peer, stats := range peerStats { - if peer != status.OurName { - nickname, found := status.Nicknames[peer] - if !found { - nickname = peer.String() - } - appendOwned(peer, nickname, stats.Reachable, stats.Ranges) + if peer != router.Name { + printOwned(peer, stats.nickname, stats.reachable, stats.ips) } } return buffer.String() }, - "printIPAMWarning": func(status ipam.Status) string { - ipsReachable := 0 - for peer, ranges := range status.Ring.OwnedRangesByPeer() { - if status.IsKnownPeer(peer) { - for _, chunk := range ranges { - ipsReachable += int(chunk.Size()) - } + "allIPAMOwnersUnreachable": func(status ipam.Status) bool { + for _, entry := range status.Entries { + if entry.Size > 0 && entry.IsKnownPeer { + return false } } - if ipsReachable == 0 { - return "- all IPs owned by unreachable peers!" - } - return "" + return true }, "printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string { counts := make(map[string]int) @@ -170,7 +157,11 @@ var statusTemplate = defTemplate("status", `\ Service: ipam {{if .IPAM.Entries}}\ - Consensus: achieved {{printIPAMWarning .IPAM}} +{{if allIPAMOwnersUnreachable .IPAM}}\ + Halted: all IPs owned by unreachable peers +{{else}}\ + Consensus: achieved +{{end}}\ {{else if .IPAM.Paxos}}\ Consensus: waiting (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}}) {{else}}\ @@ -221,7 +212,7 @@ var dnsEntriesTemplate = defTemplate("dnsEntries", `\ {{end}}\ `) -var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .IPAM}}`) +var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}}`) type WeaveStatus struct { Version string From cb65a80dce23a197f56d75c695950a9668fff761 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 24 Nov 2015 10:48:30 +0000 Subject: [PATCH 07/10] Reworded IPAM service description in `weave status` following review in #1702 --- prog/weaver/http.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 10b542d4..1e7c0480 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -60,14 +60,14 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ } percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs) - displayName := name + " (" + nickName + ")" - fmt.Fprintf(&buffer, "%30s: %8d IPs (%04.1f%% of total) %s\n", + displayName := name + " (" + nickName + "):" + fmt.Fprintf(&buffer, "%-32s %8d IPs (%04.1f%% of total) %s\n", displayName, ips, percentageRanges, reachableStr) } // print the local info first if ourStats := peerStats[router.Name]; ourStats != nil { - printOwned(router.Name, "local", true, ourStats.ips) + printOwned(router.Name, ourStats.nickname, true, ourStats.ips) } // and then the rest @@ -158,14 +158,16 @@ var statusTemplate = defTemplate("status", `\ Service: ipam {{if .IPAM.Entries}}\ {{if allIPAMOwnersUnreachable .IPAM}}\ - Halted: all IPs owned by unreachable peers + Status: all IP ranges owned by unreachable peers - use 'rmpeer' if they are dead +{{else if len .IPAM.PendingAllocates}}\ + Status: waiting for IP range grant from peers {{else}}\ - Consensus: achieved + Status: ready {{end}}\ {{else if .IPAM.Paxos}}\ - Consensus: waiting (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}}) + Status: awaiting consensus (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}}) {{else}}\ - Consensus: deferred + Status: idle {{end}}\ Range: {{.IPAM.Range}} DefaultSubnet: {{.IPAM.DefaultSubnet}} From 2fbbb802bd96a159e8a32644650c8bf6c35e756f Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 24 Nov 2015 10:36:21 +0000 Subject: [PATCH 08/10] Don't assert invariants when printing status - if it's broken you might appreciate being able to print it out --- ipam/ring/ring.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/ipam/ring/ring.go b/ipam/ring/ring.go index b7b948c3..2e384eca 100644 --- a/ipam/ring/ring.go +++ b/ipam/ring/ring.go @@ -324,8 +324,6 @@ type RangeInfo struct { } func (r *Ring) AllRangeInfo() (result []RangeInfo) { - r.assertInvariants() - for i, entry := range r.Entries { nextEntry := r.Entries.entry(i + 1) ranges := []address.Range{{Start: entry.Token, End: nextEntry.Token}} From 8bbf8231d20e4b2d009c9d5d407c286332afecba Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 24 Nov 2015 11:15:46 +0000 Subject: [PATCH 09/10] Show which range is being allocated in `weave report` --- ipam/status.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ipam/status.go b/ipam/status.go index 57af14a9..e7a252ba 100644 --- a/ipam/status.go +++ b/ipam/status.go @@ -1,6 +1,7 @@ package ipam import ( + "fmt" "github.com/weaveworks/weave/ipam/paxos" "github.com/weaveworks/weave/net/address" ) @@ -88,7 +89,7 @@ func newAllocateIdentSlice(allocator *Allocator) []string { var slice []string for _, op := range allocator.pendingAllocates { allocate := op.(*allocate) - slice = append(slice, allocate.ident) + slice = append(slice, fmt.Sprintf("%s %s", allocate.ident, allocate.r.String())) } return slice } From 7e0e1fbaad92952f674e6b8ad64cd3232331069c Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 30 Nov 2015 12:07:59 +0000 Subject: [PATCH 10/10] Adjust formatting after review feedback; hostnames up to 14 chars will now align --- prog/weaver/http.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 1e7c0480..1dc84925 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -60,8 +60,8 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{ } percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs) - displayName := name + " (" + nickName + "):" - fmt.Fprintf(&buffer, "%-32s %8d IPs (%04.1f%% of total) %s\n", + displayName := name + "(" + nickName + ")" + fmt.Fprintf(&buffer, "%-37v %8d IPs (%04.1f%% of total) %s\n", displayName, ips, percentageRanges, reachableStr) } @@ -198,7 +198,7 @@ var peersTemplate = defTemplate("peers", `\ {{.Name}}({{.NickName}}) {{range .Connections}}\ {{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} \ -{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-32v" $nameNickName}} \ +{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-37v" $nameNickName}} \ {{if .Established}}established{{else}}pending{{end}} {{end}}\ {{end}}\