cmd/tailscale/cli/jsonoutput: extract routecheck’s output format

In PR #19641, we added the `tailscale routecheck` command that
supports both `--format=json` and `--format=json-line`. To allow other
packages to import and unmarshal that JSON structure, this patch
exports that format in a new tsroutecheckjsonv0 package.

Updates #17366
Updates tailscale/corp#33033

Signed-off-by: Simon Law <sfllaw@tailscale.com>
This commit is contained in:
Simon Law
2026-06-01 10:25:33 -07:00
committed by Simon Law
parent 5cbe32e0bc
commit be16cc0d3d
3 changed files with 36 additions and 8 deletions

View File

@@ -13,12 +13,13 @@
"slices"
"strings"
"text/tabwriter"
"time"
jsonv2 "github.com/go-json-experiment/json"
"github.com/go-json-experiment/json/jsontext"
"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/cmd/tailscale/cli/jsonoutput"
"tailscale.com/cmd/tailscale/tsroutecheckjsonv0"
"tailscale.com/net/routecheck"
"tailscale.com/tstime"
)
@@ -41,13 +42,14 @@ func init() {
var routecheckFlagSet = func() *flag.FlagSet {
fs := newFlagSet("routecheck")
fs.BoolVar(&routecheckArgs.probe, "probe", false, "probe now to generate a new reachability report")
fs.StringVar(&routecheckArgs.format, "format", "", `output format: empty (for human-readable), "json" or "json-line"`)
fs.Var(&routecheckArgs.format, "format", `output format: empty (for human-readable), "json" or "json-line"`)
fs.Var(routecheckArgs.format.JSONBool(), "json", "output in JSON format")
return fs
}()
var routecheckArgs struct {
probe bool
format string
format jsonoutput.Format
}
func runRoutecheck(ctx context.Context, args []string) error {
@@ -67,7 +69,7 @@ func runRoutecheck(ctx context.Context, args []string) error {
func printRouteCheckReport(rp *routecheck.Report) error {
var enc *jsontext.Encoder
switch routecheckArgs.format {
switch routecheckArgs.format.String() {
case "":
case "json":
enc = jsontext.NewEncoder(Stdout, jsontext.WithIndent("\t"))
@@ -90,10 +92,7 @@ func printRouteCheckReport(rp *routecheck.Report) error {
}
if enc != nil {
out := struct {
Done time.Time `json:"done"`
Routes routecheck.RoutablePrefixes `json:"routes"`
}{
out := tsroutecheckjsonv0.ReportResponse{
Done: rp.Done,
Routes: routes,
}

View File

@@ -184,6 +184,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/cmd/tailscale/cli/ffcomplete from tailscale.com/cmd/tailscale/cli
tailscale.com/cmd/tailscale/cli/ffcomplete/internal from tailscale.com/cmd/tailscale/cli/ffcomplete
tailscale.com/cmd/tailscale/cli/jsonoutput from tailscale.com/cmd/tailscale/cli
tailscale.com/cmd/tailscale/tsroutecheckjsonv0 from tailscale.com/cmd/tailscale/cli
tailscale.com/control/controlbase from tailscale.com/control/controlhttp+
tailscale.com/control/controlhttp from tailscale.com/control/ts2021
tailscale.com/control/controlhttp/controlhttpcommon from tailscale.com/control/controlhttp

View File

@@ -0,0 +1,28 @@
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
//go:build !ts_omit_routecheck
// Package tsroutecheckjsonv0 provides types for unmarshalling the JSON output of the
// "tailscale routecheck --json" command:
//
// - [ReportResponse] will unmarshal the output of "tailscale routecheck --json"
//
// # WARNING: unstable
//
// Format is "v0" and is subject to change.
// There is no guarantee of backwards or forwards compatibility.
package tsroutecheckjsonv0
import (
"time"
"tailscale.com/net/routecheck"
)
// ReportResponse is the JSON form of [routecheck.Report].
// Experimental: This output is not yet stable: tailscale/tailscale#17366.
type ReportResponse struct {
Done time.Time `json:"done"`
Routes routecheck.RoutablePrefixes `json:"routes"`
}