mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 03:31:39 +00:00
tailcfg: add Node.HasCap helpers
This makes a follow up change less noisy. Updates #cleanup Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
d06b48dd0a
commit
4da0689c2c
@ -9,7 +9,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -147,15 +146,13 @@ func (e *serveEnv) runFunnel(ctx context.Context, args []string) error {
|
|||||||
//
|
//
|
||||||
// verifyFunnelEnabled may refresh the local state and modify the st input.
|
// verifyFunnelEnabled may refresh the local state and modify the st input.
|
||||||
func (e *serveEnv) verifyFunnelEnabled(ctx context.Context, st *ipnstate.Status, port uint16) error {
|
func (e *serveEnv) verifyFunnelEnabled(ctx context.Context, st *ipnstate.Status, port uint16) error {
|
||||||
hasFunnelAttrs := func(attrs []tailcfg.NodeCapability) bool {
|
hasFunnelAttrs := func(selfNode *ipnstate.PeerStatus) bool {
|
||||||
hasHTTPS := slices.Contains(attrs, tailcfg.CapabilityHTTPS)
|
return selfNode.HasCap(tailcfg.CapabilityHTTPS) && selfNode.HasCap(tailcfg.NodeAttrFunnel)
|
||||||
hasFunnel := slices.Contains(attrs, tailcfg.NodeAttrFunnel)
|
|
||||||
return hasHTTPS && hasFunnel
|
|
||||||
}
|
}
|
||||||
if hasFunnelAttrs(st.Self.Capabilities) {
|
if hasFunnelAttrs(st.Self) {
|
||||||
return nil // already enabled
|
return nil // already enabled
|
||||||
}
|
}
|
||||||
enableErr := e.enableFeatureInteractive(ctx, "funnel", hasFunnelAttrs)
|
enableErr := e.enableFeatureInteractive(ctx, "funnel", tailcfg.CapabilityHTTPS, tailcfg.NodeAttrFunnel)
|
||||||
st, statusErr := e.getLocalClientStatusWithoutPeers(ctx) // get updated status; interactive flow may block
|
st, statusErr := e.getLocalClientStatusWithoutPeers(ctx) // get updated status; interactive flow may block
|
||||||
switch {
|
switch {
|
||||||
case statusErr != nil:
|
case statusErr != nil:
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -269,9 +268,7 @@ func (e *serveEnv) runServe(ctx context.Context, args []string) error {
|
|||||||
// on, enableFeatureInteractive will error. For now, we hide that
|
// on, enableFeatureInteractive will error. For now, we hide that
|
||||||
// error and maintain the previous behavior (prior to 2023-08-15)
|
// error and maintain the previous behavior (prior to 2023-08-15)
|
||||||
// of letting them edit the serve config before enabling certs.
|
// of letting them edit the serve config before enabling certs.
|
||||||
e.enableFeatureInteractive(ctx, "serve", func(caps []tailcfg.NodeCapability) bool {
|
e.enableFeatureInteractive(ctx, "serve", tailcfg.CapabilityHTTPS)
|
||||||
return slices.Contains(caps, tailcfg.CapabilityHTTPS)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
srcPort, err := parseServePort(srcPortStr)
|
srcPort, err := parseServePort(srcPortStr)
|
||||||
@ -829,7 +826,7 @@ func parseServePort(s string) (uint16, error) {
|
|||||||
//
|
//
|
||||||
// 2023-08-09: The only valid feature values are "serve" and "funnel".
|
// 2023-08-09: The only valid feature values are "serve" and "funnel".
|
||||||
// This can be moved to some CLI lib when expanded past serve/funnel.
|
// This can be moved to some CLI lib when expanded past serve/funnel.
|
||||||
func (e *serveEnv) enableFeatureInteractive(ctx context.Context, feature string, hasRequiredCapabilities func(caps []tailcfg.NodeCapability) bool) (err error) {
|
func (e *serveEnv) enableFeatureInteractive(ctx context.Context, feature string, caps ...tailcfg.NodeCapability) (err error) {
|
||||||
info, err := e.lc.QueryFeature(ctx, feature)
|
info, err := e.lc.QueryFeature(ctx, feature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -875,7 +872,16 @@ func (e *serveEnv) enableFeatureInteractive(ctx context.Context, feature string,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if nm := n.NetMap; nm != nil && nm.SelfNode.Valid() {
|
if nm := n.NetMap; nm != nil && nm.SelfNode.Valid() {
|
||||||
if hasRequiredCapabilities(nm.SelfNode.Capabilities().AsSlice()) {
|
gotAll := true
|
||||||
|
for _, c := range caps {
|
||||||
|
if !nm.SelfNode.HasCap(c) {
|
||||||
|
// The feature is not yet enabled.
|
||||||
|
// Continue blocking until it is.
|
||||||
|
gotAll = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if gotAll {
|
||||||
e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enabled", feature), 1)
|
e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enabled", feature), 1)
|
||||||
fmt.Fprintln(os.Stdout, "Success.")
|
fmt.Fprintln(os.Stdout, "Success.")
|
||||||
return nil
|
return nil
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -233,9 +232,7 @@ func (e *serveEnv) runServeCombined(subcmd serveMode) execFunc {
|
|||||||
// on, enableFeatureInteractive will error. For now, we hide that
|
// on, enableFeatureInteractive will error. For now, we hide that
|
||||||
// error and maintain the previous behavior (prior to 2023-08-15)
|
// error and maintain the previous behavior (prior to 2023-08-15)
|
||||||
// of letting them edit the serve config before enabling certs.
|
// of letting them edit the serve config before enabling certs.
|
||||||
if err := e.enableFeatureInteractive(ctx, "serve", func(caps []tailcfg.NodeCapability) bool {
|
if err := e.enableFeatureInteractive(ctx, "serve", tailcfg.CapabilityHTTPS); err != nil {
|
||||||
return slices.Contains(caps, tailcfg.CapabilityHTTPS)
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("error enabling https feature: %w", err)
|
return fmt.Errorf("error enabling https feature: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4094,8 +4094,8 @@ func (b *LocalBackend) setNetInfo(ni *tailcfg.NetInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hasCapability(nm *netmap.NetworkMap, cap tailcfg.NodeCapability) bool {
|
func hasCapability(nm *netmap.NetworkMap, cap tailcfg.NodeCapability) bool {
|
||||||
if nm != nil && nm.SelfNode.Valid() {
|
if nm != nil {
|
||||||
return views.SliceContains(nm.SelfNode.Capabilities(), cap)
|
return nm.SelfNode.HasCap(cap)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1035,7 +1035,7 @@ func (h *peerAPIHandler) canPutFile() bool {
|
|||||||
// canDebug reports whether h can debug this node (goroutines, metrics,
|
// canDebug reports whether h can debug this node (goroutines, metrics,
|
||||||
// magicsock internal state, etc).
|
// magicsock internal state, etc).
|
||||||
func (h *peerAPIHandler) canDebug() bool {
|
func (h *peerAPIHandler) canDebug() bool {
|
||||||
if !views.SliceContains(h.selfNode.Capabilities(), tailcfg.CapabilityDebug) {
|
if !h.selfNode.HasCap(tailcfg.CapabilityDebug) {
|
||||||
// This node does not expose debug info.
|
// This node does not expose debug info.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -291,6 +291,11 @@ type PeerStatus struct {
|
|||||||
Location *tailcfg.Location `json:",omitempty"`
|
Location *tailcfg.Location `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasCap reports whether ps has the given capability.
|
||||||
|
func (ps *PeerStatus) HasCap(cap tailcfg.NodeCapability) bool {
|
||||||
|
return slices.Contains(ps.Capabilities, cap)
|
||||||
|
}
|
||||||
|
|
||||||
// StatusBuilder is a request to construct a Status. A new StatusBuilder is
|
// StatusBuilder is a request to construct a Status. A new StatusBuilder is
|
||||||
// passed to various subsystems which then call methods on it to populate state.
|
// passed to various subsystems which then call methods on it to populate state.
|
||||||
// Call its Status method to return the final constructed Status.
|
// Call its Status method to return the final constructed Status.
|
||||||
|
@ -368,6 +368,16 @@ type Node struct {
|
|||||||
ExitNodeDNSResolvers []*dnstype.Resolver `json:",omitempty"`
|
ExitNodeDNSResolvers []*dnstype.Resolver `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasCap reports whether the node has the given capability.
|
||||||
|
func (v NodeView) HasCap(cap NodeCapability) bool {
|
||||||
|
return v.ж.HasCap(cap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasCap reports whether the node has the given capability.
|
||||||
|
func (v *Node) HasCap(cap NodeCapability) bool {
|
||||||
|
return v != nil && slices.Contains(v.Capabilities, cap)
|
||||||
|
}
|
||||||
|
|
||||||
// DisplayName returns the user-facing name for a node which should
|
// DisplayName returns the user-facing name for a node which should
|
||||||
// be shown in client UIs.
|
// be shown in client UIs.
|
||||||
//
|
//
|
||||||
|
@ -15,7 +15,6 @@ import (
|
|||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/logid"
|
"tailscale.com/types/logid"
|
||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
"tailscale.com/types/views"
|
|
||||||
"tailscale.com/wgengine/wgcfg"
|
"tailscale.com/wgengine/wgcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
|
|||||||
// Setup log IDs for data plane audit logging.
|
// Setup log IDs for data plane audit logging.
|
||||||
if nm.SelfNode.Valid() {
|
if nm.SelfNode.Valid() {
|
||||||
cfg.NodeID = nm.SelfNode.StableID()
|
cfg.NodeID = nm.SelfNode.StableID()
|
||||||
canNetworkLog := views.SliceContains(nm.SelfNode.Capabilities(), tailcfg.CapabilityDataPlaneAuditLogs)
|
canNetworkLog := nm.SelfNode.HasCap(tailcfg.CapabilityDataPlaneAuditLogs)
|
||||||
if canNetworkLog && nm.SelfNode.DataPlaneAuditLogID() != "" && nm.DomainAuditLogID != "" {
|
if canNetworkLog && nm.SelfNode.DataPlaneAuditLogID() != "" && nm.DomainAuditLogID != "" {
|
||||||
nodeID, errNode := logid.ParsePrivateID(nm.SelfNode.DataPlaneAuditLogID())
|
nodeID, errNode := logid.ParsePrivateID(nm.SelfNode.DataPlaneAuditLogID())
|
||||||
if errNode != nil {
|
if errNode != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user