mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 03:31:39 +00:00
cmd/tailscale/cli: add Stdout, Stderr and output through them
So js/wasm can override where those go, without implementing an *os.File pipe pair, etc. Updates #3157 Change-Id: I14ba954d9f2349ff15b58796d95ecb1367e8ba3a Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
2ce5fc7b0a
commit
5df7ac70d6
@ -7,7 +7,6 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
"tailscale.com/client/tailscale"
|
"tailscale.com/client/tailscale"
|
||||||
@ -33,6 +32,6 @@ func runBugReport(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(logMarker)
|
outln(logMarker)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func runCert(ctx context.Context, args []string) error {
|
|||||||
domain := args[0]
|
domain := args[0]
|
||||||
|
|
||||||
printf := func(format string, a ...interface{}) {
|
printf := func(format string, a ...interface{}) {
|
||||||
fmt.Printf(format, a...)
|
printf(format, a...)
|
||||||
}
|
}
|
||||||
if certArgs.certFile == "-" || certArgs.keyFile == "-" {
|
if certArgs.certFile == "-" || certArgs.keyFile == "-" {
|
||||||
printf = log.Printf
|
printf = log.Printf
|
||||||
@ -143,7 +143,7 @@ func runCert(ctx context.Context, args []string) error {
|
|||||||
|
|
||||||
func writeIfChanged(filename string, contents []byte, mode os.FileMode) (changed bool, err error) {
|
func writeIfChanged(filename string, contents []byte, mode os.FileMode) (changed bool, err error) {
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
os.Stdout.Write(contents)
|
Stdout.Write(contents)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if old, err := os.ReadFile(filename); err == nil && bytes.Equal(contents, old) {
|
if old, err := os.ReadFile(filename); err == nil && bytes.Equal(contents, old) {
|
||||||
|
@ -31,6 +31,22 @@ import (
|
|||||||
"tailscale.com/syncs"
|
"tailscale.com/syncs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var Stderr io.Writer = os.Stderr
|
||||||
|
var Stdout io.Writer = os.Stdout
|
||||||
|
|
||||||
|
func printf(format string, a ...interface{}) {
|
||||||
|
fmt.Fprintf(Stdout, format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// outln is like fmt.Println in the common case, except when Stdout is
|
||||||
|
// changed (as in js/wasm).
|
||||||
|
//
|
||||||
|
// It's not named println because that looks like the Go built-in
|
||||||
|
// which goes to stderr and formats slightly differently.
|
||||||
|
func outln(a ...interface{}) {
|
||||||
|
fmt.Fprintln(Stdout, a...)
|
||||||
|
}
|
||||||
|
|
||||||
// ActLikeCLI reports whether a GUI application should act like the
|
// ActLikeCLI reports whether a GUI application should act like the
|
||||||
// CLI based on os.Args, GOOS, the context the process is running in
|
// CLI based on os.Args, GOOS, the context the process is running in
|
||||||
// (pty, parent PID), etc.
|
// (pty, parent PID), etc.
|
||||||
@ -82,7 +98,9 @@ func newFlagSet(name string) *flag.FlagSet {
|
|||||||
if runtime.GOOS == "js" {
|
if runtime.GOOS == "js" {
|
||||||
onError = flag.ContinueOnError
|
onError = flag.ContinueOnError
|
||||||
}
|
}
|
||||||
return flag.NewFlagSet(name, onError)
|
fs := flag.NewFlagSet(name, onError)
|
||||||
|
fs.SetOutput(Stderr)
|
||||||
|
return fs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the CLI. The args do not include the binary name.
|
// Run runs the CLI. The args do not include the binary name.
|
||||||
@ -94,7 +112,7 @@ func Run(args []string) error {
|
|||||||
var warnOnce sync.Once
|
var warnOnce sync.Once
|
||||||
tailscale.SetVersionMismatchHandler(func(clientVer, serverVer string) {
|
tailscale.SetVersionMismatchHandler(func(clientVer, serverVer string) {
|
||||||
warnOnce.Do(func() {
|
warnOnce.Do(func() {
|
||||||
fmt.Fprintf(os.Stderr, "Warning: client version %q != tailscaled server version %q\n", clientVer, serverVer)
|
fmt.Fprintf(Stderr, "Warning: client version %q != tailscaled server version %q\n", clientVer, serverVer)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ var debugArgs struct {
|
|||||||
|
|
||||||
func writeProfile(dst string, v []byte) error {
|
func writeProfile(dst string, v []byte) error {
|
||||||
if dst == "-" {
|
if dst == "-" {
|
||||||
_, err := os.Stdout.Write(v)
|
_, err := Stdout.Write(v)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(dst, v, 0600)
|
return os.WriteFile(dst, v, 0600)
|
||||||
@ -83,21 +83,21 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
if debugArgs.env {
|
if debugArgs.env {
|
||||||
for _, e := range os.Environ() {
|
for _, e := range os.Environ() {
|
||||||
fmt.Println(e)
|
outln(e)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if debugArgs.localCreds {
|
if debugArgs.localCreds {
|
||||||
port, token, err := safesocket.LocalTCPPortAndToken()
|
port, token, err := safesocket.LocalTCPPortAndToken()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("curl -u:%s http://localhost:%d/localapi/v0/status\n", token, port)
|
printf("curl -u:%s http://localhost:%d/localapi/v0/status\n", token, port)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
fmt.Printf("curl http://localhost:41112/localapi/v0/status\n")
|
printf("curl http://localhost:41112/localapi/v0/status\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fmt.Printf("curl --unix-socket %s http://foo/localapi/v0/status\n", paths.DefaultTailscaledSocket())
|
printf("curl --unix-socket %s http://foo/localapi/v0/status\n", paths.DefaultTailscaledSocket())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if out := debugArgs.cpuFile; out != "" {
|
if out := debugArgs.cpuFile; out != "" {
|
||||||
@ -128,10 +128,10 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if debugArgs.pretty {
|
if debugArgs.pretty {
|
||||||
fmt.Println(prefs.Pretty())
|
outln(prefs.Pretty())
|
||||||
} else {
|
} else {
|
||||||
j, _ := json.MarshalIndent(prefs, "", "\t")
|
j, _ := json.MarshalIndent(prefs, "", "\t")
|
||||||
fmt.Println(string(j))
|
outln(string(j))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
os.Stdout.Write(goroutines)
|
Stdout.Write(goroutines)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if debugArgs.derpMap {
|
if debugArgs.derpMap {
|
||||||
@ -150,7 +150,7 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
"failed to get local derp map, instead `curl %s/derpmap/default`: %w", ipn.DefaultControlURL, err,
|
"failed to get local derp map, instead `curl %s/derpmap/default`: %w", ipn.DefaultControlURL, err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
enc := json.NewEncoder(os.Stdout)
|
enc := json.NewEncoder(Stdout)
|
||||||
enc.SetIndent("", "\t")
|
enc.SetIndent("", "\t")
|
||||||
enc.Encode(dm)
|
enc.Encode(dm)
|
||||||
return nil
|
return nil
|
||||||
@ -164,7 +164,7 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
n.NetMap = nil
|
n.NetMap = nil
|
||||||
}
|
}
|
||||||
j, _ := json.MarshalIndent(n, "", "\t")
|
j, _ := json.MarshalIndent(n, "", "\t")
|
||||||
fmt.Printf("%s\n", j)
|
printf("%s\n", j)
|
||||||
})
|
})
|
||||||
bc.RequestEngineStatus()
|
bc.RequestEngineStatus()
|
||||||
pump(ctx, bc, c)
|
pump(ctx, bc, c)
|
||||||
@ -176,7 +176,7 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
e := json.NewEncoder(os.Stdout)
|
e := json.NewEncoder(Stdout)
|
||||||
e.SetIndent("", "\t")
|
e.SetIndent("", "\t")
|
||||||
e.Encode(wfs)
|
e.Encode(wfs)
|
||||||
return nil
|
return nil
|
||||||
@ -190,7 +190,7 @@ func runDebug(ctx context.Context, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("Size: %v\n", size)
|
log.Printf("Size: %v\n", size)
|
||||||
io.Copy(os.Stdout, rc)
|
io.Copy(Stdout, rc)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
"tailscale.com/client/tailscale"
|
"tailscale.com/client/tailscale"
|
||||||
@ -33,7 +32,7 @@ func runDown(ctx context.Context, args []string) error {
|
|||||||
return fmt.Errorf("error fetching current status: %w", err)
|
return fmt.Errorf("error fetching current status: %w", err)
|
||||||
}
|
}
|
||||||
if st.BackendState == "Stopped" {
|
if st.BackendState == "Stopped" {
|
||||||
fmt.Fprintf(os.Stderr, "Tailscale was already stopped.\n")
|
fmt.Fprintf(Stderr, "Tailscale was already stopped.\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err = tailscale.EditPrefs(ctx, &ipn.MaskedPrefs{
|
_, err = tailscale.EditPrefs(ctx, &ipn.MaskedPrefs{
|
||||||
|
@ -101,7 +101,7 @@ func runCp(ctx context.Context, args []string) error {
|
|||||||
return fmt.Errorf("can't send to %s: %v", target, err)
|
return fmt.Errorf("can't send to %s: %v", target, err)
|
||||||
}
|
}
|
||||||
if isOffline {
|
if isOffline {
|
||||||
fmt.Fprintf(os.Stderr, "# warning: %s is offline\n", target)
|
fmt.Fprintf(Stderr, "# warning: %s is offline\n", target)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(files) > 1 {
|
if len(files) > 1 {
|
||||||
@ -172,7 +172,7 @@ func runCp(ctx context.Context, args []string) error {
|
|||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
io.Copy(os.Stdout, res.Body)
|
io.Copy(Stdout, res.Body)
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
return errors.New(res.Status)
|
return errors.New(res.Status)
|
||||||
}
|
}
|
||||||
@ -293,7 +293,7 @@ func runCpTargets(ctx context.Context, args []string) error {
|
|||||||
if detail != "" {
|
if detail != "" {
|
||||||
detail = "\t" + detail
|
detail = "\t" + detail
|
||||||
}
|
}
|
||||||
fmt.Printf("%s\t%s%s\n", n.Addresses[0].IP(), n.ComputedName, detail)
|
printf("%s\t%s%s\n", n.Addresses[0].IP(), n.ComputedName, detail)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func runIP(ctx context.Context, args []string) error {
|
|||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
if ip.Is4() && v4 || ip.Is6() && v6 {
|
if ip.Is4() && v4 || ip.Is6() && v6 {
|
||||||
match = true
|
match = true
|
||||||
fmt.Println(ip)
|
outln(ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !match {
|
if !match {
|
||||||
|
@ -60,7 +60,7 @@ func runNetcheck(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(netcheckArgs.format, "json") {
|
if strings.HasPrefix(netcheckArgs.format, "json") {
|
||||||
fmt.Fprintln(os.Stderr, "# Warning: this JSON format is not yet considered a stable interface")
|
fmt.Fprintln(Stderr, "# Warning: this JSON format is not yet considered a stable interface")
|
||||||
}
|
}
|
||||||
|
|
||||||
dm, err := tailscale.CurrentDERPMap(ctx)
|
dm, err := tailscale.CurrentDERPMap(ctx)
|
||||||
@ -112,36 +112,36 @@ func printReport(dm *tailcfg.DERPMap, report *netcheck.Report) error {
|
|||||||
}
|
}
|
||||||
if j != nil {
|
if j != nil {
|
||||||
j = append(j, '\n')
|
j = append(j, '\n')
|
||||||
os.Stdout.Write(j)
|
Stdout.Write(j)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\nReport:\n")
|
printf("\nReport:\n")
|
||||||
fmt.Printf("\t* UDP: %v\n", report.UDP)
|
printf("\t* UDP: %v\n", report.UDP)
|
||||||
if report.GlobalV4 != "" {
|
if report.GlobalV4 != "" {
|
||||||
fmt.Printf("\t* IPv4: yes, %v\n", report.GlobalV4)
|
printf("\t* IPv4: yes, %v\n", report.GlobalV4)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\t* IPv4: (no addr found)\n")
|
printf("\t* IPv4: (no addr found)\n")
|
||||||
}
|
}
|
||||||
if report.GlobalV6 != "" {
|
if report.GlobalV6 != "" {
|
||||||
fmt.Printf("\t* IPv6: yes, %v\n", report.GlobalV6)
|
printf("\t* IPv6: yes, %v\n", report.GlobalV6)
|
||||||
} else if report.IPv6 {
|
} else if report.IPv6 {
|
||||||
fmt.Printf("\t* IPv6: (no addr found)\n")
|
printf("\t* IPv6: (no addr found)\n")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\t* IPv6: no\n")
|
printf("\t* IPv6: no\n")
|
||||||
}
|
}
|
||||||
fmt.Printf("\t* MappingVariesByDestIP: %v\n", report.MappingVariesByDestIP)
|
printf("\t* MappingVariesByDestIP: %v\n", report.MappingVariesByDestIP)
|
||||||
fmt.Printf("\t* HairPinning: %v\n", report.HairPinning)
|
printf("\t* HairPinning: %v\n", report.HairPinning)
|
||||||
fmt.Printf("\t* PortMapping: %v\n", portMapping(report))
|
printf("\t* PortMapping: %v\n", portMapping(report))
|
||||||
|
|
||||||
// When DERP latency checking failed,
|
// When DERP latency checking failed,
|
||||||
// magicsock will try to pick the DERP server that
|
// magicsock will try to pick the DERP server that
|
||||||
// most of your other nodes are also using
|
// most of your other nodes are also using
|
||||||
if len(report.RegionLatency) == 0 {
|
if len(report.RegionLatency) == 0 {
|
||||||
fmt.Printf("\t* Nearest DERP: unknown (no response to latency probes)\n")
|
printf("\t* Nearest DERP: unknown (no response to latency probes)\n")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\t* Nearest DERP: %v\n", dm.Regions[report.PreferredDERP].RegionName)
|
printf("\t* Nearest DERP: %v\n", dm.Regions[report.PreferredDERP].RegionName)
|
||||||
fmt.Printf("\t* DERP latency:\n")
|
printf("\t* DERP latency:\n")
|
||||||
var rids []int
|
var rids []int
|
||||||
for rid := range dm.Regions {
|
for rid := range dm.Regions {
|
||||||
rids = append(rids, rid)
|
rids = append(rids, rid)
|
||||||
@ -168,7 +168,7 @@ func printReport(dm *tailcfg.DERPMap, report *netcheck.Report) error {
|
|||||||
if netcheckArgs.verbose {
|
if netcheckArgs.verbose {
|
||||||
derpNum = fmt.Sprintf("derp%d, ", rid)
|
derpNum = fmt.Sprintf("derp%d, ", rid)
|
||||||
}
|
}
|
||||||
fmt.Printf("\t\t- %3s: %-7s (%s%s)\n", r.RegionCode, latency, derpNum, r.RegionName)
|
printf("\t\t- %3s: %-7s (%s%s)\n", r.RegionCode, latency, derpNum, r.RegionName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -89,7 +89,7 @@ func runPing(ctx context.Context, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if self {
|
if self {
|
||||||
fmt.Printf("%v is local Tailscale IP\n", ip)
|
printf("%v is local Tailscale IP\n", ip)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,14 +105,14 @@ func runPing(ctx context.Context, args []string) error {
|
|||||||
timer := time.NewTimer(pingArgs.timeout)
|
timer := time.NewTimer(pingArgs.timeout)
|
||||||
select {
|
select {
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
fmt.Printf("timeout waiting for ping reply\n")
|
printf("timeout waiting for ping reply\n")
|
||||||
case err := <-pumpErr:
|
case err := <-pumpErr:
|
||||||
return err
|
return err
|
||||||
case pr := <-prc:
|
case pr := <-prc:
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
if pr.Err != "" {
|
if pr.Err != "" {
|
||||||
if pr.IsLocalIP {
|
if pr.IsLocalIP {
|
||||||
fmt.Println(pr.Err)
|
outln(pr.Err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New(pr.Err)
|
return errors.New(pr.Err)
|
||||||
@ -132,7 +132,7 @@ func runPing(ctx context.Context, args []string) error {
|
|||||||
if pr.PeerAPIPort != 0 {
|
if pr.PeerAPIPort != 0 {
|
||||||
extra = fmt.Sprintf(", %d", pr.PeerAPIPort)
|
extra = fmt.Sprintf(", %d", pr.PeerAPIPort)
|
||||||
}
|
}
|
||||||
fmt.Printf("pong from %s (%s%s) via %v in %v\n", pr.NodeName, pr.NodeIP, extra, via, latency)
|
printf("pong from %s (%s%s) via %v in %v\n", pr.NodeName, pr.NodeIP, extra, via, latency)
|
||||||
if pingArgs.tsmp {
|
if pingArgs.tsmp {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ func runStatus(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("%s", j)
|
printf("%s", j)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if statusArgs.web {
|
if statusArgs.web {
|
||||||
@ -79,7 +79,7 @@ func runStatus(ctx context.Context, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
statusURL := interfaces.HTTPOfListener(ln)
|
statusURL := interfaces.HTTPOfListener(ln)
|
||||||
fmt.Printf("Serving Tailscale status at %v ...\n", statusURL)
|
printf("Serving Tailscale status at %v ...\n", statusURL)
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
ln.Close()
|
ln.Close()
|
||||||
@ -108,30 +108,30 @@ func runStatus(ctx context.Context, args []string) error {
|
|||||||
|
|
||||||
switch st.BackendState {
|
switch st.BackendState {
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(os.Stderr, "unexpected state: %s\n", st.BackendState)
|
fmt.Fprintf(Stderr, "unexpected state: %s\n", st.BackendState)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
case ipn.Stopped.String():
|
case ipn.Stopped.String():
|
||||||
fmt.Println("Tailscale is stopped.")
|
outln("Tailscale is stopped.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
case ipn.NeedsLogin.String():
|
case ipn.NeedsLogin.String():
|
||||||
fmt.Println("Logged out.")
|
outln("Logged out.")
|
||||||
if st.AuthURL != "" {
|
if st.AuthURL != "" {
|
||||||
fmt.Printf("\nLog in at: %s\n", st.AuthURL)
|
printf("\nLog in at: %s\n", st.AuthURL)
|
||||||
}
|
}
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
case ipn.NeedsMachineAuth.String():
|
case ipn.NeedsMachineAuth.String():
|
||||||
fmt.Println("Machine is not yet authorized by tailnet admin.")
|
outln("Machine is not yet authorized by tailnet admin.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
case ipn.Running.String(), ipn.Starting.String():
|
case ipn.Running.String(), ipn.Starting.String():
|
||||||
// Run below.
|
// Run below.
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(st.Health) > 0 {
|
if len(st.Health) > 0 {
|
||||||
fmt.Printf("# Health check:\n")
|
printf("# Health check:\n")
|
||||||
for _, m := range st.Health {
|
for _, m := range st.Health {
|
||||||
fmt.Printf("# - %s\n", m)
|
printf("# - %s\n", m)
|
||||||
}
|
}
|
||||||
fmt.Println()
|
outln()
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
@ -190,7 +190,7 @@ func runStatus(ctx context.Context, args []string) error {
|
|||||||
printPS(ps)
|
printPS(ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os.Stdout.Write(buf.Bytes())
|
Stdout.Write(buf.Bytes())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ func (a upArgsT) getAuthKey() (string, error) {
|
|||||||
var upArgs upArgsT
|
var upArgs upArgsT
|
||||||
|
|
||||||
func warnf(format string, args ...interface{}) {
|
func warnf(format string, args ...interface{}) {
|
||||||
fmt.Printf("Warning: "+format+"\n", args...)
|
printf("Warning: "+format+"\n", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -435,12 +435,12 @@ func runUp(ctx context.Context, args []string) error {
|
|||||||
startLoginInteractive()
|
startLoginInteractive()
|
||||||
case ipn.NeedsMachineAuth:
|
case ipn.NeedsMachineAuth:
|
||||||
printed = true
|
printed = true
|
||||||
fmt.Fprintf(os.Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s\n\n", prefs.AdminPageURL())
|
fmt.Fprintf(Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s\n\n", prefs.AdminPageURL())
|
||||||
case ipn.Running:
|
case ipn.Running:
|
||||||
// Done full authentication process
|
// Done full authentication process
|
||||||
if printed {
|
if printed {
|
||||||
// Only need to print an update if we printed the "please click" message earlier.
|
// Only need to print an update if we printed the "please click" message earlier.
|
||||||
fmt.Fprintf(os.Stderr, "Success.\n")
|
fmt.Fprintf(Stderr, "Success.\n")
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case running <- true:
|
case running <- true:
|
||||||
@ -451,13 +451,13 @@ func runUp(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
if url := n.BrowseToURL; url != nil && printAuthURL(*url) {
|
if url := n.BrowseToURL; url != nil && printAuthURL(*url) {
|
||||||
printed = true
|
printed = true
|
||||||
fmt.Fprintf(os.Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", *url)
|
fmt.Fprintf(Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", *url)
|
||||||
if upArgs.qr {
|
if upArgs.qr {
|
||||||
q, err := qrcode.New(*url, qrcode.Medium)
|
q, err := qrcode.New(*url, qrcode.Medium)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("QR code error: %v", err)
|
log.Printf("QR code error: %v", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", q.ToString(false))
|
fmt.Fprintf(Stderr, "%s\n", q.ToString(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
@ -36,16 +35,16 @@ func runVersion(ctx context.Context, args []string) error {
|
|||||||
log.Fatalf("too many non-flag arguments: %q", args)
|
log.Fatalf("too many non-flag arguments: %q", args)
|
||||||
}
|
}
|
||||||
if !versionArgs.daemon {
|
if !versionArgs.daemon {
|
||||||
fmt.Println(version.String())
|
outln(version.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Client: %s\n", version.String())
|
printf("Client: %s\n", version.String())
|
||||||
|
|
||||||
st, err := tailscale.StatusWithoutPeers(ctx)
|
st, err := tailscale.StatusWithoutPeers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Daemon: %s\n", st.Version)
|
printf("Daemon: %s\n", st.Version)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user