client/local,ipn/localapi: add /localapi/v0/routecheck endpoint (#19640)
In order to support a `tailscale routecheck` command, we introduce the `/localapi/v0/routecheck` endpoint to the local API. This endpoint returns the most recent report collected by the routecheck client. If `force=true` is an argument in the query string, then this endpoint will actively probe before returning the report. Updates #17366 Updates tailscale/corp#33033 Signed-off-by: Simon Law <sfllaw@tailscale.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_routecheck
|
||||
|
||||
package local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"tailscale.com/net/routecheck"
|
||||
)
|
||||
|
||||
// ErrReportPending is returned by [Client.RouteCheck] and [Client.RouteCheckProbe]
|
||||
// when the report is pending.
|
||||
var ErrRouteCheckReportUnavailable = errors.New("report pending")
|
||||
|
||||
// RouteCheckProbe performs a routecheck probe and waits for its report.
|
||||
func (lc *Client) RouteCheckProbe(ctx context.Context) (*routecheck.Report, error) {
|
||||
body, err := lc.send(ctx, "POST", "/localapi/v0/routecheck?probe=true", http.StatusOK, nil)
|
||||
if err != nil {
|
||||
if hs, ok := errors.AsType[httpStatusError](err); ok && hs.HTTPStatus == http.StatusNoContent {
|
||||
return nil, ErrRouteCheckReportUnavailable
|
||||
}
|
||||
return nil, fmt.Errorf("error %w: %s", err, body)
|
||||
}
|
||||
return decodeJSON[*routecheck.Report](body)
|
||||
}
|
||||
|
||||
// RouteCheck requests the report compiled by the latest routecheck probe.
|
||||
func (lc *Client) RouteCheck(ctx context.Context) (*routecheck.Report, error) {
|
||||
body, err := lc.send(ctx, "POST", "/localapi/v0/routecheck", http.StatusOK, nil)
|
||||
if err != nil {
|
||||
if hs, ok := errors.AsType[httpStatusError](err); ok && hs.HTTPStatus == http.StatusNoContent {
|
||||
return nil, ErrRouteCheckReportUnavailable
|
||||
}
|
||||
return nil, fmt.Errorf("error %w: %s", err, body)
|
||||
}
|
||||
return decodeJSON[*routecheck.Report](body)
|
||||
}
|
||||
Reference in New Issue
Block a user