ipn/ipnstate: update tailscale status -web to match CLI

This commit is contained in:
Brad Fitzpatrick 2021-01-26 08:28:34 -08:00
parent a98538f84a
commit a7edcd0872
2 changed files with 52 additions and 35 deletions

View File

@ -14,7 +14,6 @@
"net" "net"
"net/http" "net/http"
"os" "os"
"sort"
"strings" "strings"
"time" "time"
@ -181,7 +180,7 @@ func runStatus(ctx context.Context, args []string) error {
} }
peers = append(peers, ps) peers = append(peers, ps)
} }
sort.Slice(peers, func(i, j int) bool { return sortKey(peers[i]) < sortKey(peers[j]) }) ipnstate.SortPeers(peers)
for _, ps := range peers { for _, ps := range peers {
active := peerActive(ps) active := peerActive(ps)
if statusArgs.active && !active { if statusArgs.active && !active {
@ -211,16 +210,6 @@ func dnsOrQuoteHostname(st *ipnstate.Status, ps *ipnstate.PeerStatus) string {
return fmt.Sprintf("(%q)", strings.ReplaceAll(ps.SimpleHostName(), " ", "_")) return fmt.Sprintf("(%q)", strings.ReplaceAll(ps.SimpleHostName(), " ", "_"))
} }
func sortKey(ps *ipnstate.PeerStatus) string {
if ps.DNSName != "" {
return ps.DNSName
}
if ps.HostName != "" {
return ps.HostName
}
return ps.TailAddr
}
func ownerLogin(st *ipnstate.Status, ps *ipnstate.PeerStatus) string { func ownerLogin(st *ipnstate.Status, ps *ipnstate.PeerStatus) string {
if ps.UserID.IsZero() { if ps.UserID.IsZero() {
return "-" return "-"

View File

@ -21,6 +21,7 @@
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/util/dnsname"
) )
// Status represents the entire state of the IPN network. // Status represents the entire state of the IPN network.
@ -280,13 +281,22 @@ func (st *Status) WriteHTML(w io.Writer) {
f("<p>Tailscale IP: %s", strings.Join(ips, ", ")) f("<p>Tailscale IP: %s", strings.Join(ips, ", "))
f("<table>\n<thead>\n") f("<table>\n<thead>\n")
f("<tr><th>Peer</th><th>Node</th><th>Owner</th><th>Rx</th><th>Tx</th><th>Activity</th><th>Endpoints</th></tr>\n") f("<tr><th>Peer</th><th>OS</th><th>Node</th><th>Owner</th><th>Rx</th><th>Tx</th><th>Activity</th><th>Connection</th></tr>\n")
f("</thead>\n<tbody>\n") f("</thead>\n<tbody>\n")
now := time.Now() now := time.Now()
var peers []*PeerStatus
for _, peer := range st.Peers() { for _, peer := range st.Peers() {
ps := st.Peer[peer] ps := st.Peer[peer]
if ps.ShareeNode {
continue
}
peers = append(peers, ps)
}
SortPeers(peers)
for _, ps := range peers {
var actAgo string var actAgo string
if !ps.LastWrite.IsZero() { if !ps.LastWrite.IsZero() {
ago := now.Sub(ps.LastWrite) ago := now.Sub(ps.LastWrite)
@ -302,40 +312,44 @@ func (st *Status) WriteHTML(w io.Writer) {
owner = owner[:i] owner = owner[:i]
} }
} }
f("<tr><td>%s</td><td>%s %s<br><span class=\"tailaddr\">%s</span></td><td class=\"acenter owner\">%s</td><td class=\"aright\">%v</td><td class=\"aright\">%v</td><td class=\"aright\">%v</td>",
peer.ShortString(), hostName := ps.SimpleHostName()
html.EscapeString(ps.SimpleHostName()), dnsName := strings.TrimRight(ps.DNSName, ".")
if i := strings.Index(dnsName, "."); i != -1 && dnsname.HasSuffix(dnsName, st.MagicDNSSuffix) {
dnsName = dnsName[:i]
}
if strings.EqualFold(dnsName, hostName) || ps.UserID != st.Self.UserID {
hostName = ""
}
var hostNameHTML string
if hostName != "" {
hostNameHTML = "<br>" + html.EscapeString(hostName)
}
f("<tr><td>%s</td><td class=acenter>%s</td>"+
"<td><b>%s</b>%s<div class=\"tailaddr\">%s</div></td><td class=\"acenter owner\">%s</td><td class=\"aright\">%v</td><td class=\"aright\">%v</td><td class=\"aright\">%v</td>",
ps.PublicKey.ShortString(),
osEmoji(ps.OS), osEmoji(ps.OS),
html.EscapeString(dnsName),
hostNameHTML,
ps.TailAddr, ps.TailAddr,
html.EscapeString(owner), html.EscapeString(owner),
ps.RxBytes, ps.RxBytes,
ps.TxBytes, ps.TxBytes,
actAgo, actAgo,
) )
f("<td class=\"aright\">") f("<td>")
// TODO: let server report this active bool instead // TODO: let server report this active bool instead
active := !ps.LastWrite.IsZero() && time.Since(ps.LastWrite) < 2*time.Minute active := !ps.LastWrite.IsZero() && time.Since(ps.LastWrite) < 2*time.Minute
relay := ps.Relay if active {
if relay != "" { if ps.Relay != "" && ps.CurAddr == "" {
if active && ps.CurAddr == "" { f("relay <b>%s</b>", html.EscapeString(ps.Relay))
f("🔗 <b>derp-%v</b><br>", html.EscapeString(relay)) } else if ps.CurAddr != "" {
} else { f("direct <b>%s</b>", html.EscapeString(ps.CurAddr))
f("derp-%v<br>", html.EscapeString(relay))
} }
} }
match := false
for _, addr := range ps.Addrs {
if addr == ps.CurAddr {
match = true
f("🔗 <b>%s</b><br>", addr)
} else {
f("%s<br>", addr)
}
}
if ps.CurAddr != "" && !match {
f("<b>%s</b> \xf0\x9f\xa7\xb3<br>", ps.CurAddr)
}
f("</td>") // end Addrs f("</td>") // end Addrs
f("</tr>\n") f("</tr>\n")
@ -381,3 +395,17 @@ type PingResult struct {
// TODO(bradfitz): details like whether port mapping was used on either side? (Once supported) // TODO(bradfitz): details like whether port mapping was used on either side? (Once supported)
} }
func SortPeers(peers []*PeerStatus) {
sort.Slice(peers, func(i, j int) bool { return sortKey(peers[i]) < sortKey(peers[j]) })
}
func sortKey(ps *PeerStatus) string {
if ps.DNSName != "" {
return ps.DNSName
}
if ps.HostName != "" {
return ps.HostName
}
return ps.TailAddr
}