From 343cfd47e68a5e2f85ce7e4a0afe9b3f24c060bd Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 18 Aug 2025 16:41:43 +0200 Subject: [PATCH] do not use online from batcher Signed-off-by: Kristoffer Dalby --- hscontrol/grpcv1.go | 21 ++++----------------- hscontrol/mapper/batcher_test.go | 12 ++++++------ hscontrol/types/node.go | 4 ++-- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/hscontrol/grpcv1.go b/hscontrol/grpcv1.go index 20ff25c1..bd4204fb 100644 --- a/hscontrol/grpcv1.go +++ b/hscontrol/grpcv1.go @@ -15,7 +15,6 @@ import ( "strings" "time" - "github.com/puzpuzpuz/xsync/v4" "github.com/rs/zerolog/log" "github.com/samber/lo" "google.golang.org/grpc/codes" @@ -295,10 +294,6 @@ func (api headscaleV1APIServer) GetNode( resp := node.Proto() - // Populate the online field based on - // currently connected nodes. - resp.Online = api.h.mapBatcher.IsConnected(node.ID()) - return &v1.GetNodeResponse{Node: resp}, nil } @@ -463,8 +458,6 @@ func (api headscaleV1APIServer) ListNodes( // the filtering of nodes by user, vs nodes as a whole can // probably be done once. // TODO(kradalby): This should be done in one tx. - - IsConnected := api.h.mapBatcher.ConnectedMap() if request.GetUser() != "" { user, err := api.h.state.GetUserByName(request.GetUser()) if err != nil { @@ -473,27 +466,21 @@ func (api headscaleV1APIServer) ListNodes( nodes := api.h.state.ListNodesByUser(types.UserID(user.ID)) - response := nodesToProto(api.h.state, IsConnected, nodes) + response := nodesToProto(api.h.state, nodes) return &v1.ListNodesResponse{Nodes: response}, nil } nodes := api.h.state.ListNodes() - response := nodesToProto(api.h.state, IsConnected, nodes) + response := nodesToProto(api.h.state, nodes) return &v1.ListNodesResponse{Nodes: response}, nil } -func nodesToProto(state *state.State, isLikelyConnected *xsync.Map[types.NodeID, bool], nodes views.Slice[types.NodeView]) []*v1.Node { +func nodesToProto(state *state.State, nodes views.Slice[types.NodeView]) []*v1.Node { response := make([]*v1.Node, nodes.Len()) for index, node := range nodes.All() { resp := node.Proto() - // Populate the online field based on - // currently connected nodes. - if val, ok := isLikelyConnected.Load(node.ID()); ok && val { - resp.Online = true - } - var tags []string for _, tag := range node.RequestTags() { if state.NodeCanHaveTag(node, tag) { @@ -501,7 +488,7 @@ func nodesToProto(state *state.State, isLikelyConnected *xsync.Map[types.NodeID, } } resp.ValidTags = lo.Uniq(append(tags, node.ForcedTags().AsSlice()...)) - + resp.SubnetRoutes = util.PrefixesToString(append(state.GetNodePrimaryRoutes(node.ID()), node.ExitRoutes()...)) response[index] = resp } diff --git a/hscontrol/mapper/batcher_test.go b/hscontrol/mapper/batcher_test.go index 7903fe22..73a0843c 100644 --- a/hscontrol/mapper/batcher_test.go +++ b/hscontrol/mapper/batcher_test.go @@ -38,10 +38,10 @@ func (t *testBatcherWrapper) AddNode(id types.NodeID, c chan<- *tailcfg.MapRespo if err != nil { return err } - + // Then send the online notification that poll.go would normally send - t.Batcher.AddWork(change.NodeOnline(id)) - + t.AddWork(change.NodeOnline(id)) + return nil } @@ -51,10 +51,10 @@ func (t *testBatcherWrapper) RemoveNode(id types.NodeID, c chan<- *tailcfg.MapRe if !removed { return false } - + // Then send the offline notification that poll.go would normally send - t.Batcher.AddWork(change.NodeOffline(id)) - + t.AddWork(change.NodeOffline(id)) + return true } diff --git a/hscontrol/types/node.go b/hscontrol/types/node.go index 2761789b..d27a0c5b 100644 --- a/hscontrol/types/node.go +++ b/hscontrol/types/node.go @@ -104,7 +104,6 @@ type Node struct { // headscale. It is best effort and not persisted. LastSeen *time.Time `gorm:"column:last_seen"` - // ApprovedRoutes is a list of routes that the node is allowed to announce // as a subnet router. They are not necessarily the routes that the node // announces at the moment. @@ -357,6 +356,7 @@ func (node *Node) Proto() *v1.Node { GivenName: node.GivenName, User: node.User.Proto(), ForcedTags: node.ForcedTags, + Online: *node.IsOnline, // Only ApprovedRoutes and AvailableRoutes is set here. SubnetRoutes has // to be populated manually with PrimaryRoute, to ensure it includes the @@ -423,7 +423,7 @@ func (node *Node) AnnouncedRoutes() []netip.Prefix { // SubnetRoutes returns the list of routes that the node announces and are approved. // // IMPORTANT: This method is used for internal data structures and should NOT be used -// for the gRPC Proto conversion. For Proto, SubnetRoutes must be populated manually +// for the gRPC Proto conversion. For Proto, SubnetRoutes must be populated manually // with PrimaryRoutes to ensure it includes only routes actively served by the node. // See the comment in Proto() method and the implementation in grpcv1.go/nodesToProto. func (node *Node) SubnetRoutes() []netip.Prefix {