cli/serve: funnel interactive enablement flow tweaks

1. Add metrics to funnel flow.
2. Stop blocking users from turning off funnels when no longer in
   their node capabilities.
3. Rename LocalClient.IncrementMetric to IncrementCounter to better
   callout its usage is only for counter clientmetrics.

Updates tailscale/corp#10577

Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
pull/8892/head
Sonia Appasamy 1 year ago committed by Sonia Appasamy
parent 8e63d75018
commit 0052830c64

@ -259,13 +259,12 @@ func (lc *LocalClient) DaemonMetrics(ctx context.Context) ([]byte, error) {
return lc.get200(ctx, "/localapi/v0/metrics") return lc.get200(ctx, "/localapi/v0/metrics")
} }
// IncrementMetric increments the value of a Tailscale daemon's metric by // IncrementCounter increments the value of a Tailscale daemon's counter
// the given delta. If the metric has yet to exist, a new counter metric is // metric by the given delta. If the metric has yet to exist, a new counter
// created and initialized to delta. // metric is created and initialized to delta.
// //
// IncrementMetric only supports counter metrics and non-negative delta values. // IncrementCounter does not support gauge metrics or negative delta values.
// Gauge metrics are unsupported. func (lc *LocalClient) IncrementCounter(ctx context.Context, name string, delta int) error {
func (lc *LocalClient) IncrementMetric(ctx context.Context, name string, delta int) error {
type metricUpdate struct { type metricUpdate struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`

@ -94,8 +94,13 @@ func (e *serveEnv) runFunnel(ctx context.Context, args []string) error {
} }
port := uint16(port64) port := uint16(port64)
if err := e.verifyFunnelEnabled(ctx, st, port); err != nil { if on {
return err // Don't block from turning off existing Funnel if
// network configuration/capabilities have changed.
// Only block from starting new Funnels.
if err := e.verifyFunnelEnabled(ctx, st, port); err != nil {
return err
}
} }
dnsName := strings.TrimSuffix(st.Self.DNSName, ".") dnsName := strings.TrimSuffix(st.Self.DNSName, ".")
@ -176,7 +181,7 @@ func printFunnelWarning(sc *ipn.ServeConfig) {
p, _ := strconv.ParseUint(portStr, 10, 16) p, _ := strconv.ParseUint(portStr, 10, 16)
if _, ok := sc.TCP[uint16(p)]; !ok { if _, ok := sc.TCP[uint16(p)]; !ok {
warn = true warn = true
fmt.Fprintf(os.Stderr, "Warning: funnel=on for %s, but no serve config\n", hp) fmt.Fprintf(os.Stderr, "\nWarning: funnel=on for %s, but no serve config\n", hp)
} }
} }
if warn { if warn {

@ -133,6 +133,7 @@ type localServeClient interface {
SetServeConfig(context.Context, *ipn.ServeConfig) error SetServeConfig(context.Context, *ipn.ServeConfig) error
QueryFeature(ctx context.Context, feature string) (*tailcfg.QueryFeatureResponse, error) QueryFeature(ctx context.Context, feature string) (*tailcfg.QueryFeatureResponse, error)
WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*tailscale.IPNBusWatcher, error) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*tailscale.IPNBusWatcher, error)
IncrementCounter(ctx context.Context, name string, delta int) error
} }
// serveEnv is the environment the serve command runs within. All I/O should be // serveEnv is the environment the serve command runs within. All I/O should be
@ -796,17 +797,19 @@ func (e *serveEnv) enableFeatureInteractive(ctx context.Context, feature string,
return nil // already enabled return nil // already enabled
} }
if info.Text != "" { if info.Text != "" {
fmt.Fprintln(os.Stdout, info.Text) fmt.Fprintln(os.Stdout, "\n"+info.Text)
} }
if info.URL != "" { if info.URL != "" {
fmt.Fprintln(os.Stdout, "\n "+info.URL) fmt.Fprintln(os.Stdout, "\n "+info.URL+"\n")
} }
if !info.ShouldWait { if !info.ShouldWait {
e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_not_awaiting_enablement", feature), 1)
// The feature has not been enabled yet, // The feature has not been enabled yet,
// but the CLI should not block on user action. // but the CLI should not block on user action.
// Once info.Text is printed, exit the CLI. // Once info.Text is printed, exit the CLI.
os.Exit(0) os.Exit(0)
} }
e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_awaiting_enablement", feature), 1)
// Block until feature is enabled. // Block until feature is enabled.
watchCtx, cancelWatch := context.WithCancel(ctx) watchCtx, cancelWatch := context.WithCancel(ctx)
defer cancelWatch() defer cancelWatch()
@ -816,6 +819,7 @@ func (e *serveEnv) enableFeatureInteractive(ctx context.Context, feature string,
// don't block. We still present the URL in the CLI, // don't block. We still present the URL in the CLI,
// then close the process. Swallow the error. // then close the process. Swallow the error.
log.Fatalf("lost connection to tailscaled: %v", err) log.Fatalf("lost connection to tailscaled: %v", err)
e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enablement_lost_connection", feature), 1)
return err return err
} }
defer watcher.Close() defer watcher.Close()
@ -826,11 +830,13 @@ func (e *serveEnv) enableFeatureInteractive(ctx context.Context, feature string,
// Let the user finish enablement then rerun their // Let the user finish enablement then rerun their
// command themselves. // command themselves.
log.Fatalf("lost connection to tailscaled: %v", err) log.Fatalf("lost connection to tailscaled: %v", err)
e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enablement_lost_connection", feature), 1)
return err return err
} }
if nm := n.NetMap; nm != nil && nm.SelfNode != nil { if nm := n.NetMap; nm != nil && nm.SelfNode != nil {
if hasRequiredCapabilities(nm.SelfNode.Capabilities) { if hasRequiredCapabilities(nm.SelfNode.Capabilities) {
fmt.Fprintln(os.Stdout, "\nSuccess.") e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enabled", feature), 1)
fmt.Fprintln(os.Stdout, "Success.")
return nil return nil
} }
} }

@ -893,7 +893,11 @@ func (lc *fakeLocalServeClient) QueryFeature(ctx context.Context, feature string
} }
func (lc *fakeLocalServeClient) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*tailscale.IPNBusWatcher, error) { func (lc *fakeLocalServeClient) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*tailscale.IPNBusWatcher, error) {
return nil, nil return nil, nil // unused in tests
}
func (lc *fakeLocalServeClient) IncrementCounter(ctx context.Context, name string, delta int) error {
return nil // unused in tests
} }
// exactError returns an error checker that wants exactly the provided want error. // exactError returns an error checker that wants exactly the provided want error.

Loading…
Cancel
Save