mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	* initial capver packet tracking version Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * Log the minimum version as client version, not only capver Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * remove old versions Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * use capver for integration tests Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * changelog Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> * patch through m and n key Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com> --------- Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
		
			
				
	
	
		
			158 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| //go:generate go run main.go
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"log"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"regexp"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	xmaps "golang.org/x/exp/maps"
 | |
| 	"tailscale.com/tailcfg"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	releasesURL = "https://api.github.com/repos/tailscale/tailscale/releases"
 | |
| 	rawFileURL  = "https://github.com/tailscale/tailscale/raw/refs/tags/%s/tailcfg/tailcfg.go"
 | |
| 	outputFile  = "../capver_generated.go"
 | |
| )
 | |
| 
 | |
| type Release struct {
 | |
| 	Name string `json:"name"`
 | |
| }
 | |
| 
 | |
| func getCapabilityVersions() (map[string]tailcfg.CapabilityVersion, error) {
 | |
| 	// Fetch the releases
 | |
| 	resp, err := http.Get(releasesURL)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error fetching releases: %w", err)
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	body, err := io.ReadAll(resp.Body)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error reading response body: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	var releases []Release
 | |
| 	err = json.Unmarshal(body, &releases)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("error unmarshalling JSON: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// Regular expression to find the CurrentCapabilityVersion line
 | |
| 	re := regexp.MustCompile(`const CurrentCapabilityVersion CapabilityVersion = (\d+)`)
 | |
| 
 | |
| 	versions := make(map[string]tailcfg.CapabilityVersion)
 | |
| 
 | |
| 	for _, release := range releases {
 | |
| 		version := strings.TrimSpace(release.Name)
 | |
| 		if !strings.HasPrefix(version, "v") {
 | |
| 			version = "v" + version
 | |
| 		}
 | |
| 
 | |
| 		// Fetch the raw Go file
 | |
| 		rawURL := fmt.Sprintf(rawFileURL, version)
 | |
| 		resp, err := http.Get(rawURL)
 | |
| 		if err != nil {
 | |
| 			fmt.Printf("Error fetching raw file for version %s: %v\n", version, err)
 | |
| 			continue
 | |
| 		}
 | |
| 		defer resp.Body.Close()
 | |
| 
 | |
| 		body, err := io.ReadAll(resp.Body)
 | |
| 		if err != nil {
 | |
| 			fmt.Printf("Error reading raw file for version %s: %v\n", version, err)
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		// Find the CurrentCapabilityVersion
 | |
| 		matches := re.FindStringSubmatch(string(body))
 | |
| 		if len(matches) > 1 {
 | |
| 			capabilityVersionStr := matches[1]
 | |
| 			capabilityVersion, _ := strconv.Atoi(capabilityVersionStr)
 | |
| 			versions[version] = tailcfg.CapabilityVersion(capabilityVersion)
 | |
| 		} else {
 | |
| 			fmt.Printf("Version: %s, CurrentCapabilityVersion not found\n", version)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return versions, nil
 | |
| }
 | |
| 
 | |
| func writeCapabilityVersionsToFile(versions map[string]tailcfg.CapabilityVersion) error {
 | |
| 	// Open the output file
 | |
| 	file, err := os.Create(outputFile)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("error creating file: %w", err)
 | |
| 	}
 | |
| 	defer file.Close()
 | |
| 
 | |
| 	// Write the package declaration and variable
 | |
| 	file.WriteString("package capver\n\n")
 | |
| 	file.WriteString("//Generated DO NOT EDIT\n\n")
 | |
| 	file.WriteString(`import "tailscale.com/tailcfg"`)
 | |
| 	file.WriteString("\n\n")
 | |
| 	file.WriteString("var tailscaleToCapVer = map[string]tailcfg.CapabilityVersion{\n")
 | |
| 
 | |
| 	sortedVersions := xmaps.Keys(versions)
 | |
| 	sort.Strings(sortedVersions)
 | |
| 	for _, version := range sortedVersions {
 | |
| 		file.WriteString(fmt.Sprintf("\t\"%s\": %d,\n", version, versions[version]))
 | |
| 	}
 | |
| 	file.WriteString("}\n")
 | |
| 
 | |
| 	file.WriteString("\n\n")
 | |
| 	file.WriteString("var capVerToTailscaleVer = map[tailcfg.CapabilityVersion]string{\n")
 | |
| 
 | |
| 	capVarToTailscaleVer := make(map[tailcfg.CapabilityVersion]string)
 | |
| 	for _, v := range sortedVersions {
 | |
| 		cap := versions[v]
 | |
| 		log.Printf("cap for v: %d, %s", cap, v)
 | |
| 
 | |
| 		// If it is already set, skip and continue,
 | |
| 		// we only want the first tailscale vsion per
 | |
| 		// capability vsion.
 | |
| 		if _, ok := capVarToTailscaleVer[cap]; ok {
 | |
| 			log.Printf("Skipping %d, %s", cap, v)
 | |
| 			continue
 | |
| 		}
 | |
| 		log.Printf("Storing %d, %s", cap, v)
 | |
| 		capVarToTailscaleVer[cap] = v
 | |
| 	}
 | |
| 
 | |
| 	capsSorted := xmaps.Keys(capVarToTailscaleVer)
 | |
| 	sort.Slice(capsSorted, func(i, j int) bool {
 | |
| 		return capsSorted[i] < capsSorted[j]
 | |
| 	})
 | |
| 	for _, capVer := range capsSorted {
 | |
| 		file.WriteString(fmt.Sprintf("\t%d:\t\t\"%s\",\n", capVer, capVarToTailscaleVer[capVer]))
 | |
| 	}
 | |
| 	file.WriteString("}\n")
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func main() {
 | |
| 	versions, err := getCapabilityVersions()
 | |
| 	if err != nil {
 | |
| 		fmt.Println("Error:", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	err = writeCapabilityVersionsToFile(versions)
 | |
| 	if err != nil {
 | |
| 		fmt.Println("Error writing to file:", err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	fmt.Println("Capability versions written to", outputFile)
 | |
| }
 |