testcontrol: send updates for new DNS records or app capabilities

Two methods were recently added to the testcontrol.Server type:
AddDNSRecords and SetGlobalAppCaps. These two methods should trigger
netmap updates for all nodes connected to the Server instance, the way
that other state-change methods do (see SetNodeCapMap, for example).

This will also allow us to get rid of Server.ForceNetmapUpdate, which
was a band-aid fix to force the netmap updates which should have been
triggered by the aforementioned methods.

Fixes tailscale/corp#37102

Signed-off-by: Harry Harpham <harry@tailscale.com>
main
Harry Harpham 2 months ago
parent 73d09316e2
commit 84ee5b640b
  1. 6
      tsnet/tsnet_test.go
  2. 41
      tstest/integration/testcontrol/testcontrol.go

@ -1194,10 +1194,8 @@ func TestListenService(t *testing.T) {
tt.extraSetup(t, control)
}
// Force netmap updates to avoid race conditions. The nodes need to
// see our control updates before we can start the test.
must.Do(control.ForceNetmapUpdate(ctx, serviceHost.lb.NodeKey()))
must.Do(control.ForceNetmapUpdate(ctx, serviceClient.lb.NodeKey()))
// Wait until both nodes have up-to-date netmaps before
// proceeding with the test.
netmapUpToDate := func(s *Server) bool {
nm := s.lb.NetMap()
return slices.ContainsFunc(nm.DNS.ExtraRecords, func(r tailcfg.DNSRecord) bool {

@ -299,43 +299,6 @@ func (s *Server) addDebugMessage(nodeKeyDst key.NodePublic, msg any) bool {
return sendUpdate(oldUpdatesCh, updateDebugInjection)
}
// ForceNetmapUpdate waits for the node to get stuck in a map poll and then
// sends the current netmap (which may result in a redundant netmap). The
// intended use case is ensuring state changes propagate before running tests.
//
// This should only be called for nodes connected as streaming clients. Calling
// this with a non-streaming node will result in non-deterministic behavior.
//
// This function cannot guarantee that the node has processed the issued update,
// so tests should confirm processing by querying the node. By example:
//
// if err := s.ForceNetmapUpdate(node.Key()); err != nil {
// // handle error
// }
// for !updatesPresent(node.NetMap()) {
// time.Sleep(10 * time.Millisecond)
// }
func (s *Server) ForceNetmapUpdate(ctx context.Context, nodeKey key.NodePublic) error {
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
if err := s.AwaitNodeInMapRequest(ctx, nodeKey); err != nil {
return fmt.Errorf("waiting for node to poll: %w", err)
}
mr, err := s.MapResponse(&tailcfg.MapRequest{NodeKey: nodeKey})
if err != nil {
return fmt.Errorf("generating map response: %w", err)
}
if s.addDebugMessage(nodeKey, mr) {
return nil
}
// If we failed to send the map response, loop around and try again.
}
}
// Mark the Node key of every node as expired
func (s *Server) SetExpireAllNodes(expired bool) {
s.mu.Lock()
@ -589,8 +552,9 @@ func (s *Server) SetNodeCapMap(nodeKey key.NodePublic, capMap tailcfg.NodeCapMap
// ]
func (s *Server) SetGlobalAppCaps(appCaps tailcfg.PeerCapMap) {
s.mu.Lock()
defer s.mu.Unlock()
s.globalAppCaps = appCaps
s.mu.Unlock()
s.updateLocked("SetGlobalAppCaps", s.nodeIDsLocked(0))
}
// AddDNSRecords adds records to the server's DNS config.
@ -601,6 +565,7 @@ func (s *Server) AddDNSRecords(records ...tailcfg.DNSRecord) {
s.DNSConfig = new(tailcfg.DNSConfig)
}
s.DNSConfig.ExtraRecords = append(s.DNSConfig.ExtraRecords, records...)
s.updateLocked("AddDNSRecords", s.nodeIDsLocked(0))
}
// nodeIDsLocked returns the node IDs of all nodes in the server, except

Loading…
Cancel
Save