new weave status, weave status ..., and weave report

This commit is contained in:
Adam Harrison authored and Matthias Radestock committed 2015-08-11 12:15:13 +01:00
1 parent 00ecff09f7
commit fc9a1c8664
27 files changed
+784 -493

No files matched your search

-5
View File
@@ -10,7 +10,6 @@ import (
// A subsystem/server/... that can be stopped or queried about the status with a signal
type SignalReceiver interface {
Stop() error
Status() string
}
func SignalHandlerLoop(ss ...SignalReceiver) {
@@ -28,10 +27,6 @@ func SignalHandlerLoop(ss ...SignalReceiver) {
case syscall.SIGQUIT:
stacklen := runtime.Stack(buf, true)
Log.Infof("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end", buf[:stacklen])
case syscall.SIGUSR1:
for _, subsystem := range ss {
Log.Infof("=== received SIGUSR1 ===\n*** status...\n%s\n*** end", subsystem.Status())
}
}
}
}
+12
View File
@@ -1,8 +1,20 @@
package common
import (
"strings"
)
// Assert test is true, panic otherwise
func Assert(test bool) {
if !test {
panic("Assertion failure")
}
}
func ErrorMessages(errors []error) string {
var result []string
for _, err := range errors {
result = append(result, err.Error())
}
return strings.Join(result, "\n")
}
-4
View File
@@ -62,10 +62,6 @@ func (g *allocate) Cancel() {
g.resultChan <- allocateResult{0, fmt.Errorf("Allocate request for %s cancelled", g.ident)}
}
func (g *allocate) String() string {
return fmt.Sprintf("Allocate for %s", g.ident)
}
func (g *allocate) ForContainer(ident string) bool {
return g.ident == ident
}
-35
View File
@@ -33,8 +33,6 @@ type operation interface {
Cancel()
String() string
// Does this operation pertain to the given container id?
// Used for tidying up pending operations when containers die.
ForContainer(ident string) bool
@@ -275,15 +273,6 @@ func (alloc *Allocator) Free(ident string, addrToFree address.Address) error {
return <-errChan
}
// Sync.
func (alloc *Allocator) String() string {
resultChan := make(chan string)
alloc.actionChan <- func() {
resultChan <- alloc.string()
}
return <-resultChan
}
// Shutdown (Sync)
func (alloc *Allocator) Shutdown() {
alloc.infof("Shutdown")
@@ -493,30 +482,6 @@ func (alloc *Allocator) actorLoop(actionChan <-chan func()) {
// Helper functions
func (alloc *Allocator) string() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "Allocator range %s", alloc.universe)
if alloc.ring.Empty() {
if alloc.paxosTicker != nil {
fmt.Fprintf(&buf, " awaiting consensus: %s", alloc.paxos.String())
}
} else {
fmt.Fprint(&buf, "\nOwned Ranges:")
alloc.ring.FprintWithNicknames(&buf, alloc.nicknames)
}
if len(alloc.pendingAllocates)+len(alloc.pendingClaims) > 0 {
fmt.Fprintf(&buf, "\nPending requests:")
for _, op := range alloc.pendingAllocates {
fmt.Fprintf(&buf, "\n %s", op.String())
}
for _, op := range alloc.pendingClaims {
fmt.Fprintf(&buf, "\n %s", op.String())
}
}
return buf.String()
}
// Ensure we are making progress towards an established ring
func (alloc *Allocator) establishRing() {
if !alloc.ring.Empty() || alloc.paxosTicker != nil {
-4
View File
@@ -98,10 +98,6 @@ func (c *claim) Cancel() {
c.sendResult(fmt.Errorf("Operation cancelled."))
}
func (c *claim) String() string {
return fmt.Sprintf("Claim %s -> %s", c.ident, c.addr.String())
}
func (c *claim) ForContainer(ident string) bool {
return c.ident == ident
}
+9 -6
View File
@@ -1,8 +1,6 @@
package paxos
import (
"fmt"
"github.com/weaveworks/weave/router"
)
@@ -252,9 +250,14 @@ func (node *Node) Consensus() (bool, AcceptedValue) {
return false, AcceptedValue{}
}
func (node *Node) String() string {
if ok, val := node.Consensus(); ok {
return fmt.Sprintf("Consensus reached with size %d", len(val.Value))
type Status struct {
KnownNodes int
Quorum uint
}
func NewStatus(node *Node) *Status {
if node == nil {
return nil
}
return fmt.Sprintf("Nodes known: %d, Quorum size: %d", len(node.knows), node.quorum)
return &Status{len(node.knows), node.quorum}
}
+82
View File
@@ -0,0 +1,82 @@
package ipam
import (
"github.com/weaveworks/weave/ipam/paxos"
"github.com/weaveworks/weave/net/address"
)
type Status struct {
Paxos *paxos.Status
Range string
DefaultSubnet string
Entries []EntryStatus
PendingClaims []ClaimStatus
PendingAllocates []string
}
type EntryStatus struct {
Token string
Peer string
Version uint32
}
type ClaimStatus struct {
Ident string
Address address.Address
}
func NewStatus(allocator *Allocator, defaultSubnet address.CIDR) *Status {
if allocator == nil {
return nil
}
var paxosStatus *paxos.Status
if allocator.paxosTicker != nil {
paxosStatus = paxos.NewStatus(allocator.paxos)
}
resultChan := make(chan *Status)
allocator.actionChan <- func() {
resultChan <- &Status{
paxosStatus,
allocator.universe.String(),
defaultSubnet.String(),
newEntryStatusSlice(allocator),
newClaimStatusSlice(allocator),
newAllocateIdentSlice(allocator)}
}
return <-resultChan
}
func newEntryStatusSlice(allocator *Allocator) []EntryStatus {
var slice []EntryStatus
if allocator.ring.Empty() {
return slice
}
for _, entry := range allocator.ring.Entries {
slice = append(slice, EntryStatus{entry.Token.String(), entry.Peer.String(), entry.Version})
}
return slice
}
func newClaimStatusSlice(allocator *Allocator) []ClaimStatus {
var slice []ClaimStatus
for _, op := range allocator.pendingClaims {
claim := op.(*claim)
slice = append(slice, ClaimStatus{claim.ident, claim.addr})
}
return slice
}
func newAllocateIdentSlice(allocator *Allocator) []string {
var slice []string
for _, op := range allocator.pendingAllocates {
allocate := op.(*allocate)
slice = append(slice, allocate.ident)
}
return slice
}
-17
View File
@@ -185,23 +185,6 @@ func (n *Nameserver) deleteTombstones() {
})
}
func (n *Nameserver) String() string {
n.RLock()
defer n.RUnlock()
var buf bytes.Buffer
for _, entry := range n.entries {
if entry.Tombstone > 0 {
continue
}
containerid := entry.ContainerID
if len(containerid) > 12 {
containerid = containerid[:12]
}
fmt.Fprintf(&buf, "%s: %s [%s]\n", containerid, entry.Hostname, entry.Addr.String())
}
return buf.String()
}
func (n *Nameserver) Gossip() router.GossipData {
n.RLock()
defer n.RUnlock()
+43
View File
@@ -0,0 +1,43 @@
package nameserver
type Status struct {
Domain string
Address string
TTL uint32
Entries []EntryStatus
}
type EntryStatus struct {
Hostname string
Origin string
ContainerID string
Address string
Version int
Tombstone int64
}
func NewStatus(ns *Nameserver, dnsServer *DNSServer) *Status {
if dnsServer == nil {
return nil
}
ns.RLock()
defer ns.RUnlock()
var entryStatusSlice []EntryStatus
for _, entry := range ns.entries {
entryStatusSlice = append(entryStatusSlice, EntryStatus{
entry.Hostname,
entry.Origin.String(),
entry.ContainerID,
entry.Addr.String(),
entry.Version,
entry.Tombstone})
}
return &Status{
dnsServer.domain,
dnsServer.address,
dnsServer.ttl,
entryStatusSlice}
}
+174 -20
View File
@@ -1,44 +1,198 @@
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/mux"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/ipam"
"github.com/weaveworks/weave/nameserver"
"github.com/weaveworks/weave/net/address"
weave "github.com/weaveworks/weave/router"
"net/http"
"strings"
"text/template"
)
func HandleHTTP(muxRouter *mux.Router,
router *weave.Router,
allocator *ipam.Allocator,
defaultSubnet address.CIDR,
ns *nameserver.Nameserver,
dnsserver *nameserver.DNSServer) {
var rootTemplate = template.New("root").Funcs(map[string]interface{}{
"countDNSEntries": func(entries []nameserver.EntryStatus) int {
count := 0
for _, entry := range entries {
if entry.Tombstone == 0 {
count++
}
}
return count
},
"printConnectionCounts": func(conns []weave.LocalConnectionStatus) string {
counts := make(map[string]int)
for _, conn := range conns {
counts[conn.State]++
}
return printCounts(counts, []string{"established", "pending", "retrying", "failed", "connecting"})
},
"printPeerConnectionCounts": func(peers []weave.PeerStatus) string {
counts := make(map[string]int)
for _, peer := range peers {
for _, conn := range peer.Connections {
if conn.Established {
counts["established"]++
} else {
counts["pending"]++
}
}
}
return printCounts(counts, []string{"established", "pending"})
},
"printState": func(enabled bool) string {
if enabled {
return "enabled"
}
return "disabled"
},
"trimSuffix": strings.TrimSuffix,
})
muxRouter.Methods("GET").Path("/status").Headers("Accept", "application/json").HandlerFunc(
// Print counts in a specified order
func printCounts(counts map[string]int, keys []string) string {
var stringCounts []string
for _, key := range keys {
if count, ok := counts[key]; ok {
stringCounts = append(stringCounts, fmt.Sprintf("%d %s", count, key))
}
}
return strings.Join(stringCounts, ", ")
}
// Strip escaped newlines from template
func escape(template string) string {
return strings.Replace(template, "\\\n", "", -1)
}
// Define a named template panicking on error
func defTemplate(name string, text string) *template.Template {
return template.Must(rootTemplate.New(name).Parse(escape(text)))
}
var statusTemplate = defTemplate("status", `\
Version: {{.Version}}
Service: router
Protocol: {{.Router.Protocol}} \
{{if eq .Router.ProtocolMinVersion .Router.ProtocolMaxVersion}}\
{{.Router.ProtocolMaxVersion}}\
{{else}}\
{{.Router.ProtocolMinVersion}}..{{.Router.ProtocolMaxVersion}}\
{{end}}
Name: {{.Router.Name}}({{.Router.NickName}})
Encryption: {{printState .Router.Encryption}}
PeerDiscovery: {{printState .Router.PeerDiscovery}}
Targets: {{len .Router.Targets}}
Connections: {{len .Router.Connections}}{{with printConnectionCounts .Router.Connections}} ({{.}}){{end}}
Peers: {{len .Router.Peers}}{{with printPeerConnectionCounts .Router.Peers}} (with {{.}} connections between them){{end}}
{{if .IPAM}}\
Service: ipam
{{if .IPAM.Entries}}\
Consensus: achieved
{{else if .IPAM.Paxos}}\
Consensus: waiting (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}})
{{else}}\
Consensus: deferred
{{end}}\
Range: {{.IPAM.Range}}
DefaultSubnet: {{.IPAM.DefaultSubnet}}
{{end}}\
{{if .DNS}}\
Service: dns
Domain: {{.DNS.Domain}}
TTL: {{.DNS.TTL}}
Entries: {{countDNSEntries .DNS.Entries}}
{{end}}\
`)
var targetsTemplate = defTemplate("targetsTemplate", `\
{{range .Router.Targets}}{{.}}
{{end}}\
`)
var connectionsTemplate = defTemplate("connectionsTemplate", `\
{{range .Router.Connections}}\
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}}
{{end}}\
`)
var peersTemplate = defTemplate("peers", `\
{{range .Router.Peers}}\
{{.Name}}({{.NickName}})
{{range .Connections}}\
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} \
{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-32v" $nameNickName}} \
{{if .Established}}established{{else}}pending{{end}}
{{end}}\
{{end}}\
`)
var dnsEntriesTemplate = defTemplate("dnsEntries", `\
{{$domain := printf ".%v" .DNS.Domain}}\
{{range .DNS.Entries}}\
{{if eq .Tombstone 0}}\
{{$hostname := trimSuffix .Hostname $domain}}\
{{printf "%-12v" $hostname}} {{printf "%-15v" .Address}} {{printf "%12.12v" .ContainerID}} {{.Origin}}
{{end}}\
{{end}}\
`)
type WeaveStatus struct {
Version string
Router *weave.Status `json:"Router,omitempty"`
IPAM *ipam.Status `json:"IPAM,omitempty"`
DNS *nameserver.Status `json:"DNS,omitempty"`
}
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.Router, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
status := func() WeaveStatus {
return WeaveStatus{
version,
weave.NewStatus(router),
ipam.NewStatus(allocator, defaultSubnet),
nameserver.NewStatus(ns, dnsserver)}
}
muxRouter.Methods("GET").Path("/report").Headers("Accept", "application/json").HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
json, _ := router.StatusJSON(version)
json, _ := json.MarshalIndent(status(), "", " ")
w.Header().Set("Content-Type", "application/json")
w.Write(json)
})
muxRouter.Methods("GET").Path("/status").HandlerFunc(
muxRouter.Methods("GET").Path("/report").Queries("format", "{format}").HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "weave router", version)
fmt.Fprintln(w, router.Status())
if allocator != nil {
fmt.Fprintln(w, allocator.String())
fmt.Fprintln(w, "Allocator default subnet:", defaultSubnet)
formatTemplate, err := template.New("format").Parse(mux.Vars(r)["format"])
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Fprintln(w, "")
if dnsserver == nil {
fmt.Fprintln(w, "WeaveDNS is disabled")
} else {
fmt.Fprintln(w, dnsserver.String())
fmt.Fprintln(w, ns.String())
if err := formatTemplate.Execute(w, status()); err != nil {
http.Error(w, "error during template execution", http.StatusInternalServerError)
Log.Error(err)
}
})
defHandler := func(path string, template *template.Template) {
muxRouter.Methods("GET").Path(path).HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if err := template.Execute(w, status()); err != nil {
http.Error(w, "error during template execution", http.StatusInternalServerError)
Log.Error(err)
}
})
}
defHandler("/status", statusTemplate)
defHandler("/status/targets", targetsTemplate)
defHandler("/status/connections", connectionsTemplate)
defHandler("/status/peers", peersTemplate)
defHandler("/status/dns", dnsEntriesTemplate)
}
+13 -28
View File
@@ -193,27 +193,29 @@ func main() {
router.Start()
if errors := router.ConnectionMaker.InitiateConnections(peers, false); len(errors) > 0 {
Log.Fatal(errorMessages(errors))
Log.Fatal(ErrorMessages(errors))
}
// The weave script always waits for a status call to succeed,
// so there is no point in doing "weave launch --http-addr ''".
// This is here to support stand-alone use of weaver.
if httpAddr != "" {
go handleHTTP(router, httpAddr, allocator, defaultSubnet, dockerCli, ns, dnsserver)
muxRouter := mux.NewRouter()
if allocator != nil {
allocator.HandleHTTP(muxRouter, defaultSubnet, dockerCli)
}
if ns != nil {
ns.HandleHTTP(muxRouter)
}
router.HandleHTTP(muxRouter)
HandleHTTP(muxRouter, version, router, allocator, defaultSubnet, ns, dnsserver)
http.Handle("/", muxRouter)
go listenAndServeHTTP(httpAddr, muxRouter)
}
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)
mflag.Visit(func(f *mflag.Flag) {
@@ -304,23 +306,7 @@ func determineQuorum(initPeerCountFlag int, peers []string) uint {
return quorum
}
func handleHTTP(router *weave.Router, httpAddr string, allocator *ipam.Allocator, defaultSubnet address.CIDR, docker *docker.Client, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
muxRouter := mux.NewRouter()
if allocator != nil {
allocator.HandleHTTP(muxRouter, defaultSubnet, docker)
}
if ns != nil {
ns.HandleHTTP(muxRouter)
}
router.HandleHTTP(muxRouter)
HandleHTTP(muxRouter, router, allocator, defaultSubnet, ns, dnsserver)
http.Handle("/", muxRouter)
func listenAndServeHTTP(httpAddr string, muxRouter *mux.Router) {
protocol := "tcp"
if strings.HasPrefix(httpAddr, "/") {
os.Remove(httpAddr) // in case it's there from last time
@@ -330,7 +316,6 @@ func handleHTTP(router *weave.Router, httpAddr string, allocator *ipam.Allocator
if err != nil {
Log.Fatal("Unable to create http listener socket: ", err)
}
err = http.Serve(l, nil)
if err != nil {
Log.Fatal("Unable to create http server", err)
-12
View File
@@ -89,18 +89,6 @@ func (conn *RemoteConnection) ErrorLog(args ...interface{}) {
log.Errorln(append(append([]interface{}{}, fmt.Sprintf("->[%s|%s]:", conn.remoteTCPAddr, conn.remote)), args...)...)
}
func (conn *RemoteConnection) String() string {
from := "<nil>"
if conn.local != nil {
from = conn.local.String()
}
to := "<nil>"
if conn.remote != nil {
to = conn.remote.String()
}
return fmt.Sprint("Connection ", from, "->", to)
}
// Does not return anything. If the connection is successful, it will
// end up in the local peer's connections map.
func StartLocalConnection(connRemote *RemoteConnection, tcpConn *net.TCPConn, udpAddr *net.UDPAddr, router *Router, acceptNewPeer bool) {
-53
View File
@@ -1,7 +1,6 @@
package router
import (
"bytes"
"fmt"
"math/rand"
"net"
@@ -104,58 +103,6 @@ func (cm *ConnectionMaker) Refresh() {
cm.actionChan <- func() bool { return true }
}
func (cm *ConnectionMaker) Status() ConnectionMakerStatus {
// We need to Refresh first in order to clear out any 'attempting'
// connections from cm.targets that have been established since
// the last run of cm.checkStateAndAttemptConnections. These
// entries are harmless but do represent stale state that we do
// not want to report.
cm.Refresh()
resultChan := make(chan ConnectionMakerStatus, 0)
cm.actionChan <- func() bool {
status := ConnectionMakerStatus{
DirectPeers: []string{},
Reconnects: make(map[string]Target),
}
for peer := range cm.directPeers {
status.DirectPeers = append(status.DirectPeers, peer)
}
for address, target := range cm.targets {
status.Reconnects[address] = *target
}
resultChan <- status
return false
}
return <-resultChan
}
type ConnectionMakerStatus struct {
DirectPeers []string
Reconnects map[string]Target
}
func (status ConnectionMakerStatus) String() string {
var buf bytes.Buffer
fmt.Fprint(&buf, "Direct Peers:")
for _, peer := range status.DirectPeers {
fmt.Fprintf(&buf, " %s", peer)
}
fmt.Fprintln(&buf, "\nReconnects:")
for address, target := range status.Reconnects {
fmt.Fprintf(&buf, "->[%s]", address)
if target.lastError != nil {
fmt.Fprintf(&buf, " (%s)", target.lastError)
}
if target.attempting {
fmt.Fprintf(&buf, " trying since %v\n", target.tryAfter)
} else {
fmt.Fprintf(&buf, " next try at %v\n", target.tryAfter)
}
}
return buf.String()
}
func (cm *ConnectionMaker) queryLoop(actionChan <-chan ConnectionMakerAction) {
timer := time.NewTimer(MaxDuration)
run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) }
+2 -10
View File
@@ -3,18 +3,10 @@ package router
import (
"fmt"
"github.com/gorilla/mux"
"github.com/weaveworks/weave/common"
"net/http"
"strings"
)
func errorMessages(errors []error) string {
var result []string
for _, err := range errors {
result = append(result, err.Error())
}
return strings.Join(result, "\n")
}
func (router *Router) HandleHTTP(muxRouter *mux.Router) {
muxRouter.Methods("POST").Path("/connect").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -22,7 +14,7 @@ func (router *Router) HandleHTTP(muxRouter *mux.Router) {
http.Error(w, fmt.Sprint("unable to parse form: ", err), http.StatusBadRequest)
}
if errors := router.ConnectionMaker.InitiateConnections(r.Form["peer"], r.FormValue("replace") == "true"); len(errors) > 0 {
http.Error(w, errorMessages(errors), http.StatusBadRequest)
http.Error(w, common.ErrorMessages(errors), http.StatusBadRequest)
}
})
-116
View File
@@ -1,116 +0,0 @@
package router
import (
"encoding/json"
"fmt"
"time"
)
func (router *Router) StatusJSON(version string) ([]byte, error) {
return json.Marshal(struct {
Version string
Encryption bool
PeerDiscovery bool
Name string
NickName string
Interface string
Macs *MacCache
Peers *Peers
Routes *Routes
ConnectionMakerStatus
}{version, router.UsingPassword(), router.PeerDiscovery, router.Ourself.Name.String(), router.Ourself.NickName, fmt.Sprintf("%v", router.Iface), router.Macs, router.Peers, router.Routes, router.ConnectionMaker.Status()})
}
func (cache *MacCache) MarshalJSON() ([]byte, error) {
type cacheEntry struct {
Mac string
Name string
NickName string
LastSeen time.Time
}
var entries []*cacheEntry
for key, entry := range cache.table {
entries = append(entries, &cacheEntry{intmac(key).String(), entry.peer.Name.String(), entry.peer.NickName, entry.lastSeen})
}
return json.Marshal(entries)
}
func (peers *Peers) MarshalJSON() ([]byte, error) {
type p struct {
Name string
NickName string
UID PeerUID
Version uint64
Connections []Connection
}
var ps []*p
peers.ForEach(func(peer *Peer) {
var connections []Connection
if peer == peers.ourself.Peer {
for conn := range peers.ourself.Connections() {
connections = append(connections, conn)
}
} else {
// Modifying peer.connections requires a write lock on
// Peers, and since we are holding a read lock (due to the
// ForEach), access without locking the peer is safe.
for _, conn := range peer.connections {
connections = append(connections, conn)
}
}
ps = append(ps, &p{peer.Name.String(), peer.NickName, peer.UID, peer.version, connections})
})
return json.Marshal(ps)
}
func (routes *Routes) MarshalJSON() ([]byte, error) {
routes.RLock()
defer routes.RUnlock()
type uni struct {
Dest, Via PeerName
}
type broad struct {
Source PeerName
Via []PeerName
}
var r struct {
Unicast []*uni
Broadcast []*broad
}
for name, hop := range routes.unicast {
r.Unicast = append(r.Unicast, &uni{name, hop})
}
for name, hops := range routes.broadcast {
r.Broadcast = append(r.Broadcast, &broad{name, hops})
}
return json.Marshal(r)
}
func (conn *RemoteConnection) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Name string
NickName string
TCPAddr string
}{conn.Remote().Name.String(), conn.Remote().NickName, conn.RemoteTCPAddr()})
}
func (name PeerName) MarshalJSON() ([]byte, error) {
return json.Marshal(name.String())
}
func (target Target) MarshalJSON() ([]byte, error) {
t := struct {
Attempting bool `json:"Attempting,omitempty"`
TryAfter time.Time `json:"TryAfter,omitempty"`
TryInterval string `json:"TryInterval,omitempty"`
LastError string `json:"LastError,omitempty"`
}{
Attempting: target.attempting,
TryAfter: target.tryAfter,
TryInterval: target.tryInterval.String(),
}
if target.lastError != nil {
t.LastError = target.lastError.Error()
}
return json.Marshal(t)
}
-12
View File
@@ -1,8 +1,6 @@
package router
import (
"bytes"
"fmt"
"net"
"sync"
"time"
@@ -82,16 +80,6 @@ func (cache *MacCache) Delete(peer *Peer) bool {
return found
}
func (cache *MacCache) String() string {
var buf bytes.Buffer
cache.RLock()
defer cache.RUnlock()
for key, entry := range cache.table {
fmt.Fprintf(&buf, "%v -> %s (%v)\n", intmac(key), entry.peer, entry.lastSeen)
}
return buf.String()
}
func (cache *MacCache) setExpiryTimer() {
cache.expiryTimer = time.AfterFunc(cache.maxAge/10, func() { cache.expire() })
}
-29
View File
@@ -3,7 +3,6 @@ package router
import (
"bytes"
"encoding/gob"
"fmt"
"io"
"sync"
)
@@ -170,34 +169,6 @@ func (peers *Peers) GarbageCollect() []*Peer {
return removed
}
func (peers *Peers) String() string {
var buf bytes.Buffer
printConnection := func(conn Connection) {
established := ""
if !conn.Established() {
established = " (unestablished)"
}
fmt.Fprintf(&buf, " -> %s [%v%s]\n", conn.Remote(), conn.RemoteTCPAddr(), established)
}
peers.ForEach(func(peer *Peer) {
if peer == peers.ourself.Peer {
fmt.Fprintln(&buf, peers.ourself.Info())
for conn := range peers.ourself.Connections() {
printConnection(conn)
}
} else {
fmt.Fprintln(&buf, peer.Info())
// Modifying peer.connections requires a write lock on
// Peers, and since we are holding a read lock (due to the
// ForEach), access without locking the peer is safe.
for _, conn := range peer.connections {
printConnection(conn)
}
}
})
return buf.String()
}
func (peers *Peers) garbageCollect() []*Peer {
removed := []*Peer{}
peers.ourself.RLock()
-20
View File
@@ -115,26 +115,6 @@ func (router *Router) UsingPassword() bool {
return router.Password != nil
}
func (router *Router) Status() string {
var buf bytes.Buffer
fmt.Fprintln(&buf, "Our name is", router.Ourself)
fmt.Fprintln(&buf, "Encryption", onOff(router.UsingPassword()))
fmt.Fprintln(&buf, "Peer discovery", onOff(router.PeerDiscovery))
fmt.Fprintln(&buf, "Sniffing traffic on", router.Iface)
fmt.Fprintf(&buf, "MACs:\n%s", router.Macs)
fmt.Fprintf(&buf, "Peers:\n%s", router.Peers)
fmt.Fprintf(&buf, "Routes:\n%s", router.Routes)
fmt.Fprint(&buf, router.ConnectionMaker.Status())
return buf.String()
}
func onOff(b bool) string {
if b {
return "on"
}
return "off"
}
func (router *Router) sniff(pio PacketSourceSink) {
log.Println("Sniffing traffic on", router.Iface)
-19
View File
@@ -1,8 +1,6 @@
package router
import (
"bytes"
"fmt"
"math"
"sync"
)
@@ -109,23 +107,6 @@ func (routes *Routes) RandomNeighbours(except PeerName) PeerNameSet {
return res
}
func (routes *Routes) String() string {
var buf bytes.Buffer
routes.RLock()
defer routes.RUnlock()
fmt.Fprintln(&buf, "unicast:")
for name, hop := range routes.unicast {
fmt.Fprintf(&buf, "%s -> %s\n", name, hop)
}
fmt.Fprintln(&buf, "broadcast:")
for name, hops := range routes.broadcast {
fmt.Fprintf(&buf, "%s -> %v\n", name, hops)
}
// We don't include the 'all' routes here since they are of
// limited utility in troubleshooting
return buf.String()
}
// Request recalculation of the routing table. This is async but can
// effectively be made synchronous with a subsequent call to
// EnsureRecalculated.
+215
View File
@@ -0,0 +1,215 @@
package router
import (
"time"
)
type Status struct {
Protocol string
ProtocolMinVersion int
ProtocolMaxVersion int
Encryption bool
PeerDiscovery bool
Name string
NickName string
Port int
Interface string
MACs []MACStatus
Peers []PeerStatus
UnicastRoutes []UnicastRouteStatus
BroadcastRoutes []BroadcastRouteStatus
Connections []LocalConnectionStatus
Targets []string
}
type MACStatus struct {
Mac string
Name string
NickName string
LastSeen time.Time
}
type PeerStatus struct {
Name string
NickName string
UID PeerUID
Version uint64
Connections []ConnectionStatus
}
type ConnectionStatus struct {
Name string
NickName string
Address string
Outbound bool
Established bool
}
type UnicastRouteStatus struct {
Dest, Via string
}
type BroadcastRouteStatus struct {
Source string
Via []string
}
type LocalConnectionStatus struct {
Address string
Outbound bool
State string
Info string
}
func NewStatus(router *Router) *Status {
var ifaceName string
if router.Iface != nil {
ifaceName = router.Iface.Name
}
return &Status{
Protocol,
ProtocolMinVersion,
ProtocolMaxVersion,
router.UsingPassword(),
router.PeerDiscovery,
router.Ourself.Name.String(),
router.Ourself.NickName,
router.Port,
ifaceName,
NewMACStatusSlice(router.Macs),
NewPeerStatusSlice(router.Peers),
NewUnicastRouteStatusSlice(router.Routes),
NewBroadcastRouteStatusSlice(router.Routes),
NewLocalConnectionStatusSlice(router.ConnectionMaker),
NewTargetSlice(router.ConnectionMaker)}
}
func NewMACStatusSlice(cache *MacCache) []MACStatus {
cache.RLock()
defer cache.RUnlock()
var slice []MACStatus
for key, entry := range cache.table {
slice = append(slice, MACStatus{
intmac(key).String(),
entry.peer.Name.String(),
entry.peer.NickName,
entry.lastSeen})
}
return slice
}
func NewPeerStatusSlice(peers *Peers) []PeerStatus {
var slice []PeerStatus
peers.ForEach(func(peer *Peer) {
var connections []ConnectionStatus
if peer == peers.ourself.Peer {
for conn := range peers.ourself.Connections() {
connections = append(connections, newConnectionStatus(conn))
}
} else {
// Modifying peer.connections requires a write lock on
// Peers, and since we are holding a read lock (due to the
// ForEach), access without locking the peer is safe.
for _, conn := range peer.connections {
connections = append(connections, newConnectionStatus(conn))
}
}
slice = append(slice, PeerStatus{
peer.Name.String(),
peer.NickName,
peer.UID,
peer.version,
connections})
})
return slice
}
func newConnectionStatus(c Connection) ConnectionStatus {
return ConnectionStatus{
c.Remote().Name.String(),
c.Remote().NickName,
c.RemoteTCPAddr(),
c.Outbound(),
c.Established()}
}
func NewUnicastRouteStatusSlice(routes *Routes) []UnicastRouteStatus {
routes.RLock()
defer routes.RUnlock()
var slice []UnicastRouteStatus
for dest, via := range routes.unicast {
slice = append(slice, UnicastRouteStatus{dest.String(), via.String()})
}
return slice
}
func NewBroadcastRouteStatusSlice(routes *Routes) []BroadcastRouteStatus {
routes.RLock()
defer routes.RUnlock()
var slice []BroadcastRouteStatus
for source, via := range routes.broadcast {
var hops []string
for _, hop := range via {
hops = append(hops, hop.String())
}
slice = append(slice, BroadcastRouteStatus{source.String(), hops})
}
return slice
}
func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus {
// We need to Refresh first in order to clear out any 'attempting'
// connections from cm.targets that have been established since
// the last run of cm.checkStateAndAttemptConnections. These
// entries are harmless but do represent stale state that we do
// not want to report.
cm.Refresh()
resultChan := make(chan []LocalConnectionStatus, 0)
cm.actionChan <- func() bool {
var slice []LocalConnectionStatus
for conn := range cm.ourself.Connections() {
state := "pending"
if conn.Established() {
state = "established"
}
slice = append(slice, LocalConnectionStatus{conn.RemoteTCPAddr(), conn.Outbound(), state, conn.Remote().String()})
}
for address, target := range cm.targets {
var state, info string
switch {
case target.lastError == nil:
state = "connecting"
info = ""
case target.attempting:
state = "retrying"
info = target.lastError.Error()
default:
state = "failed"
info = target.lastError.Error() + ", retry: " + target.tryAfter.String()
}
slice = append(slice, LocalConnectionStatus{address, true, state, info})
}
resultChan <- slice
return false
}
return <-resultChan
}
func NewTargetSlice(cm *ConnectionMaker) []string {
resultChan := make(chan []string, 0)
cm.actionChan <- func() bool {
var slice []string
for peer := range cm.directPeers {
slice = append(slice, peer)
}
resultChan <- slice
return false
}
return <-resultChan
}
+5
View File
@@ -498,6 +498,11 @@ be disabled with the `--no-discovery` option to `weave launch`. In
this mode, weave will only connect to the addresses specified at
launch time and with `weave connect`.
The list of all hosts that a peer has been asked to connect to with
`weave launch` and `weave connect` can be obtained with
host# weave status targets
### <a name="container-mobility"></a>Container mobility
Containers can be moved between hosts without requiring any
+18 -12
View File
@@ -48,6 +48,17 @@ time, you can give the number of peers like this:
host3$ weave launch --init-peer-count 3 $HOST2
The consensus mechanism used to determine a majority transitions
through three states: 'deferred', 'waiting' and 'achieved':
* 'deferred' - no allocation requests or claims have been made yet;
consensus is deferred until then
* 'waiting' - an attempt to achieve consensus is ongoing, triggered by
an allocation or claim request; allocations will block. This state
persists until a quorum of peers are able to communicate amongst
themselves successfully
* 'achieved' - consensus achieved; allocations proceed normally
### More on `--init-peer-count`
TL;DR: it isn't a problem to over-estimate by a bit, but if you supply
@@ -199,21 +210,16 @@ reports on the current status of the weave router and IP allocator:
````
...
Allocator universe 10.2.0.0/16
Owned Ranges:
10.2.1.1 -> 96:e9:e2:2e:2d:bc (host1) (v3)
10.2.1.128 -> ea:84:25:9b:31:2e (host2) (v3)
10.2.1.192 -> ea:6c:21:09:cf:f0 (host3) (v9)
Allocator default subnet: 10.2.1.0/24
Service: ipam
Consensus: waiting(quorum: 2, known: 0)
Range: [10.32.0.0-10.48.0.0)
DefaultSubnet: 10.32.0.0/12
...
````
The first section covers the router; see the [troubleshooting
guide](troubleshooting.html#status-report) for full details.
guide](troubleshooting.html#weave-status) for full details.
The 'Allocator' section summarises the overall position and lists
which address ranges have been assigned to which peer. Each range
begins at the address shown and ends just before the next address, or
wraps around at the end of the subnet. The 'v' number denotes how many
times that entry has been updated.
The 'Service: ipam' section displays the consensus state as well as
the total allocation range and default subnet.
+149 -75
View File
@@ -5,6 +5,14 @@ layout: default
# Troubleshooting Weave
* [Overall status](#weave-status)
* [List connections](#weave-status-connections)
* [List peers](#weave-status-peers)
* [List DNS entries](#weave-status-dns)
* [JSON report](#weave-report)
* [List attached containers](#list-attached-containers)
* [Snapshot releases](#snapshot-releases)
Check what version of weave you are running with
weave version
@@ -29,9 +37,6 @@ Another useful debugging technique is to attach standard packet
capture and analysis tools, such as tcpdump and wireshark, to the
`weave` network bridge on the host.
One can ask a weave router for a [status report](#status-report) or
for a [list of attached containers](#list-attached-containers).
To stop weave, run
weave stop
@@ -50,100 +55,169 @@ Any running application containers will permanently lose connectivity
with the weave network and have to be restarted in order to
re-connect.
### <a name="status-report"></a>Status report
### <a name="weave-status"></a>Overall status
The command
weave status
reports on the current status of the weave router and DNS.
This produces output like:
A status summary can be obtained with `weave status`:
````
weave router 0.7.0
Our name is 7a:f4:56:87:76:3b(weave01)
Encryption off
Peer discovery on
Sniffing traffic on &{39 65535 ethwe ae:e3:07:9c:8c:d4 up|broadcast|multicast}
MACs:
ba:8c:b9:dc:e1:c9 -> 7a:f4:56:87:76:3b(weave01) (2014-10-23 16:39:19.482338935 +0000 UTC)
ce:15:34:a9:b5:6d -> 7a:f4:56:87:76:3b(weave01) (2014-10-23 16:39:28.257103595 +0000 UTC)
7a:61:a2:49:4b:91 -> 7a:f4:56:87:76:3b(weave01) (2014-10-23 16:39:27.482970752 +0000 UTC)
9e:95:0c:54:8e:39 -> 7a:16:dd:5b:83:de(weave02) (2014-10-23 16:39:28.795601325 +0000 UTC)
72:5f:a4:60:e5:ce -> 7a:16:dd:5b:83:de(weave02) (2014-10-23 16:39:29.575995255 +0000 UTC)
Peers:
7a:16:dd:5b:83:de(weave02) (v31) (UID 13151318985609435078)
-> 7a:f4:56:87:76:3b(weave01) [37.157.33.76:7195]
7a:f4:56:87:76:3b(weave01) (v1) (UID 6913268221365110570)
-> 7a:16:dd:5b:83:de(weave02) [191.235.147.190:6783]
Routes:
unicast:
7a:f4:56:87:76:3b -> 00:00:00:00:00:00
7a:16:dd:5b:83:de -> 7a:16:dd:5b:83:de
broadcast:
7a:f4:56:87:76:3b -> [7a:16:dd:5b:83:de]
7a:16:dd:5b:83:de -> []
Direct Peers: 191.235.147.190 192.168.32.1
Reconnects:
->[192.168.32.1:6783] (dial tcp4 192.168.32.1:6783: connection timed out) next try at 2014-10-23 16:39:50.585932102 +0000 UTC
$ weave status
Version: 1.1.0
Service: router
Protocol: weave 1..2
Name: 4a:0f:f6:ec:1c:93(host1)
Encryption: disabled
PeerDiscovery: enabled
Targets: [192.168.48.14 192.168.48.15]
Connections: 5 (1 established, 1 pending, 1 retrying, 1 failed, 1 connecting)
Peers: 3 (with 5 established, 1 pending connections betweeen them)
Service: ipam
Consensus: achieved
Range: [10.32.0.0-10.48.0.0)
DefaultSubnet: 10.32.0.0/12
Service: dns
Domain: weave.local.
TTL: 1
Entries: 9
Service: proxy
Address: tcp://127.0.0.1:12375
````
The terms used here are explained further at
[how it works](how-it-works.html).
The 'Our name' line identifies the local weave router as a peer in the
weave network, displaying the peer name followed by the peer's nickname
in parenthesis. The nickname defaults to the name of the host on which
the weave container was launched; if desired it can be overriden by
supplying the `--nickname` argument to `weave launch`.
The 'Version' line shows the weave version.
The 'Sniffing traffic' line shows details of the virtual ethernet
interface that weave is using to receive packets on the local
machine.
The 'Protocol' line indicates the weave router's inter-peer
communication protocol name and supported versions (min..max).
The 'Name' line identifies the local weave router as a peer in the
weave network. The nickname shown in parentheses defaults to the name
of the host on which the weave container was launched; if desired it
can be overriden by supplying the `--nickname` argument to `weave
launch`.
The 'Encryption' line indicates whether
[encryption](features.html#security) is in use for communication
between peers.
The 'Peer discovery' line indicates whether
The 'PeerDiscovery' line indicates whether
[automatic peer discovery](features.html#dynamic-topologies) is
enabled (which is the default).
The 'MACs' section lists all MAC addresses known to this router. These
identify containers in the weave network, as well as points for
[host network integration](features.html#host-network-integration). For
each MAC the list shows the peer they reside on, and the time when the
router last saw some traffic from that MAC. The router forgets
addresses which are inactive for longer than 10 minutes.
'Targets' is the number of hosts that the local weave router has been
asked to connect to in `weave launch` and `weave connect`. The
complete list can be obtained with `weave status targets`.
The 'Peers' section lists all peers known to this router, including
itself. Each peer is shown with its name, nickname, version number
(incremented on each reconnect) and the UID. Then each line
beginning `->` shows another peer that it is connected to, with the
IP address and port number of the connection. In the above example,
the local router has connected to its peer using address
191.235.147.190:6783, and its peer sees the same connection as coming
from 37.157.33.76:7195.
'Connections' shows the total number connections between the local weave
router and other peers, and a break down of that figure by connection
state. Further details are available with
[`weave status connections`](#weave-status-connections).
The 'Routes' section summarised the information for deciding how to
route packets between peers, which is mostly of interest when the
weave network is not fully connected. See the
[architecture documentation](https://raw.githubusercontent.com/weaveworks/weave/master/docs/architecture.txt)
for a full explanation.
'Peers' shows the total number of peers in the network, and the number of
connections between them. Further details are available with
[`weave status peers`](#weave-status-peers).
'Direct Peers' lists the hosts which weave was told to connect to in
`weave launch` and `weave connect`.
There are further sections for the [IP address
allocator](ipam.html#troubleshooting),
[weaveDNS](weavedns.html#troubleshooting), and [Weave Docker API
Proxy](proxy.html#troubleshooting).
The 'Reconnects' section lists peers that this router is aware of, but is
not currently connected to. Each line contains some information about
what went wrong the last time; whether it is attempting to connect or
is waiting for a while before connecting again.
### <a name="weave-status-connections"></a>List connections
There may also be further sections for the
[IP address allocator](ipam.html#troubleshooting),
[weaveDNS](weavedns.html#troubleshooting), and
[Weave Docker API Proxy](proxy.html#troubleshooting).
Detailed information on the local weave router's connections can be
obtained with `weave status connections`:
````
$ weave status connections
<- 192.168.48.12:33866 established 7e:21:4a:70:2f:45(host2)
<- 192.168.48.13:60773 pending 7e:ae:cd:d5:23:8d(host3)
-> 192.168.48.14:6783 retrying dial tcp4 192.168.48.14:6783: no route to host
-> 192.168.48.15:6783 failed dial tcp4 192.168.48.15:6783: no route to host, retry: 2015-08-06 18:55:38.246910357 +0000 UTC
-> 192.168.48.16:6783 connecting
````
The columns are as follows:
* Connection origination direction (`->` for outbound, `<-` for
inbound)
* Remote TCP address
* Status
* `connecting` - first connection attempt in progress
* `failed` - TCP connection or UDP heartbeat failed
* `retrying` - retry of a previously failed connection attempt in
progress; reason for previous failure follows
* `pending` - TCP connection up, waiting for confirmation of
UDP heartbeat
* `established` - TCP connection and corresponding UDP path are up
* Info - the remote peer name and nickname for (un)established
connections, the failure reason for failed and retrying connection
### <a name="weave-status-peers"></a>List peers
Detailed information on peers can be obtained with `weave status
peers`:
````
$ weave status peers
ce:31:e0:06:45:1a(host1)
<- 192.168.48.12:39634 ea:2d:b2:e6:e4:f5(host2) established
<- 192.168.48.13:49619 ee:38:33:a7:d9:71(host3) established
ea:2d:b2:e6:e4:f5(host2)
-> 192.168.48.11:6783 ce:31:e0:06:45:1a(host1) established
<- 192.168.48.13:58181 ee:38:33:a7:d9:71(host3) established
ee:38:33:a7:d9:71(host3)
-> 192.168.48.12:6783 ea:2d:b2:e6:e4:f5(host2) established
-> 192.168.48.11:6783 ce:31:e0:06:45:1a(host1) established
````
This lists all peers known to this router, including itself. Each
peer is shown with its name and nickname, then each line thereafter
shows another peer that it is connected to, with the direction, IP
address and port number of the connection. In the above example,
`host3` has connected to `host1` at `192.168.48.11:6783`; `host1` sees
the `host3` end of the same connection as `192.168.48.13:49619`.
### <a name="weave-status-dns"></a>List DNS entries
Detailed information on DNS registrations can be obtained with `weave
status dns`:
````
$ weave status dns
one 10.32.0.1 eebd81120ee4 4a:0f:f6:ec:1c:93
one 10.43.255.255 4fcec78d2a9b 66:c4:47:c6:65:bf
one 10.40.0.0 bab69d305cba ba:98:d0:37:4f:1c
three 10.32.0.3 7615b6537f74 4a:0f:f6:ec:1c:93
three 10.44.0.1 c0b39dc52f8d 66:c4:47:c6:65:bf
three 10.40.0.2 8a9c2e2ef00f ba:98:d0:37:4f:1c
two 10.32.0.2 83689b8f34e0 4a:0f:f6:ec:1c:93
two 10.44.0.0 7edc306cb668 66:c4:47:c6:65:bf
two 10.40.0.1 68a5e9c2641b ba:98:d0:37:4f:1c
````
The columns are as follows:
* Unqualified hostname
* IPv4 address
* Registering entity identifier (typically a container ID)
* Name of peer from which the registration originates
### <a name="weave-report"></a>JSON report
$ weave report
Produces a comprehensive dump of the internal state of the router,
IPAM and DNS services in JSON format, including all the information
available from the `weave status` commands. You can also supply a
Golang text template to `weave report` in a similar fashion to `docker
inspect`:
$ weave report -f '{{{.DNS.Domain}}'
weave.local.
### <a name="list-attached-containers"></a>List attached containers
+10 -10
View File
@@ -247,25 +247,25 @@ DNS:
````
...
WeaveDNS (d6:1b:df:42:af:7d)
listening on port 53, for domain weave.local.
response ttl 30
1d836dea2c56: foo.weave.local. [10.2.2.1]
Service: dns
Domain: weave.local.
TTL: 1
Entries: 9
...
````
The first section covers the router; see the [troubleshooting
guide](troubleshooting.html#status-report) for more detail.
guide](troubleshooting.html#weave-status) for more detail.
The second section is pertinent to weaveDNS, and includes:
The 'Service: dns' section is pertinent to weaveDNS, and includes:
* Port on which the DNS server is listening
* The local domain suffix which is being served
* The response ttl
* The names known to the weaveDNS server. Each entry comprises
the container ID, IP address and its fully qualified domain name
* The total number of entries
You may also use `weave status dns` to obtain a [complete
dump](troubleshooting.html#weave-status-dns) of all DNS registrations.
Information on the processing of queries, and the general operation of
weaveDNS, can be obtained from the container logs with
+2 -1
View File
@@ -6,7 +6,8 @@ C1=10.2.1.4
C2=10.2.1.7
direct_peers() {
weave_on $1 status | sed -n -e 's|^Direct Peers: \(.*\)|\1|p' | tr -s ' ' '\n'
weave_on $1 report -f "{{range .Router.Targets}}{{.}}
{{end}}"
}
assert_peers() {
+29
View File
@@ -0,0 +1,29 @@
#! /bin/bash
. ./config.sh
UNIVERSE=10.2.0.0/16
start_suite "weave status/report"
weave_on $HOST1 launch --ipalloc-range $UNIVERSE --name 8a:3e:3e:3e:3e:3e --nickname nicknamington
check() {
assert "weave_on $HOST1 status | grep -oP '(?<= $1: ).*'" "$3"
assert "weave_on $HOST1 report -f '$2'" "$3"
}
check "Name" "{{.Router.Name}}({{.Router.NickName}})" "8a:3e:3e:3e:3e:3e(nicknamington)"
check "Peers" "{{len .Router.Peers}}" "1"
check "DefaultSubnet" "{{.IPAM.DefaultSubnet}}" $UNIVERSE
check "Domain" "{{.DNS.Domain}}" "weave.local."
assert_raises "weave_on $HOST1 status peers | grep nicknamington"
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"
start_container $HOST1 --name test
assert "weave_on $HOST1 status dns | tr -s ' ' | cut -d ' ' -f 1" "test"
assert_raises "weave_on $HOST1 report | grep nicknamington"
end_suite
+21 -5
View File
@@ -45,7 +45,8 @@ weave env
weave config
weave connect [--replace] [<peer> ...]
weave forget <peer> ...
weave status
weave status [targets | connections | peers | dns]
weave report [-f <format>]
weave run [--with-dns | --without-dns] [<addr> ...]
<docker run args> ...
weave start [<addr> ...] <container_id>
@@ -1323,14 +1324,29 @@ case "$COMMAND" in
;;
status)
res=0
call_weave GET /status || res=1
echo
if check_running $PROXY_CONTAINER_NAME 2>/dev/null ; then
OMIT_PROXY=
STATUS_URL="/status"
while [ $# -gt 0 ] ; do
OMIT_PROXY=1
STATUS_URL="$STATUS_URL/$1"
shift
done
call_weave GET $STATUS_URL || res=1
if [ -z "$OMIT_PROXY" ] && check_running $PROXY_CONTAINER_NAME 2>/dev/null ; then
echo
echo "weave proxy is running"
echo " Service: proxy"
echo " Address: $(proxy_addr)"
fi
[ $res -eq 0 ]
;;
report)
if [ $# -gt 0 ] ; then
[ $# -eq 2 -a "$1" = "-f" ] || usage
call_weave GET /report --get --data-urlencode "format=$2"
else
call_weave GET /report -H 'Accept: application/json'
fi
;;
run)
dns_args "$@"
shift $(dns_arg_count "$@")