mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-18 12:32:13 +00:00
ipn: move Options.Notify to its own method
We already had SetNotifyCallback elsewhere on controlclient, so use that name. Baby steps towards some CLI refactor work. Updates tailscale/tailscale#1436
This commit is contained in:
parent
d488678fdc
commit
799973a68d
@ -238,44 +238,44 @@ func runUp(ctx context.Context, args []string) error {
|
|||||||
startLoginInteractive := func() { loginOnce.Do(func() { bc.StartLoginInteractive() }) }
|
startLoginInteractive := func() { loginOnce.Do(func() { bc.StartLoginInteractive() }) }
|
||||||
|
|
||||||
bc.SetPrefs(prefs)
|
bc.SetPrefs(prefs)
|
||||||
|
bc.SetNotifyCallback(func(n ipn.Notify) {
|
||||||
|
if n.ErrMessage != nil {
|
||||||
|
msg := *n.ErrMessage
|
||||||
|
if msg == ipn.ErrMsgPermissionDenied {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
msg += " (Tailscale service in use by other user?)"
|
||||||
|
default:
|
||||||
|
msg += " (try 'sudo tailscale up [...]')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fatalf("backend error: %v\n", msg)
|
||||||
|
}
|
||||||
|
if s := n.State; s != nil {
|
||||||
|
switch *s {
|
||||||
|
case ipn.NeedsLogin:
|
||||||
|
printed = true
|
||||||
|
startLoginInteractive()
|
||||||
|
case ipn.NeedsMachineAuth:
|
||||||
|
printed = true
|
||||||
|
fmt.Fprintf(os.Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s/admin/machines\n\n", upArgs.server)
|
||||||
|
case ipn.Starting, ipn.Running:
|
||||||
|
// Done full authentication process
|
||||||
|
if printed {
|
||||||
|
// Only need to print an update if we printed the "please click" message earlier.
|
||||||
|
fmt.Fprintf(os.Stderr, "Success.\n")
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if url := n.BrowseToURL; url != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", *url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
opts := ipn.Options{
|
opts := ipn.Options{
|
||||||
StateKey: ipn.GlobalDaemonStateKey,
|
StateKey: ipn.GlobalDaemonStateKey,
|
||||||
AuthKey: upArgs.authKey,
|
AuthKey: upArgs.authKey,
|
||||||
Notify: func(n ipn.Notify) {
|
|
||||||
if n.ErrMessage != nil {
|
|
||||||
msg := *n.ErrMessage
|
|
||||||
if msg == ipn.ErrMsgPermissionDenied {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows":
|
|
||||||
msg += " (Tailscale service in use by other user?)"
|
|
||||||
default:
|
|
||||||
msg += " (try 'sudo tailscale up [...]')"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fatalf("backend error: %v\n", msg)
|
|
||||||
}
|
|
||||||
if s := n.State; s != nil {
|
|
||||||
switch *s {
|
|
||||||
case ipn.NeedsLogin:
|
|
||||||
printed = true
|
|
||||||
startLoginInteractive()
|
|
||||||
case ipn.NeedsMachineAuth:
|
|
||||||
printed = true
|
|
||||||
fmt.Fprintf(os.Stderr, "\nTo authorize your machine, visit (as admin):\n\n\t%s/admin/machines\n\n", upArgs.server)
|
|
||||||
case ipn.Starting, ipn.Running:
|
|
||||||
// Done full authentication process
|
|
||||||
if printed {
|
|
||||||
// Only need to print an update if we printed the "please click" message earlier.
|
|
||||||
fmt.Fprintf(os.Stderr, "Success.\n")
|
|
||||||
}
|
|
||||||
cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if url := n.BrowseToURL; url != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "\nTo authenticate, visit:\n\n\t%s\n\n", *url)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// On Windows, we still run in mostly the "legacy" way that
|
// On Windows, we still run in mostly the "legacy" way that
|
||||||
@ -293,8 +293,7 @@ func runUp(ctx context.Context, args []string) error {
|
|||||||
opts.Prefs = prefs
|
opts.Prefs = prefs
|
||||||
}
|
}
|
||||||
|
|
||||||
// We still have to Start right now because it's the only way to
|
// We still have to Start for now. This causes a bunch of churn
|
||||||
// set up notifications and whatnot. This causes a bunch of churn
|
|
||||||
// every time the CLI touches anything.
|
// every time the CLI touches anything.
|
||||||
//
|
//
|
||||||
// TODO(danderson): redo the frontend/backend API to assume
|
// TODO(danderson): redo the frontend/backend API to assume
|
||||||
|
@ -259,30 +259,30 @@ func tailscaleUp(ctx context.Context) (authURL string, retErr error) {
|
|||||||
c, bc, ctx, cancel := connect(ctx)
|
c, bc, ctx, cancel := connect(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
bc.SetNotifyCallback(func(n ipn.Notify) {
|
||||||
|
if n.ErrMessage != nil {
|
||||||
|
msg := *n.ErrMessage
|
||||||
|
if msg == ipn.ErrMsgPermissionDenied {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
msg += " (Tailscale service in use by other user?)"
|
||||||
|
default:
|
||||||
|
msg += " (try 'sudo tailscale up [...]')"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retErr = fmt.Errorf("backend error: %v", msg)
|
||||||
|
cancel()
|
||||||
|
} else if url := n.BrowseToURL; url != nil {
|
||||||
|
authURL = *url
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
bc.SetPrefs(prefs)
|
bc.SetPrefs(prefs)
|
||||||
|
|
||||||
opts := ipn.Options{
|
bc.Start(ipn.Options{
|
||||||
StateKey: ipn.GlobalDaemonStateKey,
|
StateKey: ipn.GlobalDaemonStateKey,
|
||||||
Notify: func(n ipn.Notify) {
|
})
|
||||||
if n.ErrMessage != nil {
|
|
||||||
msg := *n.ErrMessage
|
|
||||||
if msg == ipn.ErrMsgPermissionDenied {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows":
|
|
||||||
msg += " (Tailscale service in use by other user?)"
|
|
||||||
default:
|
|
||||||
msg += " (try 'sudo tailscale up [...]')"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retErr = fmt.Errorf("backend error: %v", msg)
|
|
||||||
cancel()
|
|
||||||
} else if url := n.BrowseToURL; url != nil {
|
|
||||||
authURL = *url
|
|
||||||
cancel()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
bc.Start(opts)
|
|
||||||
bc.StartLoginInteractive()
|
bc.StartLoginInteractive()
|
||||||
pump(ctx, bc, c)
|
pump(ctx, bc, c)
|
||||||
|
|
||||||
|
@ -122,8 +122,6 @@ type Options struct {
|
|||||||
// TODO(danderson): remove some time after the transition to
|
// TODO(danderson): remove some time after the transition to
|
||||||
// tailscaled is done.
|
// tailscaled is done.
|
||||||
LegacyConfigPath string
|
LegacyConfigPath string
|
||||||
// Notify is called when backend events happen.
|
|
||||||
Notify func(Notify) `json:"-"`
|
|
||||||
// HTTPTestClient is an optional HTTP client to pass to controlclient
|
// HTTPTestClient is an optional HTTP client to pass to controlclient
|
||||||
// (for tests only).
|
// (for tests only).
|
||||||
HTTPTestClient *http.Client
|
HTTPTestClient *http.Client
|
||||||
@ -135,6 +133,9 @@ type Options struct {
|
|||||||
// (It has nothing to do with the interface between the backends
|
// (It has nothing to do with the interface between the backends
|
||||||
// and the cloud control plane.)
|
// and the cloud control plane.)
|
||||||
type Backend interface {
|
type Backend interface {
|
||||||
|
// SetNotifyCallback sets the callback to be called on updates
|
||||||
|
// from the backend to the client.
|
||||||
|
SetNotifyCallback(func(Notify))
|
||||||
// Start starts or restarts the backend, typically when a
|
// Start starts or restarts the backend, typically when a
|
||||||
// frontend client connects.
|
// frontend client connects.
|
||||||
Start(Options) error
|
Start(Options) error
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package ipn
|
package ipn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
@ -21,18 +20,28 @@ type FakeBackend struct {
|
|||||||
|
|
||||||
func (b *FakeBackend) Start(opts Options) error {
|
func (b *FakeBackend) Start(opts Options) error {
|
||||||
b.serverURL = opts.Prefs.ControlURL
|
b.serverURL = opts.Prefs.ControlURL
|
||||||
if opts.Notify == nil {
|
if b.notify == nil {
|
||||||
log.Fatalf("FakeBackend.Start: opts.Notify is nil\n")
|
panic("FakeBackend.Start: SetNotifyCallback not called")
|
||||||
}
|
}
|
||||||
b.notify = opts.Notify
|
|
||||||
b.notify(Notify{Prefs: opts.Prefs})
|
|
||||||
nl := NeedsLogin
|
nl := NeedsLogin
|
||||||
b.notify(Notify{State: &nl})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{Prefs: opts.Prefs})
|
||||||
|
b.notify(Notify{State: &nl})
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *FakeBackend) SetNotifyCallback(notify func(Notify)) {
|
||||||
|
if notify == nil {
|
||||||
|
panic("FakeBackend.SetNotifyCallback: notify is nil")
|
||||||
|
}
|
||||||
|
b.notify = notify
|
||||||
|
}
|
||||||
|
|
||||||
func (b *FakeBackend) newState(s State) {
|
func (b *FakeBackend) newState(s State) {
|
||||||
b.notify(Notify{State: &s})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{State: &s})
|
||||||
|
}
|
||||||
if s == Running {
|
if s == Running {
|
||||||
b.live = true
|
b.live = true
|
||||||
} else {
|
} else {
|
||||||
@ -42,7 +51,9 @@ func (b *FakeBackend) newState(s State) {
|
|||||||
|
|
||||||
func (b *FakeBackend) StartLoginInteractive() {
|
func (b *FakeBackend) StartLoginInteractive() {
|
||||||
u := b.serverURL + "/this/is/fake"
|
u := b.serverURL + "/this/is/fake"
|
||||||
b.notify(Notify{BrowseToURL: &u})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{BrowseToURL: &u})
|
||||||
|
}
|
||||||
b.login()
|
b.login()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +65,14 @@ func (b *FakeBackend) login() {
|
|||||||
b.newState(NeedsMachineAuth)
|
b.newState(NeedsMachineAuth)
|
||||||
b.newState(Stopped)
|
b.newState(Stopped)
|
||||||
// TODO(apenwarr): Fill in a more interesting netmap here.
|
// TODO(apenwarr): Fill in a more interesting netmap here.
|
||||||
b.notify(Notify{NetMap: &netmap.NetworkMap{}})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{NetMap: &netmap.NetworkMap{}})
|
||||||
|
}
|
||||||
b.newState(Starting)
|
b.newState(Starting)
|
||||||
// TODO(apenwarr): Fill in a more interesting status.
|
// TODO(apenwarr): Fill in a more interesting status.
|
||||||
b.notify(Notify{Engine: &EngineStatus{}})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{Engine: &EngineStatus{}})
|
||||||
|
}
|
||||||
b.newState(Running)
|
b.newState(Running)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +85,9 @@ func (b *FakeBackend) SetPrefs(new *Prefs) {
|
|||||||
panic("FakeBackend.SetPrefs got nil prefs")
|
panic("FakeBackend.SetPrefs got nil prefs")
|
||||||
}
|
}
|
||||||
|
|
||||||
b.notify(Notify{Prefs: new.Clone()})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{Prefs: new.Clone()})
|
||||||
|
}
|
||||||
if new.WantRunning && !b.live {
|
if new.WantRunning && !b.live {
|
||||||
b.newState(Starting)
|
b.newState(Starting)
|
||||||
b.newState(Running)
|
b.newState(Running)
|
||||||
@ -87,13 +104,19 @@ func (b *FakeBackend) EditPrefs(mp *MaskedPrefs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *FakeBackend) RequestEngineStatus() {
|
func (b *FakeBackend) RequestEngineStatus() {
|
||||||
b.notify(Notify{Engine: &EngineStatus{}})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{Engine: &EngineStatus{}})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *FakeBackend) FakeExpireAfter(x time.Duration) {
|
func (b *FakeBackend) FakeExpireAfter(x time.Duration) {
|
||||||
b.notify(Notify{NetMap: &netmap.NetworkMap{}})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{NetMap: &netmap.NetworkMap{}})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *FakeBackend) Ping(ip string, useTSMP bool) {
|
func (b *FakeBackend) Ping(ip string, useTSMP bool) {
|
||||||
b.notify(Notify{PingResult: &ipnstate.PingResult{}})
|
if b.notify != nil {
|
||||||
|
b.notify(Notify{PingResult: &ipnstate.PingResult{}})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,25 +15,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Handle struct {
|
type Handle struct {
|
||||||
frontendLogID string
|
b Backend
|
||||||
b Backend
|
logf logger.Logf
|
||||||
xnotify func(Notify)
|
|
||||||
logf logger.Logf
|
|
||||||
|
|
||||||
// Mutex protects everything below
|
// Mutex protects everything below
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
xnotify func(Notify)
|
||||||
|
frontendLogID string
|
||||||
netmapCache *netmap.NetworkMap
|
netmapCache *netmap.NetworkMap
|
||||||
engineStatusCache EngineStatus
|
engineStatusCache EngineStatus
|
||||||
stateCache State
|
stateCache State
|
||||||
prefsCache *Prefs
|
prefsCache *Prefs
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandle(b Backend, logf logger.Logf, opts Options) (*Handle, error) {
|
func NewHandle(b Backend, logf logger.Logf, notify func(Notify), opts Options) (*Handle, error) {
|
||||||
h := &Handle{
|
h := &Handle{
|
||||||
b: b,
|
b: b,
|
||||||
logf: logf,
|
logf: logf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.SetNotifyCallback(notify)
|
||||||
err := h.Start(opts)
|
err := h.Start(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -42,18 +43,25 @@ func NewHandle(b Backend, logf logger.Logf, opts Options) (*Handle, error) {
|
|||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handle) SetNotifyCallback(notify func(Notify)) {
|
||||||
|
h.mu.Lock()
|
||||||
|
h.xnotify = notify
|
||||||
|
h.mu.Unlock()
|
||||||
|
|
||||||
|
h.b.SetNotifyCallback(h.notify)
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handle) Start(opts Options) error {
|
func (h *Handle) Start(opts Options) error {
|
||||||
|
h.mu.Lock()
|
||||||
h.frontendLogID = opts.FrontendLogID
|
h.frontendLogID = opts.FrontendLogID
|
||||||
h.xnotify = opts.Notify
|
|
||||||
h.netmapCache = nil
|
h.netmapCache = nil
|
||||||
h.engineStatusCache = EngineStatus{}
|
h.engineStatusCache = EngineStatus{}
|
||||||
h.stateCache = NoState
|
h.stateCache = NoState
|
||||||
if opts.Prefs != nil {
|
if opts.Prefs != nil {
|
||||||
h.prefsCache = opts.Prefs.Clone()
|
h.prefsCache = opts.Prefs.Clone()
|
||||||
}
|
}
|
||||||
xopts := opts
|
h.mu.Unlock()
|
||||||
xopts.Notify = h.notify
|
return h.b.Start(opts)
|
||||||
return h.b.Start(xopts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handle) Reset() {
|
func (h *Handle) Reset() {
|
||||||
|
@ -519,6 +519,12 @@ func (b *LocalBackend) setWgengineStatus(s *wgengine.Status, err error) {
|
|||||||
b.send(ipn.Notify{Engine: &es})
|
b.send(ipn.Notify{Engine: &es})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LocalBackend) SetNotifyCallback(notify func(ipn.Notify)) {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
b.notify = notify
|
||||||
|
}
|
||||||
|
|
||||||
// Start applies the configuration specified in opts, and starts the
|
// Start applies the configuration specified in opts, and starts the
|
||||||
// state machine.
|
// state machine.
|
||||||
//
|
//
|
||||||
@ -585,7 +591,6 @@ func (b *LocalBackend) Start(opts ipn.Options) error {
|
|||||||
}
|
}
|
||||||
applyPrefsToHostinfo(hostinfo, b.prefs)
|
applyPrefsToHostinfo(hostinfo, b.prefs)
|
||||||
|
|
||||||
b.notify = opts.Notify
|
|
||||||
b.setNetMapLocked(nil)
|
b.setNetMapLocked(nil)
|
||||||
persistv := b.prefs.Persist
|
persistv := b.prefs.Persist
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
|
@ -189,8 +189,8 @@ func (bs *BackendServer) GotCommand(ctx context.Context, cmd *Command) error {
|
|||||||
bs.GotQuit = true
|
bs.GotQuit = true
|
||||||
return errors.New("Quit command received")
|
return errors.New("Quit command received")
|
||||||
} else if c := cmd.Start; c != nil {
|
} else if c := cmd.Start; c != nil {
|
||||||
|
bs.b.SetNotifyCallback(bs.send)
|
||||||
opts := c.Opts
|
opts := c.Opts
|
||||||
opts.Notify = bs.send
|
|
||||||
return bs.b.Start(opts)
|
return bs.b.Start(opts)
|
||||||
} else if c := cmd.StartLoginInteractive; c != nil {
|
} else if c := cmd.StartLoginInteractive; c != nil {
|
||||||
bs.b.StartLoginInteractive()
|
bs.b.StartLoginInteractive()
|
||||||
@ -287,8 +287,6 @@ func (bc *BackendClient) Quit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bc *BackendClient) Start(opts Options) error {
|
func (bc *BackendClient) Start(opts Options) error {
|
||||||
bc.notify = opts.Notify
|
|
||||||
opts.Notify = nil // server can't call our function pointer
|
|
||||||
bc.send(Command{Start: &StartArgs{Opts: opts}})
|
bc.send(Command{Start: &StartArgs{Opts: opts}})
|
||||||
return nil // remote Start() errors must be handled remotely
|
return nil // remote Start() errors must be handled remotely
|
||||||
}
|
}
|
||||||
|
@ -90,13 +90,11 @@ func TestClientServer(t *testing.T) {
|
|||||||
bc = NewBackendClient(clogf, clientToServer)
|
bc = NewBackendClient(clogf, clientToServer)
|
||||||
|
|
||||||
ch := make(chan Notify, 256)
|
ch := make(chan Notify, 256)
|
||||||
h, err := NewHandle(bc, clogf, Options{
|
notify := func(n Notify) { ch <- n }
|
||||||
|
h, err := NewHandle(bc, clogf, notify, Options{
|
||||||
Prefs: &Prefs{
|
Prefs: &Prefs{
|
||||||
ControlURL: "http://example.com/fake",
|
ControlURL: "http://example.com/fake",
|
||||||
},
|
},
|
||||||
Notify: func(n Notify) {
|
|
||||||
ch <- n
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewHandle error: %v\n", err)
|
t.Fatalf("NewHandle error: %v\n", err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user