Files
headscale/hscontrol/capver/capver.go
T
Kristoffer Dalby 1bd62737b9 mapper: send removed peers as their own delta
Removals derived from a policy change, full update or reconnect rode a
response whose DNSConfig, SSHPolicy, Node or Peers force a full rebuild.

Updates tailscale/tailscale#15660
2026-09-30 19:03:13 +02:00

95 lines
2.7 KiB
Go

package capver
//go:generate go run ../../tools/capver/main.go
import (
"maps"
"slices"
"strings"
"tailscale.com/tailcfg"
"tailscale.com/util/cmpver"
"tailscale.com/util/set"
)
// minVersionParts is the minimum number of version parts needed for major.minor.
const minVersionParts = 2
// fullNetmapRemovalsCapVer is the capability version of Tailscale main when
// clients started reporting peers a full netmap drops as removed
// (tailscale/tailscale#15660); v1.104 is the first release at or above it.
const fullNetmapRemovalsCapVer tailcfg.CapabilityVersion = 148
// CanOldCodeBeCleanedUp is called at server startup to panic when
// [MinSupportedCapabilityVersion] has crossed a threshold at which a
// backwards-compat emit path can be deleted. Each entry pairs a
// [tailcfg.CapabilityVersion] threshold with the message identifying
// the code to remove.
//
// All capability-version-gated cleanups should be registered here.
func CanOldCodeBeCleanedUp() {
if MinSupportedCapabilityVersion >= fullNetmapRemovalsCapVer {
panic("the tailscale/tailscale#15660 compat can be cleaned up: grep for it (hscontrol/mapper/batcher.go and its tests)")
}
}
func tailscaleVersSorted() []string {
return slices.Sorted(maps.Keys(tailscaleToCapVer))
}
// TailscaleVersion returns the Tailscale version for the given [tailcfg.CapabilityVersion].
func TailscaleVersion(ver tailcfg.CapabilityVersion) string {
return capVerToTailscaleVer[ver]
}
// CapabilityVersion returns the [tailcfg.CapabilityVersion] for the given Tailscale version.
// It accepts both full versions (v1.90.1) and minor versions (v1.90).
func CapabilityVersion(ver string) tailcfg.CapabilityVersion {
if !strings.HasPrefix(ver, "v") {
ver = "v" + ver
}
// Try direct lookup first (works for minor versions like v1.90)
if cv, ok := tailscaleToCapVer[ver]; ok {
return cv
}
// Try extracting minor version from full version (v1.90.1 -> v1.90)
parts := strings.Split(strings.TrimPrefix(ver, "v"), ".")
if len(parts) >= minVersionParts {
minor := "v" + parts[0] + "." + parts[1]
return tailscaleToCapVer[minor]
}
return 0
}
// TailscaleLatestMajorMinor returns the n latest Tailscale versions (e.g. 1.80).
func TailscaleLatestMajorMinor(n int, stripV bool) []string {
if n <= 0 {
return nil
}
majors := set.Set[string]{}
for _, vers := range tailscaleVersSorted() {
if stripV {
vers = strings.TrimPrefix(vers, "v")
}
v := strings.Split(vers, ".")
majors.Add(v[0] + "." + v[1])
}
majorSl := majors.Slice()
// cmpver orders versions numerically, so v1.100 sorts after v1.98 rather than
// lexically before it.
slices.SortFunc(majorSl, cmpver.Compare)
if n > len(majorSl) {
return majorSl
}
return majorSl[len(majorSl)-n:]
}