ipn/{ipnlocal,ipnstate,localapi}: add localapi endpoints for client self-update (#10188)

* ipn/{ipnlocal,ipnstate,localapi}: add localapi endpoints for client self-update

Updates #10187.

Signed-off-by: Naman Sood <mail@nsood.in>

* depaware

Updates #10187.

Signed-off-by: Naman Sood <mail@nsood.in>

* address review feedback

Signed-off-by: Naman Sood <mail@nsood.in>

---------

Signed-off-by: Naman Sood <mail@nsood.in>
This commit is contained in:
Naman Sood
2023-11-09 13:00:47 -08:00
committed by GitHub
parent 55cd5c575b
commit e57fd9cda4
4 changed files with 152 additions and 3 deletions

View File

@@ -34,6 +34,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"tailscale.com/appc"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/clientupdate"
"tailscale.com/control/controlclient"
"tailscale.com/control/controlknobs"
"tailscale.com/doctor"
@@ -265,8 +266,10 @@ type LocalBackend struct {
directFileDoFinalRename bool // false on macOS, true on several NAS platforms
componentLogUntil map[string]componentLogState
// c2nUpdateStatus is the status of c2n-triggered client update.
c2nUpdateStatus updateStatus
currentUser ipnauth.WindowsToken
c2nUpdateStatus updateStatus
currentUser ipnauth.WindowsToken
selfUpdateProgress []ipnstate.UpdateProgress
lastSelfUpdateState ipnstate.SelfUpdateStatus
// ServeConfig fields. (also guarded by mu)
lastServeConfJSON mem.RO // last JSON that was parsed into serveConfig
@@ -374,6 +377,8 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
loginFlags: loginFlags,
clock: clock,
activeWatchSessions: make(set.Set[string]),
selfUpdateProgress: make([]ipnstate.UpdateProgress, 0),
lastSelfUpdateState: ipnstate.UpdateFinished,
}
netMon := sys.NetMon.Get()
@@ -5539,6 +5544,54 @@ func (b *LocalBackend) DebugBreakDERPConns() error {
return b.magicConn().DebugBreakDERPConns()
}
func (b *LocalBackend) pushSelfUpdateProgress(up ipnstate.UpdateProgress) {
b.mu.Lock()
defer b.mu.Unlock()
b.selfUpdateProgress = append(b.selfUpdateProgress, up)
b.lastSelfUpdateState = up.Status
}
func (b *LocalBackend) clearSelfUpdateProgress() {
b.mu.Lock()
defer b.mu.Unlock()
b.selfUpdateProgress = make([]ipnstate.UpdateProgress, 0)
b.lastSelfUpdateState = ipnstate.UpdateFinished
}
func (b *LocalBackend) GetSelfUpdateProgress() []ipnstate.UpdateProgress {
b.mu.Lock()
defer b.mu.Unlock()
res := make([]ipnstate.UpdateProgress, len(b.selfUpdateProgress))
copy(res, b.selfUpdateProgress)
return res
}
func (b *LocalBackend) DoSelfUpdate() {
b.mu.Lock()
updateState := b.lastSelfUpdateState
b.mu.Unlock()
// don't start an update if one is already in progress
if updateState == ipnstate.UpdateInProgress {
return
}
b.clearSelfUpdateProgress()
b.pushSelfUpdateProgress(ipnstate.NewUpdateProgress(ipnstate.UpdateInProgress, ""))
up, err := clientupdate.NewUpdater(clientupdate.Arguments{
Logf: func(format string, args ...any) {
b.pushSelfUpdateProgress(ipnstate.NewUpdateProgress(ipnstate.UpdateInProgress, fmt.Sprintf(format, args...)))
},
})
if err != nil {
b.pushSelfUpdateProgress(ipnstate.NewUpdateProgress(ipnstate.UpdateFailed, err.Error()))
}
err = up.Update()
if err != nil {
b.pushSelfUpdateProgress(ipnstate.NewUpdateProgress(ipnstate.UpdateFailed, err.Error()))
} else {
b.pushSelfUpdateProgress(ipnstate.NewUpdateProgress(ipnstate.UpdateFinished, "tailscaled did not restart; please restart Tailscale manually."))
}
}
// ObserveDNSResponse passes a DNS response from the PeerAPI DNS server to the
// App Connector to enable route discovery.
func (b *LocalBackend) ObserveDNSResponse(res []byte) {