mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 13:18:53 +00:00
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:
@@ -27,6 +27,7 @@ import (
|
||||
"time"
|
||||
|
||||
"tailscale.com/client/tailscale/apitype"
|
||||
"tailscale.com/clientupdate"
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/health"
|
||||
"tailscale.com/hostinfo"
|
||||
@@ -125,6 +126,9 @@ var handler = map[string]localAPIHandler{
|
||||
"watch-ipn-bus": (*Handler).serveWatchIPNBus,
|
||||
"whois": (*Handler).serveWhoIs,
|
||||
"query-feature": (*Handler).serveQueryFeature,
|
||||
"update/check": (*Handler).serveUpdateCheck,
|
||||
"update/install": (*Handler).serveUpdateInstall,
|
||||
"update/progress": (*Handler).serveUpdateProgress,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -2418,6 +2422,75 @@ func (h *Handler) serveDebugLog(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// serveUpdateCheck returns the ClientVersion from Status, which contains
|
||||
// information on whether an update is available, and if so, what version,
|
||||
// *if* we support auto-updates on this platform. If we don't, this endpoint
|
||||
// always returns a ClientVersion saying we're running the newest version.
|
||||
// Effectively, it tells us whether serveUpdateInstall will be able to install
|
||||
// an update for us.
|
||||
func (h *Handler) serveUpdateCheck(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := clientupdate.NewUpdater(clientupdate.Arguments{
|
||||
ForAutoUpdate: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if we don't support auto-update, just say that we're up to date
|
||||
if errors.Is(err, errors.ErrUnsupported) {
|
||||
json.NewEncoder(w).Encode(tailcfg.ClientVersion{RunningLatest: true})
|
||||
} else {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cv := h.b.StatusWithoutPeers().ClientVersion
|
||||
// ipnstate.Status documentation notes that ClientVersion may be nil on some
|
||||
// platforms where this information is unavailable. In that case, return a
|
||||
// ClientVersion that says we're up to date, since we have no information on
|
||||
// whether an update is possible.
|
||||
if cv == nil {
|
||||
cv = &tailcfg.ClientVersion{RunningLatest: true}
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(cv)
|
||||
}
|
||||
|
||||
// serveUpdateInstall sends a request to the LocalBackend to start a Tailscale
|
||||
// self-update. A successful response does not indicate whether the update
|
||||
// succeeded, only that the request was accepted. Clients should use
|
||||
// serveUpdateProgress after pinging this endpoint to check how the update is
|
||||
// going.
|
||||
func (h *Handler) serveUpdateInstall(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
|
||||
go h.b.DoSelfUpdate()
|
||||
}
|
||||
|
||||
// serveUpdateProgress returns the status of an in-progress Tailscale self-update.
|
||||
// This is provided as a slice of ipnstate.UpdateProgress structs with various
|
||||
// log messages in order from oldest to newest. If an update is not in progress,
|
||||
// the returned slice will be empty.
|
||||
func (h *Handler) serveUpdateProgress(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
ups := h.b.GetSelfUpdateProgress()
|
||||
|
||||
json.NewEncoder(w).Encode(ups)
|
||||
}
|
||||
|
||||
var (
|
||||
metricInvalidRequests = clientmetric.NewCounter("localapi_invalid_requests")
|
||||
|
||||
|
Reference in New Issue
Block a user