cmd/tailscale/cli: add basic 'down' subcommand
RELNOTE=yes
This commit is contained in:
parent
f27a57911b
commit
483141094c
|
@ -31,7 +31,7 @@ func ActLikeCLI() bool {
|
|||
return false
|
||||
}
|
||||
switch os.Args[1] {
|
||||
case "up", "status", "netcheck", "ping", "version",
|
||||
case "up", "down", "status", "netcheck", "ping", "version",
|
||||
"debug",
|
||||
"-V", "--version", "-h", "--help":
|
||||
return true
|
||||
|
@ -58,6 +58,7 @@ change in the future.
|
|||
`),
|
||||
Subcommands: []*ffcli.Command{
|
||||
upCmd,
|
||||
downCmd,
|
||||
netcheckCmd,
|
||||
statusCmd,
|
||||
pingCmd,
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/peterbourgon/ff/v2/ffcli"
|
||||
"tailscale.com/ipn"
|
||||
)
|
||||
|
||||
var downCmd = &ffcli.Command{
|
||||
Name: "down",
|
||||
ShortUsage: "down",
|
||||
ShortHelp: "Disconnect from Tailscale",
|
||||
|
||||
Exec: runDown,
|
||||
}
|
||||
|
||||
func runDown(ctx context.Context, args []string) error {
|
||||
if len(args) > 0 {
|
||||
log.Fatalf("too many non-flag arguments: %q", args)
|
||||
}
|
||||
|
||||
c, bc, ctx, cancel := connect(ctx)
|
||||
defer cancel()
|
||||
|
||||
timer := time.AfterFunc(5*time.Second, func() {
|
||||
log.Fatalf("timeout running stop")
|
||||
})
|
||||
defer timer.Stop()
|
||||
|
||||
bc.SetNotifyCallback(func(n ipn.Notify) {
|
||||
if n.ErrMessage != nil {
|
||||
log.Fatal(*n.ErrMessage)
|
||||
}
|
||||
if n.Status != nil {
|
||||
cur := n.Status.BackendState
|
||||
switch cur {
|
||||
case "Stopped":
|
||||
log.Printf("already stopped")
|
||||
cancel()
|
||||
default:
|
||||
log.Printf("was in state %q", cur)
|
||||
}
|
||||
return
|
||||
}
|
||||
if n.State != nil {
|
||||
log.Printf("now in state %q", *n.State)
|
||||
if *n.State == ipn.Stopped {
|
||||
cancel()
|
||||
}
|
||||
return
|
||||
}
|
||||
log.Printf("Notify: %#v", n)
|
||||
})
|
||||
|
||||
bc.RequestStatus()
|
||||
bc.SetWantRunning(false)
|
||||
pump(ctx, bc, c)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -144,6 +144,9 @@ type Backend interface {
|
|||
// WantRunning. This may cause the wireguard engine to
|
||||
// reconfigure or stop.
|
||||
SetPrefs(*Prefs)
|
||||
// SetWantRunning is like SetPrefs but sets only the
|
||||
// WantRunning field.
|
||||
SetWantRunning(wantRunning bool)
|
||||
// RequestEngineStatus polls for an update from the wireguard
|
||||
// engine. Only needed if you want to display byte
|
||||
// counts. Connection events are emitted automatically without
|
||||
|
|
|
@ -79,6 +79,10 @@ func (b *FakeBackend) SetPrefs(new *Prefs) {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *FakeBackend) SetWantRunning(v bool) {
|
||||
b.SetPrefs(&Prefs{WantRunning: v})
|
||||
}
|
||||
|
||||
func (b *FakeBackend) RequestEngineStatus() {
|
||||
b.notify(Notify{Engine: &EngineStatus{}})
|
||||
}
|
||||
|
|
|
@ -90,6 +90,12 @@ type StatusBuilder struct {
|
|||
st Status
|
||||
}
|
||||
|
||||
func (sb *StatusBuilder) SetBackendState(v string) {
|
||||
sb.mu.Lock()
|
||||
defer sb.mu.Unlock()
|
||||
sb.st.BackendState = v
|
||||
}
|
||||
|
||||
func (sb *StatusBuilder) Status() *Status {
|
||||
sb.mu.Lock()
|
||||
defer sb.mu.Unlock()
|
||||
|
|
14
ipn/local.go
14
ipn/local.go
|
@ -144,6 +144,8 @@ func (b *LocalBackend) UpdateStatus(sb *ipnstate.StatusBuilder) {
|
|||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
sb.SetBackendState(b.state.String())
|
||||
|
||||
// TODO: hostinfo, and its networkinfo
|
||||
// TODO: EngineStatus copy (and deprecate it?)
|
||||
if b.netMap != nil {
|
||||
|
@ -796,6 +798,18 @@ func (b *LocalBackend) shieldsAreUp() bool {
|
|||
return b.prefs.ShieldsUp
|
||||
}
|
||||
|
||||
func (b *LocalBackend) SetWantRunning(wantRunning bool) {
|
||||
b.mu.Lock()
|
||||
new := b.prefs.Clone()
|
||||
b.mu.Unlock()
|
||||
if new.WantRunning == wantRunning {
|
||||
return
|
||||
}
|
||||
new.WantRunning = wantRunning
|
||||
b.logf("SetWantRunning: %v", wantRunning)
|
||||
b.SetPrefs(new)
|
||||
}
|
||||
|
||||
// SetPrefs saves new user preferences and propagates them throughout
|
||||
// the system. Implements Backend.
|
||||
func (b *LocalBackend) SetPrefs(new *Prefs) {
|
||||
|
|
|
@ -57,6 +57,7 @@ type Command struct {
|
|||
Login *oauth2.Token
|
||||
Logout *NoArgs
|
||||
SetPrefs *SetPrefsArgs
|
||||
SetWantRunning *bool
|
||||
RequestEngineStatus *NoArgs
|
||||
RequestStatus *NoArgs
|
||||
FakeExpireAfter *FakeExpireAfterArgs
|
||||
|
@ -144,6 +145,9 @@ func (bs *BackendServer) GotCommand(cmd *Command) error {
|
|||
} else if c := cmd.SetPrefs; c != nil {
|
||||
bs.b.SetPrefs(c.New)
|
||||
return nil
|
||||
} else if c := cmd.SetWantRunning; c != nil {
|
||||
bs.b.SetWantRunning(*c)
|
||||
return nil
|
||||
} else if c := cmd.RequestEngineStatus; c != nil {
|
||||
bs.b.RequestEngineStatus()
|
||||
return nil
|
||||
|
@ -266,6 +270,10 @@ func (bc *BackendClient) Ping(ip string) {
|
|||
bc.send(Command{Ping: &PingArgs{IP: ip}})
|
||||
}
|
||||
|
||||
func (bc *BackendClient) SetWantRunning(v bool) {
|
||||
bc.send(Command{SetWantRunning: &v})
|
||||
}
|
||||
|
||||
// MaxMessageSize is the maximum message size, in bytes.
|
||||
const MaxMessageSize = 10 << 20
|
||||
|
||||
|
|
Loading…
Reference in New Issue