cmd/tailscale/cli: make push get peerapi base via localapi, not TSMP ping
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>pull/1696/head
parent
1dc2cf4835
commit
a08d978476
|
@ -13,7 +13,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"mime"
|
"mime"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -23,9 +22,8 @@ import (
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v2/ffcli"
|
"github.com/peterbourgon/ff/v2/ffcli"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
|
"inet.af/netaddr"
|
||||||
"tailscale.com/client/tailscale"
|
"tailscale.com/client/tailscale"
|
||||||
"tailscale.com/ipn"
|
|
||||||
"tailscale.com/ipn/ipnstate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var pushCmd = &ffcli.Command{
|
var pushCmd = &ffcli.Command{
|
||||||
|
@ -63,11 +61,15 @@ func runPush(ctx context.Context, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
peerAPIPort, err := discoverPeerAPIPort(ctx, ip)
|
peerAPIBase, lastSeen, err := discoverPeerAPIBase(ctx, ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !lastSeen.IsZero() && time.Since(lastSeen) > lastSeenOld {
|
||||||
|
fmt.Fprintf(os.Stderr, "# warning: %s last seen %v ago\n", hostOrIP, time.Since(lastSeen).Round(time.Minute))
|
||||||
|
}
|
||||||
|
|
||||||
var fileContents io.Reader
|
var fileContents io.Reader
|
||||||
var name = pushArgs.name
|
var name = pushArgs.name
|
||||||
var contentLength int64 = -1
|
var contentLength int64 = -1
|
||||||
|
@ -103,7 +105,7 @@ func runPush(ctx context.Context, args []string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dstURL := "http://" + net.JoinHostPort(ip, fmt.Sprint(peerAPIPort)) + "/v0/put/" + url.PathEscape(name)
|
dstURL := peerAPIBase + "/v0/put/" + url.PathEscape(name)
|
||||||
req, err := http.NewRequestWithContext(ctx, "PUT", dstURL, fileContents)
|
req, err := http.NewRequestWithContext(ctx, "PUT", dstURL, fileContents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -124,51 +126,28 @@ func runPush(ctx context.Context, args []string) error {
|
||||||
return errors.New(res.Status)
|
return errors.New(res.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func discoverPeerAPIPort(ctx context.Context, ip string) (port uint16, err error) {
|
func discoverPeerAPIBase(ctx context.Context, ipStr string) (base string, lastSeen time.Time, err error) {
|
||||||
c, bc, ctx, cancel := connect(ctx)
|
ip, err := netaddr.ParseIP(ipStr)
|
||||||
defer cancel()
|
if err != nil {
|
||||||
|
return "", time.Time{}, err
|
||||||
prc := make(chan *ipnstate.PingResult, 2)
|
|
||||||
bc.SetNotifyCallback(func(n ipn.Notify) {
|
|
||||||
if n.ErrMessage != nil {
|
|
||||||
log.Fatal(*n.ErrMessage)
|
|
||||||
}
|
|
||||||
if pr := n.PingResult; pr != nil && pr.IP == ip {
|
|
||||||
prc <- pr
|
|
||||||
}
|
|
||||||
})
|
|
||||||
go pump(ctx, bc, c)
|
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
discoPings := 0
|
|
||||||
timer := time.NewTimer(10 * time.Second)
|
|
||||||
defer timer.Stop()
|
|
||||||
|
|
||||||
sendPings := func() {
|
|
||||||
bc.Ping(ip, false)
|
|
||||||
bc.Ping(ip, true)
|
|
||||||
}
|
}
|
||||||
sendPings()
|
fts, err := tailscale.FileTargets(ctx)
|
||||||
for {
|
if err != nil {
|
||||||
select {
|
return "", time.Time{}, err
|
||||||
case <-ticker.C:
|
}
|
||||||
sendPings()
|
for _, ft := range fts {
|
||||||
case <-timer.C:
|
n := ft.Node
|
||||||
return 0, fmt.Errorf("timeout contacting %v; it offline?", ip)
|
for _, a := range n.Addresses {
|
||||||
case pr := <-prc:
|
if a.IP != ip {
|
||||||
if p := pr.PeerAPIPort; p != 0 {
|
continue
|
||||||
return p, nil
|
|
||||||
}
|
}
|
||||||
discoPings++
|
if n.LastSeen != nil {
|
||||||
if discoPings == 3 {
|
lastSeen = *n.LastSeen
|
||||||
return 0, fmt.Errorf("%v is online, but seems to be running an old Tailscale version", ip)
|
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
return ft.PeerAPIURL, lastSeen, nil
|
||||||
return 0, ctx.Err()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return "", time.Time{}, errors.New("target seems to be running an old Tailscale version")
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxSniff = 4 << 20
|
const maxSniff = 4 << 20
|
||||||
|
@ -213,6 +192,8 @@ func (r *slowReader) Read(p []byte) (n int, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lastSeenOld = 20 * time.Minute
|
||||||
|
|
||||||
func runPushTargets(ctx context.Context, args []string) error {
|
func runPushTargets(ctx context.Context, args []string) error {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
return errors.New("invalid arguments with --targets")
|
return errors.New("invalid arguments with --targets")
|
||||||
|
@ -227,7 +208,7 @@ func runPushTargets(ctx context.Context, args []string) error {
|
||||||
if n.LastSeen == nil {
|
if n.LastSeen == nil {
|
||||||
ago = "\tnode never seen"
|
ago = "\tnode never seen"
|
||||||
} else {
|
} else {
|
||||||
if d := time.Since(*n.LastSeen); d > 20*time.Minute {
|
if d := time.Since(*n.LastSeen); d > lastSeenOld {
|
||||||
ago = fmt.Sprintf("\tlast seen %v ago", d.Round(time.Minute))
|
ago = fmt.Sprintf("\tlast seen %v ago", d.Round(time.Minute))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue