types: move DebugRoutes from routes to types
Unblocks deletion of the routes package. Updates #3203
This commit is contained in:
parent
1fe682b141
commit
942313a10a
22
hscontrol/types/debug_routes.go
Normal file
22
hscontrol/types/debug_routes.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
// DebugRoutes is the JSON-shaped snapshot of the headscale primary
|
||||||
|
// route ledger exposed by the /debug/routes endpoint and consumed by
|
||||||
|
// the integration test harness. It used to live in hscontrol/routes,
|
||||||
|
// but the algorithm now runs inside hscontrol/state and that package
|
||||||
|
// must not be imported from integration code.
|
||||||
|
type DebugRoutes struct {
|
||||||
|
// AvailableRoutes maps node IDs to their advertised routes
|
||||||
|
// (intersection of announced and approved). Only nodes currently
|
||||||
|
// connected to headscale are listed.
|
||||||
|
AvailableRoutes map[NodeID][]netip.Prefix `json:"available_routes"`
|
||||||
|
|
||||||
|
// PrimaryRoutes maps route prefixes to the node currently elected
|
||||||
|
// primary for that prefix.
|
||||||
|
PrimaryRoutes map[string]NodeID `json:"primary_routes"`
|
||||||
|
|
||||||
|
// UnhealthyNodes lists nodes that have failed health probes.
|
||||||
|
UnhealthyNodes []NodeID `json:"unhealthy_nodes,omitempty"`
|
||||||
|
}
|
||||||
@ -6,7 +6,6 @@ import (
|
|||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
"github.com/juanfont/headscale/hscontrol"
|
"github.com/juanfont/headscale/hscontrol"
|
||||||
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
||||||
"github.com/juanfont/headscale/hscontrol/routes"
|
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
"github.com/juanfont/headscale/integration/hsic"
|
"github.com/juanfont/headscale/integration/hsic"
|
||||||
"github.com/ory/dockertest/v3"
|
"github.com/ory/dockertest/v3"
|
||||||
@ -43,7 +42,7 @@ type ControlServer interface {
|
|||||||
GetIPInNetwork(network *dockertest.Network) string
|
GetIPInNetwork(network *dockertest.Network) string
|
||||||
SetPolicy(pol *policyv2.Policy) error
|
SetPolicy(pol *policyv2.Policy) error
|
||||||
GetAllMapReponses() (map[types.NodeID][]tailcfg.MapResponse, error)
|
GetAllMapReponses() (map[types.NodeID][]tailcfg.MapResponse, error)
|
||||||
PrimaryRoutes() (*routes.DebugRoutes, error)
|
PrimaryRoutes() (*types.DebugRoutes, error)
|
||||||
DebugBatcher() (*hscontrol.DebugBatcherInfo, error)
|
DebugBatcher() (*hscontrol.DebugBatcherInfo, error)
|
||||||
DebugNodeStore() (map[types.NodeID]types.Node, error)
|
DebugNodeStore() (map[types.NodeID]types.Node, error)
|
||||||
DebugFilter() ([]tailcfg.FilterRule, error)
|
DebugFilter() ([]tailcfg.FilterRule, error)
|
||||||
|
|||||||
@ -27,7 +27,6 @@ import (
|
|||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
"github.com/juanfont/headscale/hscontrol"
|
"github.com/juanfont/headscale/hscontrol"
|
||||||
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
||||||
"github.com/juanfont/headscale/hscontrol/routes"
|
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
"github.com/juanfont/headscale/integration/dockertestutil"
|
"github.com/juanfont/headscale/integration/dockertestutil"
|
||||||
@ -1639,7 +1638,7 @@ func (t *HeadscaleInContainer) GetAllMapReponses() (map[types.NodeID][]tailcfg.M
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrimaryRoutes fetches the primary routes from the debug endpoint.
|
// PrimaryRoutes fetches the primary routes from the debug endpoint.
|
||||||
func (t *HeadscaleInContainer) PrimaryRoutes() (*routes.DebugRoutes, error) {
|
func (t *HeadscaleInContainer) PrimaryRoutes() (*types.DebugRoutes, error) {
|
||||||
// Execute curl inside the container to access the debug endpoint locally
|
// Execute curl inside the container to access the debug endpoint locally
|
||||||
command := []string{
|
command := []string{
|
||||||
"curl", "-s", "-H", "Accept: application/json", "http://localhost:9090/debug/routes",
|
"curl", "-s", "-H", "Accept: application/json", "http://localhost:9090/debug/routes",
|
||||||
@ -1650,7 +1649,7 @@ func (t *HeadscaleInContainer) PrimaryRoutes() (*routes.DebugRoutes, error) {
|
|||||||
return nil, fmt.Errorf("fetching routes from debug endpoint: %w", err)
|
return nil, fmt.Errorf("fetching routes from debug endpoint: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var debugRoutes routes.DebugRoutes
|
var debugRoutes types.DebugRoutes
|
||||||
if err := json.Unmarshal([]byte(result), &debugRoutes); err != nil { //nolint:noinlineerr
|
if err := json.Unmarshal([]byte(result), &debugRoutes); err != nil { //nolint:noinlineerr
|
||||||
return nil, fmt.Errorf("decoding routes response: %w", err)
|
return nil, fmt.Errorf("decoding routes response: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
||||||
"github.com/juanfont/headscale/hscontrol/routes"
|
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
"github.com/juanfont/headscale/integration/hsic"
|
"github.com/juanfont/headscale/integration/hsic"
|
||||||
@ -227,7 +226,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
propagationTime := integrationutil.ScaledTimeout(60 * time.Second)
|
propagationTime := integrationutil.ScaledTimeout(60 * time.Second)
|
||||||
|
|
||||||
// Helper function to validate primary routes table state
|
// Helper function to validate primary routes table state
|
||||||
validatePrimaryRoutes := func(t *testing.T, headscale ControlServer, expectedRoutes *routes.DebugRoutes, message string) {
|
validatePrimaryRoutes := func(t *testing.T, headscale ControlServer, expectedRoutes *types.DebugRoutes, message string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||||
primaryRoutesState, err := headscale.PrimaryRoutes()
|
primaryRoutesState, err := headscale.PrimaryRoutes()
|
||||||
@ -383,7 +382,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate primary routes table state - no routes approved yet
|
// Validate primary routes table state - no routes approved yet
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{},
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{},
|
||||||
PrimaryRoutes: map[string]types.NodeID{}, // No primary routes yet
|
PrimaryRoutes: map[string]types.NodeID{}, // No primary routes yet
|
||||||
}, "Primary routes table should be empty (no approved routes yet)")
|
}, "Primary routes table should be empty (no approved routes yet)")
|
||||||
@ -477,7 +476,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 1")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 1")
|
||||||
|
|
||||||
// Validate primary routes table state - router 1 is primary
|
// Validate primary routes table state - router 1 is primary
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
// Note: Router 2 and 3 are available but not approved
|
// Note: Router 2 and 3 are available but not approved
|
||||||
@ -557,7 +556,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying Router 1 remains PRIMARY after Router 2 approval")
|
}, propagationTime, 200*time.Millisecond, "Verifying Router 1 remains PRIMARY after Router 2 approval")
|
||||||
|
|
||||||
// Validate primary routes table state - router 1 still primary, router 2 approved but standby
|
// Validate primary routes table state - router 1 still primary, router 2 approved but standby
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -594,7 +593,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute still goes through router 1 in HA mode")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute still goes through router 1 in HA mode")
|
||||||
|
|
||||||
// Validate primary routes table state - router 1 primary, router 2 approved (standby)
|
// Validate primary routes table state - router 1 primary, router 2 approved (standby)
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -704,7 +703,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traffic still flows through PRIMARY router 1 with full HA setup active")
|
}, propagationTime, 200*time.Millisecond, "Verifying traffic still flows through PRIMARY router 1 with full HA setup active")
|
||||||
|
|
||||||
// Validate primary routes table state - all 3 routers approved, router 1 still primary
|
// Validate primary routes table state - all 3 routers approved, router 1 still primary
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -785,7 +784,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 2 after failover")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 2 after failover")
|
||||||
|
|
||||||
// Validate primary routes table state - router 2 is now primary after router 1 failure
|
// Validate primary routes table state - router 2 is now primary after router 1 failure
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
// Router 1 is disconnected, so not in AvailableRoutes
|
// Router 1 is disconnected, so not in AvailableRoutes
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -859,7 +858,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 3 after second failover")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 3 after second failover")
|
||||||
|
|
||||||
// Validate primary routes table state - router 3 is now primary after router 2 failure
|
// Validate primary routes table state - router 3 is now primary after router 2 failure
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
// Routers 1 and 2 are disconnected, so not in AvailableRoutes
|
// Routers 1 and 2 are disconnected, so not in AvailableRoutes
|
||||||
types.NodeID(MustFindNode(subRouter3.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter3.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -939,7 +938,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute still goes through router 3 after router 1 recovery")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute still goes through router 3 after router 1 recovery")
|
||||||
|
|
||||||
// Validate primary routes table state - router 3 remains primary after router 1 comes back
|
// Validate primary routes table state - router 3 remains primary after router 1 comes back
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
// Router 2 is still disconnected
|
// Router 2 is still disconnected
|
||||||
@ -1022,7 +1021,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 3 after full recovery")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 3 after full recovery")
|
||||||
|
|
||||||
// Validate primary routes table state - router 3 remains primary after all routers back online
|
// Validate primary routes table state - router 3 remains primary after all routers back online
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -1109,7 +1108,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 1 after route disable")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 1 after route disable")
|
||||||
|
|
||||||
// Validate primary routes table state - router 1 is primary after router 3 route disabled
|
// Validate primary routes table state - router 1 is primary after router 3 route disabled
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -1197,7 +1196,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 2 after second route disable")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute goes through router 2 after second route disable")
|
||||||
|
|
||||||
// Validate primary routes table state - router 2 is primary after router 1 route disabled
|
// Validate primary routes table state - router 2 is primary after router 1 route disabled
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
// Router 1's route is no longer approved, so not in AvailableRoutes
|
// Router 1's route is no longer approved, so not in AvailableRoutes
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -1284,7 +1283,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Verifying traceroute still goes through router 2 after route re-enable")
|
}, propagationTime, 200*time.Millisecond, "Verifying traceroute still goes through router 2 after route re-enable")
|
||||||
|
|
||||||
// Validate primary routes table state after router 1 re-approval
|
// Validate primary routes table state after router 1 re-approval
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
@ -1326,7 +1325,7 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
|||||||
}, propagationTime, 200*time.Millisecond, "Waiting for route state after router 3 re-approval")
|
}, propagationTime, 200*time.Millisecond, "Waiting for route state after router 3 re-approval")
|
||||||
|
|
||||||
// Validate primary routes table state after router 3 re-approval
|
// Validate primary routes table state after router 3 re-approval
|
||||||
validatePrimaryRoutes(t, headscale, &routes.DebugRoutes{
|
validatePrimaryRoutes(t, headscale, &types.DebugRoutes{
|
||||||
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
AvailableRoutes: map[types.NodeID][]netip.Prefix{
|
||||||
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter1.Hostname(), nodes).GetId()): {pref},
|
||||||
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
types.NodeID(MustFindNode(subRouter2.Hostname(), nodes).GetId()): {pref},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user