cmd/tailscale, ipn/localapi: get daemon version from localapi status

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/1546/head
Brad Fitzpatrick 2021-03-18 21:07:58 -07:00
parent d0dffe33c0
commit 439d70dce2
5 changed files with 104 additions and 58 deletions

View File

@ -103,7 +103,16 @@ func Goroutines(ctx context.Context) ([]byte, error) {
// Status returns the Tailscale daemon's status. // Status returns the Tailscale daemon's status.
func Status(ctx context.Context) (*ipnstate.Status, error) { func Status(ctx context.Context) (*ipnstate.Status, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "http://local-tailscaled.sock/localapi/v0/status", nil) return status(ctx, "")
}
// StatusWithPeers returns the Tailscale daemon's status, without the peer info.
func StatusWithoutPeers(ctx context.Context) (*ipnstate.Status, error) {
return status(ctx, "?peers=false")
}
func status(ctx context.Context, queryString string) (*ipnstate.Status, error) {
req, err := http.NewRequestWithContext(ctx, "GET", "http://local-tailscaled.sock/localapi/v0/status"+queryString, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -11,7 +11,7 @@ import (
"log" "log"
"github.com/peterbourgon/ff/v2/ffcli" "github.com/peterbourgon/ff/v2/ffcli"
"tailscale.com/ipn" "tailscale.com/client/tailscale"
"tailscale.com/version" "tailscale.com/version"
) )
@ -42,29 +42,10 @@ func runVersion(ctx context.Context, args []string) error {
fmt.Printf("Client: %s\n", version.String()) fmt.Printf("Client: %s\n", version.String())
c, bc, ctx, cancel := connect(ctx) st, err := tailscale.StatusWithoutPeers(ctx)
defer cancel() if err != nil {
return err
bc.AllowVersionSkew = true
done := make(chan struct{})
bc.SetNotifyCallback(func(n ipn.Notify) {
if n.ErrMessage != nil {
log.Fatal(*n.ErrMessage)
} }
if n.Engine != nil { fmt.Printf("Daemon: %s\n", st.Version)
fmt.Printf("Daemon: %s\n", n.Version)
close(done)
}
})
go pump(ctx, bc, c)
bc.RequestEngineStatus()
select {
case <-done:
return nil return nil
case <-ctx.Done():
return ctx.Err()
}
} }

View File

@ -218,20 +218,45 @@ func (b *LocalBackend) Status() *ipnstate.Status {
return sb.Status() return sb.Status()
} }
// StatusWithoutPeers is like Status but omits any details
// of peers.
func (b *LocalBackend) StatusWithoutPeers() *ipnstate.Status {
sb := new(ipnstate.StatusBuilder)
b.updateStatus(sb, nil)
return sb.Status()
}
// UpdateStatus implements ipnstate.StatusUpdater. // UpdateStatus implements ipnstate.StatusUpdater.
func (b *LocalBackend) UpdateStatus(sb *ipnstate.StatusBuilder) { func (b *LocalBackend) UpdateStatus(sb *ipnstate.StatusBuilder) {
b.e.UpdateStatus(sb) b.e.UpdateStatus(sb)
b.updateStatus(sb, b.populatePeerStatusLocked)
}
// updateStatus populates sb with status.
//
// extraLocked, if non-nil, is called while b.mu is still held.
func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func(*ipnstate.StatusBuilder)) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
sb.SetVersion(version.Long)
sb.SetBackendState(b.state.String()) sb.SetBackendState(b.state.String())
sb.SetAuthURL(b.authURL) sb.SetAuthURL(b.authURL)
// TODO: hostinfo, and its networkinfo // TODO: hostinfo, and its networkinfo
// TODO: EngineStatus copy (and deprecate it?) // TODO: EngineStatus copy (and deprecate it?)
if b.netMap != nil { if b.netMap != nil {
sb.SetMagicDNSSuffix(b.netMap.MagicDNSSuffix()) sb.SetMagicDNSSuffix(b.netMap.MagicDNSSuffix())
}
if extraLocked != nil {
extraLocked(sb)
}
}
func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
if b.netMap == nil {
return
}
for id, up := range b.netMap.UserProfiles { for id, up := range b.netMap.UserProfiles {
sb.AddUser(id, up) sb.AddUser(id, up)
} }
@ -264,7 +289,6 @@ func (b *LocalBackend) UpdateStatus(sb *ipnstate.StatusBuilder) {
ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID, ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID,
}) })
} }
}
} }
// WhoIs reports the node and user who owns the node with the given IP:port. // WhoIs reports the node and user who owns the node with the given IP:port.

View File

@ -26,7 +26,14 @@ import (
// Status represents the entire state of the IPN network. // Status represents the entire state of the IPN network.
type Status struct { type Status struct {
// Version is the daemon's long version (see version.Long).
Version string
// BackendState is an ipn.State string value:
// "NoState", "NeedsLogin", "NeedsMachineAuth", "Stopped",
// "Starting", "Running".
BackendState string BackendState string
AuthURL string // current URL provided by control to authorize client AuthURL string // current URL provided by control to authorize client
TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node
Self *PeerStatus Self *PeerStatus
@ -105,6 +112,12 @@ type StatusBuilder struct {
st Status st Status
} }
func (sb *StatusBuilder) SetVersion(v string) {
sb.mu.Lock()
defer sb.mu.Unlock()
sb.st.Version = v
}
func (sb *StatusBuilder) SetBackendState(v string) { func (sb *StatusBuilder) SetBackendState(v string) {
sb.mu.Lock() sb.mu.Lock()
defer sb.mu.Unlock() defer sb.mu.Unlock()

View File

@ -10,9 +10,11 @@ import (
"io" "io"
"net/http" "net/http"
"runtime" "runtime"
"strconv"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/ipnstate"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
) )
@ -118,7 +120,24 @@ func (h *Handler) serveStatus(w http.ResponseWriter, r *http.Request) {
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
var st *ipnstate.Status
if defBool(r.FormValue("peers"), true) {
st = h.b.Status()
} else {
st = h.b.StatusWithoutPeers()
}
e := json.NewEncoder(w) e := json.NewEncoder(w)
e.SetIndent("", "\t") e.SetIndent("", "\t")
e.Encode(h.b.Status()) e.Encode(st)
}
func defBool(a string, def bool) bool {
if a == "" {
return def
}
v, err := strconv.ParseBool(a)
if err != nil {
return def
}
return v
} }