mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-28 05:00:08 +00:00
cmd/tailscale/cli,client,ipn: add appc-routes cli command
Allow the user to access information about routes an app connector has learned, such as how many routes for each domain. Fixes tailscale/corp#32624 Signed-off-by: Fran Bull <fran@tailscale.com>
This commit is contained in:
@@ -77,6 +77,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
||||
google.golang.org/protobuf/runtime/protoimpl from github.com/prometheus/client_model/go+
|
||||
google.golang.org/protobuf/types/known/timestamppb from github.com/prometheus/client_golang/prometheus+
|
||||
tailscale.com from tailscale.com/version
|
||||
tailscale.com/appc from tailscale.com/client/local
|
||||
💣 tailscale.com/atomicfile from tailscale.com/cmd/derper+
|
||||
tailscale.com/client/local from tailscale.com/derp/derpserver
|
||||
tailscale.com/client/tailscale/apitype from tailscale.com/client/local
|
||||
@@ -151,6 +152,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
||||
L 💣 tailscale.com/util/dirwalk from tailscale.com/metrics
|
||||
tailscale.com/util/dnsname from tailscale.com/hostinfo+
|
||||
tailscale.com/util/eventbus from tailscale.com/net/netmon+
|
||||
tailscale.com/util/execqueue from tailscale.com/appc
|
||||
💣 tailscale.com/util/hashx from tailscale.com/util/deephash
|
||||
tailscale.com/util/lineiter from tailscale.com/hostinfo+
|
||||
tailscale.com/util/mak from tailscale.com/health+
|
||||
|
||||
@@ -769,7 +769,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
||||
sigs.k8s.io/yaml from k8s.io/apimachinery/pkg/runtime/serializer/json+
|
||||
sigs.k8s.io/yaml/goyaml.v2 from sigs.k8s.io/yaml+
|
||||
tailscale.com from tailscale.com/version
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal+
|
||||
💣 tailscale.com/atomicfile from tailscale.com/ipn+
|
||||
tailscale.com/client/local from tailscale.com/client/tailscale+
|
||||
tailscale.com/client/tailscale from tailscale.com/cmd/k8s-operator+
|
||||
|
||||
153
cmd/tailscale/cli/appcroutes.go
Normal file
153
cmd/tailscale/cli/appcroutes.go
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"tailscale.com/appc"
|
||||
)
|
||||
|
||||
var appcRoutesArgs struct {
|
||||
all bool
|
||||
domainMap bool
|
||||
n bool
|
||||
}
|
||||
|
||||
var appcRoutesCmd = &ffcli.Command{
|
||||
Name: "appc-routes",
|
||||
ShortUsage: "tailscale appc-routes",
|
||||
Exec: runAppcRoutesInfo,
|
||||
ShortHelp: "Print the current app connector routes",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := newFlagSet("appc-routes")
|
||||
fs.BoolVar(&appcRoutesArgs.all, "all", false, "Print learned domains and routes and extra policy configured routes.")
|
||||
fs.BoolVar(&appcRoutesArgs.domainMap, "map", false, "Print the map of learned domains: [routes].")
|
||||
fs.BoolVar(&appcRoutesArgs.n, "n", false, "Print the total number of routes this node advertises.")
|
||||
return fs
|
||||
})(),
|
||||
LongHelp: strings.TrimSpace(`
|
||||
The 'tailscale appc-routes' command prints the current App Connector route status.
|
||||
|
||||
By default this command prints the domains configured in the app connector configuration and how many routes have been
|
||||
learned for each domain.
|
||||
|
||||
--all prints the routes learned from the domains configured in the app connector configuration; and any extra routes provided
|
||||
in the the policy app connector 'routes' field.
|
||||
|
||||
--map prints the routes learned from the domains configured in the app connector configuration.
|
||||
|
||||
-n prints the total number of routes advertised by this device, whether learned, set in the policy, or set locally.
|
||||
|
||||
For more information about App Connectors, refer to
|
||||
https://tailscale.com/kb/1281/app-connectors
|
||||
`),
|
||||
}
|
||||
|
||||
func getAllOutput(ri *appc.RouteInfo) (string, error) {
|
||||
domains, err := json.MarshalIndent(ri.Domains, " ", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
control, err := json.MarshalIndent(ri.Control, " ", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s := fmt.Sprintf(`Learned Routes
|
||||
==============
|
||||
%s
|
||||
|
||||
Routes from Policy
|
||||
==================
|
||||
%s
|
||||
`, domains, control)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type domainCount struct {
|
||||
domain string
|
||||
count int
|
||||
}
|
||||
|
||||
func getSummarizeLearnedOutput(ri *appc.RouteInfo) string {
|
||||
x := make([]domainCount, len(ri.Domains))
|
||||
i := 0
|
||||
maxDomainWidth := 0
|
||||
for k, v := range ri.Domains {
|
||||
if len(k) > maxDomainWidth {
|
||||
maxDomainWidth = len(k)
|
||||
}
|
||||
x[i] = domainCount{domain: k, count: len(v)}
|
||||
i++
|
||||
}
|
||||
slices.SortFunc(x, func(i, j domainCount) int {
|
||||
if i.count > j.count {
|
||||
return -1
|
||||
}
|
||||
if i.count < j.count {
|
||||
return 1
|
||||
}
|
||||
if i.domain > j.domain {
|
||||
return 1
|
||||
}
|
||||
if i.domain < j.domain {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
s := ""
|
||||
fmtString := fmt.Sprintf("%%-%ds %%d\n", maxDomainWidth) // eg "%-10s %d\n"
|
||||
for _, dc := range x {
|
||||
s += fmt.Sprintf(fmtString, dc.domain, dc.count)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func runAppcRoutesInfo(ctx context.Context, args []string) error {
|
||||
prefs, err := localClient.GetPrefs(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !prefs.AppConnector.Advertise {
|
||||
fmt.Println("not a connector")
|
||||
return nil
|
||||
}
|
||||
|
||||
if appcRoutesArgs.n {
|
||||
fmt.Println(len(prefs.AdvertiseRoutes))
|
||||
return nil
|
||||
}
|
||||
|
||||
routeInfo, err := localClient.GetAppConnectorRouteInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if appcRoutesArgs.domainMap {
|
||||
domains, err := json.Marshal(routeInfo.Domains)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(domains))
|
||||
return nil
|
||||
}
|
||||
|
||||
if appcRoutesArgs.all {
|
||||
s, err := getAllOutput(&routeInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Print(getSummarizeLearnedOutput(&routeInfo))
|
||||
return nil
|
||||
}
|
||||
@@ -276,6 +276,7 @@ change in the future.
|
||||
idTokenCmd,
|
||||
configureHostCmd(),
|
||||
systrayCmd,
|
||||
appcRoutesCmd,
|
||||
),
|
||||
FlagSet: rootfs,
|
||||
Exec: func(ctx context.Context, args []string) error {
|
||||
|
||||
@@ -70,6 +70,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
software.sslmate.com/src/go-pkcs12 from tailscale.com/cmd/tailscale/cli
|
||||
software.sslmate.com/src/go-pkcs12/internal/rc2 from software.sslmate.com/src/go-pkcs12
|
||||
tailscale.com from tailscale.com/version
|
||||
tailscale.com/appc from tailscale.com/client/local+
|
||||
💣 tailscale.com/atomicfile from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/client/local from tailscale.com/client/tailscale+
|
||||
L tailscale.com/client/systray from tailscale.com/cmd/tailscale/cli
|
||||
@@ -168,6 +169,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
L 💣 tailscale.com/util/dirwalk from tailscale.com/metrics
|
||||
tailscale.com/util/dnsname from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/util/eventbus from tailscale.com/client/local+
|
||||
tailscale.com/util/execqueue from tailscale.com/appc
|
||||
tailscale.com/util/groupmember from tailscale.com/client/web
|
||||
💣 tailscale.com/util/hashx from tailscale.com/util/deephash
|
||||
tailscale.com/util/httpm from tailscale.com/client/tailscale+
|
||||
|
||||
@@ -51,7 +51,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
💣 go4.org/mem from tailscale.com/control/controlbase+
|
||||
go4.org/netipx from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com from tailscale.com/version
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/atomicfile from tailscale.com/ipn+
|
||||
tailscale.com/client/tailscale/apitype from tailscale.com/ipn/ipnauth+
|
||||
tailscale.com/clientupdate from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -240,7 +240,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
gvisor.dev/gvisor/pkg/tcpip/transport/udp from gvisor.dev/gvisor/pkg/tcpip/adapters/gonet+
|
||||
gvisor.dev/gvisor/pkg/waiter from gvisor.dev/gvisor/pkg/context+
|
||||
tailscale.com from tailscale.com/version
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal+
|
||||
💣 tailscale.com/atomicfile from tailscale.com/ipn+
|
||||
LD tailscale.com/chirp from tailscale.com/cmd/tailscaled
|
||||
tailscale.com/client/local from tailscale.com/client/web+
|
||||
|
||||
@@ -211,7 +211,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
|
||||
gvisor.dev/gvisor/pkg/tcpip/transport/udp from gvisor.dev/gvisor/pkg/tcpip/adapters/gonet+
|
||||
gvisor.dev/gvisor/pkg/waiter from gvisor.dev/gvisor/pkg/context+
|
||||
tailscale.com from tailscale.com/version
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal
|
||||
tailscale.com/appc from tailscale.com/ipn/ipnlocal+
|
||||
💣 tailscale.com/atomicfile from tailscale.com/ipn+
|
||||
tailscale.com/client/local from tailscale.com/client/web+
|
||||
tailscale.com/client/tailscale from tailscale.com/internal/client/tailscale
|
||||
|
||||
Reference in New Issue
Block a user