mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-23 02:24:10 +00:00
all: check unchecked error returns
Fix errcheck and errchkjson lint issues by properly handling or explicitly discarding error return values. Changes include: - cmd/headscale/cli: Check MarkFlagRequired and AddMiddleware errors - hscontrol/db: Check VACUUM exec result - hscontrol/debug: Check Write errors in HTTP handlers - hscontrol/handlers: Add error logging for JSON encoding - hscontrol/mapper: Check AddNode errors in tests - hscontrol/platform_config: Check Write error - hscontrol/util/prompt: Check Scanln and Write errors - integration: Check json.Marshal and cleanup function errors
This commit is contained in:
parent
15d0efbf9d
commit
52fc725cf1
14 changed files with 73 additions and 61 deletions
|
|
@ -134,7 +134,7 @@ func getMockOIDC(clientID string, clientSecret string, users []mockoidc.MockUser
|
||||||
ErrorQueue: &mockoidc.ErrorQueue{},
|
ErrorQueue: &mockoidc.ErrorQueue{},
|
||||||
}
|
}
|
||||||
|
|
||||||
mock.AddMiddleware(func(h http.Handler) http.Handler {
|
_ = mock.AddMiddleware(func(h http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Info().Msgf("Request: %+v", r)
|
log.Info().Msgf("Request: %+v", r)
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,12 @@ func init() {
|
||||||
nodeCmd.AddCommand(deleteNodeCmd)
|
nodeCmd.AddCommand(deleteNodeCmd)
|
||||||
|
|
||||||
tagCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
|
tagCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
|
||||||
tagCmd.MarkFlagRequired("identifier")
|
_ = tagCmd.MarkFlagRequired("identifier")
|
||||||
tagCmd.Flags().StringSliceP("tags", "t", []string{}, "List of tags to add to the node")
|
tagCmd.Flags().StringSliceP("tags", "t", []string{}, "List of tags to add to the node")
|
||||||
nodeCmd.AddCommand(tagCmd)
|
nodeCmd.AddCommand(tagCmd)
|
||||||
|
|
||||||
approveRoutesCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
|
approveRoutesCmd.Flags().Uint64P("identifier", "i", 0, "Node identifier (ID)")
|
||||||
approveRoutesCmd.MarkFlagRequired("identifier")
|
_ = approveRoutesCmd.MarkFlagRequired("identifier")
|
||||||
approveRoutesCmd.Flags().StringSliceP("routes", "r", []string{}, `List of routes that will be approved (comma-separated, e.g. "10.0.0.0/8,192.168.0.0/24" or empty string to remove all approved routes)`)
|
approveRoutesCmd.Flags().StringSliceP("routes", "r", []string{}, `List of routes that will be approved (comma-separated, e.g. "10.0.0.0/8,192.168.0.0/24" or empty string to remove all approved routes)`)
|
||||||
nodeCmd.AddCommand(approveRoutesCmd)
|
nodeCmd.AddCommand(approveRoutesCmd)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func init() {
|
||||||
userCmd.AddCommand(renameUserCmd)
|
userCmd.AddCommand(renameUserCmd)
|
||||||
usernameAndIDFlag(renameUserCmd)
|
usernameAndIDFlag(renameUserCmd)
|
||||||
renameUserCmd.Flags().StringP("new-name", "r", "", "New username")
|
renameUserCmd.Flags().StringP("new-name", "r", "", "New username")
|
||||||
renameNodeCmd.MarkFlagRequired("new-name")
|
_ = renameUserCmd.MarkFlagRequired("new-name")
|
||||||
}
|
}
|
||||||
|
|
||||||
var errMissingParameter = errors.New("missing parameters")
|
var errMissingParameter = errors.New("missing parameters")
|
||||||
|
|
|
||||||
|
|
@ -1035,7 +1035,7 @@ func (hsdb *HSDatabase) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if hsdb.cfg.Database.Type == types.DatabaseSqlite && hsdb.cfg.Database.Sqlite.WriteAheadLog {
|
if hsdb.cfg.Database.Type == types.DatabaseSqlite && hsdb.cfg.Database.Sqlite.WriteAheadLog {
|
||||||
db.Exec("VACUUM")
|
_, _ = db.Exec("VACUUM")
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.Close()
|
return db.Close()
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,14 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(overviewJSON)
|
_, _ = w.Write(overviewJSON)
|
||||||
} else {
|
} else {
|
||||||
// Default to text/plain for backward compatibility
|
// Default to text/plain for backward compatibility
|
||||||
overview := h.state.DebugOverview()
|
overview := h.state.DebugOverview()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(overview))
|
_, _ = w.Write([]byte(overview))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(configJSON)
|
_, _ = w.Write(configJSON)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Policy endpoint
|
// Policy endpoint
|
||||||
|
|
@ -77,7 +77,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(policy))
|
_, _ = w.Write([]byte(policy))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Filter rules endpoint
|
// Filter rules endpoint
|
||||||
|
|
@ -96,7 +96,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(filterJSON)
|
_, _ = w.Write(filterJSON)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// SSH policies endpoint
|
// SSH policies endpoint
|
||||||
|
|
@ -111,7 +111,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(sshJSON)
|
_, _ = w.Write(sshJSON)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// DERP map endpoint
|
// DERP map endpoint
|
||||||
|
|
@ -131,14 +131,14 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(derpJSON)
|
_, _ = w.Write(derpJSON)
|
||||||
} else {
|
} else {
|
||||||
// Default to text/plain for backward compatibility
|
// Default to text/plain for backward compatibility
|
||||||
derpInfo := h.state.DebugDERPMap()
|
derpInfo := h.state.DebugDERPMap()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(derpInfo))
|
_, _ = w.Write([]byte(derpInfo))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -159,14 +159,14 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(nodeStoreJSON)
|
_, _ = w.Write(nodeStoreJSON)
|
||||||
} else {
|
} else {
|
||||||
// Default to text/plain for backward compatibility
|
// Default to text/plain for backward compatibility
|
||||||
nodeStoreInfo := h.state.DebugNodeStore()
|
nodeStoreInfo := h.state.DebugNodeStore()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(nodeStoreInfo))
|
_, _ = w.Write([]byte(nodeStoreInfo))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -182,7 +182,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(cacheJSON)
|
_, _ = w.Write(cacheJSON)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Routes endpoint
|
// Routes endpoint
|
||||||
|
|
@ -202,14 +202,14 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(routesJSON)
|
_, _ = w.Write(routesJSON)
|
||||||
} else {
|
} else {
|
||||||
// Default to text/plain for backward compatibility
|
// Default to text/plain for backward compatibility
|
||||||
routes := h.state.DebugRoutesString()
|
routes := h.state.DebugRoutesString()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(routes))
|
_, _ = w.Write([]byte(routes))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -230,14 +230,14 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(policyManagerJSON)
|
_, _ = w.Write(policyManagerJSON)
|
||||||
} else {
|
} else {
|
||||||
// Default to text/plain for backward compatibility
|
// Default to text/plain for backward compatibility
|
||||||
policyManagerInfo := h.state.DebugPolicyManager()
|
policyManagerInfo := h.state.DebugPolicyManager()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(policyManagerInfo))
|
_, _ = w.Write([]byte(policyManagerInfo))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
@ -250,7 +250,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
if res == nil {
|
if res == nil {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte("HEADSCALE_DEBUG_DUMP_MAPRESPONSE_PATH not set"))
|
_, _ = w.Write([]byte("HEADSCALE_DEBUG_DUMP_MAPRESPONSE_PATH not set"))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +263,7 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(resJSON)
|
_, _ = w.Write(resJSON)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Batcher endpoint
|
// Batcher endpoint
|
||||||
|
|
@ -283,14 +283,14 @@ func (h *Headscale) debugHTTPServer() *http.Server {
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write(batcherJSON)
|
_, _ = w.Write(batcherJSON)
|
||||||
} else {
|
} else {
|
||||||
// Default to text/plain for backward compatibility
|
// Default to text/plain for backward compatibility
|
||||||
batcherInfo := h.debugBatcher()
|
batcherInfo := h.debugBatcher()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(batcherInfo))
|
_, _ = w.Write([]byte(batcherInfo))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,9 @@ func (h *Headscale) KeyHandler(
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "application/json")
|
writer.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(writer).Encode(resp)
|
if err := json.NewEncoder(writer).Encode(resp); err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to encode key response")
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +181,9 @@ func (h *Headscale) HealthHandler(
|
||||||
res.Status = "fail"
|
res.Status = "fail"
|
||||||
}
|
}
|
||||||
|
|
||||||
json.NewEncoder(writer).Encode(res)
|
if err := json.NewEncoder(writer).Encode(res); err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to encode health response")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := h.state.PingDB(req.Context())
|
err := h.state.PingDB(req.Context())
|
||||||
|
|
@ -268,7 +272,7 @@ func (a *AuthProviderWeb) RegisterHandler(
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
writer.Write([]byte(templates.RegisterWeb(registrationId).Render()))
|
_, _ = writer.Write([]byte(templates.RegisterWeb(registrationId).Render()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FaviconHandler(writer http.ResponseWriter, req *http.Request) {
|
func FaviconHandler(writer http.ResponseWriter, req *http.Request) {
|
||||||
|
|
|
||||||
|
|
@ -526,7 +526,7 @@ type multiChannelNodeConn struct {
|
||||||
// generateConnectionID generates a unique connection identifier.
|
// generateConnectionID generates a unique connection identifier.
|
||||||
func generateConnectionID() string {
|
func generateConnectionID() string {
|
||||||
bytes := make([]byte, 8)
|
bytes := make([]byte, 8)
|
||||||
rand.Read(bytes)
|
_, _ = rand.Read(bytes)
|
||||||
|
|
||||||
return hex.EncodeToString(bytes)
|
return hex.EncodeToString(bytes)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -549,7 +549,7 @@ func TestEnhancedTrackingWithBatcher(t *testing.T) {
|
||||||
testNode.start()
|
testNode.start()
|
||||||
|
|
||||||
// Connect the node to the batcher
|
// Connect the node to the batcher
|
||||||
batcher.AddNode(testNode.n.ID, testNode.ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(testNode.n.ID, testNode.ch, tailcfg.CapabilityVersion(100))
|
||||||
|
|
||||||
// Wait for connection to be established
|
// Wait for connection to be established
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||||
|
|
@ -658,7 +658,7 @@ func TestBatcherScalabilityAllToAll(t *testing.T) {
|
||||||
|
|
||||||
for i := range allNodes {
|
for i := range allNodes {
|
||||||
node := &allNodes[i]
|
node := &allNodes[i]
|
||||||
batcher.AddNode(node.n.ID, node.ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(node.n.ID, node.ch, tailcfg.CapabilityVersion(100))
|
||||||
|
|
||||||
// Issue full update after each join to ensure connectivity
|
// Issue full update after each join to ensure connectivity
|
||||||
batcher.AddWork(change.FullUpdate())
|
batcher.AddWork(change.FullUpdate())
|
||||||
|
|
@ -827,7 +827,7 @@ func TestBatcherBasicOperations(t *testing.T) {
|
||||||
tn2 := testData.Nodes[1]
|
tn2 := testData.Nodes[1]
|
||||||
|
|
||||||
// Test AddNode with real node ID
|
// Test AddNode with real node ID
|
||||||
batcher.AddNode(tn.n.ID, tn.ch, 100)
|
_ = batcher.AddNode(tn.n.ID, tn.ch, 100)
|
||||||
|
|
||||||
if !batcher.IsConnected(tn.n.ID) {
|
if !batcher.IsConnected(tn.n.ID) {
|
||||||
t.Error("Node should be connected after AddNode")
|
t.Error("Node should be connected after AddNode")
|
||||||
|
|
@ -848,7 +848,7 @@ func TestBatcherBasicOperations(t *testing.T) {
|
||||||
drainChannelTimeout(tn.ch, "first node before second", 100*time.Millisecond)
|
drainChannelTimeout(tn.ch, "first node before second", 100*time.Millisecond)
|
||||||
|
|
||||||
// Add the second node and verify update message
|
// Add the second node and verify update message
|
||||||
batcher.AddNode(tn2.n.ID, tn2.ch, 100)
|
_ = batcher.AddNode(tn2.n.ID, tn2.ch, 100)
|
||||||
assert.True(t, batcher.IsConnected(tn2.n.ID))
|
assert.True(t, batcher.IsConnected(tn2.n.ID))
|
||||||
|
|
||||||
// First node should get an update that second node has connected.
|
// First node should get an update that second node has connected.
|
||||||
|
|
@ -1053,7 +1053,7 @@ func TestBatcherWorkQueueBatching(t *testing.T) {
|
||||||
testNodes := testData.Nodes
|
testNodes := testData.Nodes
|
||||||
|
|
||||||
ch := make(chan *tailcfg.MapResponse, 10)
|
ch := make(chan *tailcfg.MapResponse, 10)
|
||||||
batcher.AddNode(testNodes[0].n.ID, ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(testNodes[0].n.ID, ch, tailcfg.CapabilityVersion(100))
|
||||||
|
|
||||||
// Track update content for validation
|
// Track update content for validation
|
||||||
var receivedUpdates []*tailcfg.MapResponse
|
var receivedUpdates []*tailcfg.MapResponse
|
||||||
|
|
@ -1157,7 +1157,7 @@ func XTestBatcherChannelClosingRace(t *testing.T) {
|
||||||
ch1 := make(chan *tailcfg.MapResponse, 1)
|
ch1 := make(chan *tailcfg.MapResponse, 1)
|
||||||
|
|
||||||
wg.Go(func() {
|
wg.Go(func() {
|
||||||
batcher.AddNode(testNode.n.ID, ch1, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(testNode.n.ID, ch1, tailcfg.CapabilityVersion(100))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add real work during connection chaos
|
// Add real work during connection chaos
|
||||||
|
|
@ -1170,7 +1170,7 @@ func XTestBatcherChannelClosingRace(t *testing.T) {
|
||||||
|
|
||||||
wg.Go(func() {
|
wg.Go(func() {
|
||||||
runtime.Gosched() // Yield to introduce timing variability
|
runtime.Gosched() // Yield to introduce timing variability
|
||||||
batcher.AddNode(testNode.n.ID, ch2, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(testNode.n.ID, ch2, tailcfg.CapabilityVersion(100))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Remove second connection
|
// Remove second connection
|
||||||
|
|
@ -1261,7 +1261,7 @@ func TestBatcherWorkerChannelSafety(t *testing.T) {
|
||||||
ch := make(chan *tailcfg.MapResponse, 5)
|
ch := make(chan *tailcfg.MapResponse, 5)
|
||||||
|
|
||||||
// Add node and immediately queue real work
|
// Add node and immediately queue real work
|
||||||
batcher.AddNode(testNode.n.ID, ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(testNode.n.ID, ch, tailcfg.CapabilityVersion(100))
|
||||||
batcher.AddWork(change.DERPMap())
|
batcher.AddWork(change.DERPMap())
|
||||||
|
|
||||||
// Consumer goroutine to validate data and detect channel issues
|
// Consumer goroutine to validate data and detect channel issues
|
||||||
|
|
@ -1384,7 +1384,7 @@ func TestBatcherConcurrentClients(t *testing.T) {
|
||||||
for _, node := range stableNodes {
|
for _, node := range stableNodes {
|
||||||
ch := make(chan *tailcfg.MapResponse, NORMAL_BUFFER_SIZE)
|
ch := make(chan *tailcfg.MapResponse, NORMAL_BUFFER_SIZE)
|
||||||
stableChannels[node.n.ID] = ch
|
stableChannels[node.n.ID] = ch
|
||||||
batcher.AddNode(node.n.ID, ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(node.n.ID, ch, tailcfg.CapabilityVersion(100))
|
||||||
|
|
||||||
// Monitor updates for each stable client
|
// Monitor updates for each stable client
|
||||||
go func(nodeID types.NodeID, channel chan *tailcfg.MapResponse) {
|
go func(nodeID types.NodeID, channel chan *tailcfg.MapResponse) {
|
||||||
|
|
@ -1458,7 +1458,7 @@ func TestBatcherConcurrentClients(t *testing.T) {
|
||||||
|
|
||||||
churningChannelsMutex.Unlock()
|
churningChannelsMutex.Unlock()
|
||||||
|
|
||||||
batcher.AddNode(nodeID, ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(nodeID, ch, tailcfg.CapabilityVersion(100))
|
||||||
|
|
||||||
// Consume updates to prevent blocking
|
// Consume updates to prevent blocking
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -1771,7 +1771,7 @@ func XTestBatcherScalability(t *testing.T) {
|
||||||
|
|
||||||
for i := range testNodes {
|
for i := range testNodes {
|
||||||
node := &testNodes[i]
|
node := &testNodes[i]
|
||||||
batcher.AddNode(node.n.ID, node.ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(node.n.ID, node.ch, tailcfg.CapabilityVersion(100))
|
||||||
connectedNodesMutex.Lock()
|
connectedNodesMutex.Lock()
|
||||||
|
|
||||||
connectedNodes[node.n.ID] = true
|
connectedNodes[node.n.ID] = true
|
||||||
|
|
@ -2149,7 +2149,7 @@ func TestBatcherFullPeerUpdates(t *testing.T) {
|
||||||
|
|
||||||
// Connect nodes one at a time and wait for each to be connected
|
// Connect nodes one at a time and wait for each to be connected
|
||||||
for i, node := range allNodes {
|
for i, node := range allNodes {
|
||||||
batcher.AddNode(node.n.ID, node.ch, tailcfg.CapabilityVersion(100))
|
_ = batcher.AddNode(node.n.ID, node.ch, tailcfg.CapabilityVersion(100))
|
||||||
t.Logf("Connected node %d (ID: %d)", i, node.n.ID)
|
t.Logf("Connected node %d (ID: %d)", i, node.n.ID)
|
||||||
|
|
||||||
// Wait for node to be connected
|
// Wait for node to be connected
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ func (h *Headscale) WindowsConfigMessage(
|
||||||
) {
|
) {
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
writer.Write([]byte(templates.Windows(h.cfg.ServerURL).Render()))
|
_, _ = writer.Write([]byte(templates.Windows(h.cfg.ServerURL).Render()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppleConfigMessage shows a simple message in the browser to point the user to the iOS/MacOS profile and instructions for how to install it.
|
// AppleConfigMessage shows a simple message in the browser to point the user to the iOS/MacOS profile and instructions for how to install it.
|
||||||
|
|
@ -29,7 +29,7 @@ func (h *Headscale) AppleConfigMessage(
|
||||||
) {
|
) {
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
writer.Write([]byte(templates.Apple(h.cfg.ServerURL).Render()))
|
_, _ = writer.Write([]byte(templates.Apple(h.cfg.ServerURL).Render()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Headscale) ApplePlatformConfig(
|
func (h *Headscale) ApplePlatformConfig(
|
||||||
|
|
@ -98,7 +98,7 @@ func (h *Headscale) ApplePlatformConfig(
|
||||||
writer.Header().
|
writer.Header().
|
||||||
Set("Content-Type", "application/x-apple-aspen-config; charset=utf-8")
|
Set("Content-Type", "application/x-apple-aspen-config; charset=utf-8")
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
writer.Write(content.Bytes())
|
_, _ = writer.Write(content.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppleMobileConfig struct {
|
type AppleMobileConfig struct {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ func YesNo(msg string) bool {
|
||||||
fmt.Fprint(os.Stderr, msg+" [y/n] ")
|
fmt.Fprint(os.Stderr, msg+" [y/n] ")
|
||||||
|
|
||||||
var resp string
|
var resp string
|
||||||
fmt.Scanln(&resp)
|
_, _ = fmt.Scanln(&resp)
|
||||||
|
|
||||||
resp = strings.ToLower(resp)
|
resp = strings.ToLower(resp)
|
||||||
switch resp {
|
switch resp {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ func TestYesNo(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
|
|
||||||
w.WriteString(tt.input)
|
_, _ = w.WriteString(tt.input)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Call the function
|
// Call the function
|
||||||
|
|
@ -106,7 +106,7 @@ func TestYesNo(t *testing.T) {
|
||||||
|
|
||||||
// Check that the prompt was written to stderr
|
// Check that the prompt was written to stderr
|
||||||
var stderrBuf bytes.Buffer
|
var stderrBuf bytes.Buffer
|
||||||
io.Copy(&stderrBuf, stderrR)
|
_, _ = io.Copy(&stderrBuf, stderrR)
|
||||||
stderrR.Close()
|
stderrR.Close()
|
||||||
|
|
||||||
expectedPrompt := "Test question [y/n] "
|
expectedPrompt := "Test question [y/n] "
|
||||||
|
|
@ -134,7 +134,7 @@ func TestYesNoPromptMessage(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
|
|
||||||
w.WriteString("n\n")
|
_, _ = w.WriteString("n\n")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Call the function with a custom message
|
// Call the function with a custom message
|
||||||
|
|
@ -149,7 +149,7 @@ func TestYesNoPromptMessage(t *testing.T) {
|
||||||
|
|
||||||
// Check that the custom message was included in the prompt
|
// Check that the custom message was included in the prompt
|
||||||
var stderrBuf bytes.Buffer
|
var stderrBuf bytes.Buffer
|
||||||
io.Copy(&stderrBuf, stderrR)
|
_, _ = io.Copy(&stderrBuf, stderrR)
|
||||||
stderrR.Close()
|
stderrR.Close()
|
||||||
|
|
||||||
expectedPrompt := customMessage + " [y/n] "
|
expectedPrompt := customMessage + " [y/n] "
|
||||||
|
|
@ -193,7 +193,7 @@ func TestYesNoCaseInsensitive(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
defer w.Close()
|
defer w.Close()
|
||||||
|
|
||||||
w.WriteString(tc.input)
|
_, _ = w.WriteString(tc.input)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Call the function
|
// Call the function
|
||||||
|
|
@ -206,7 +206,7 @@ func TestYesNoCaseInsensitive(t *testing.T) {
|
||||||
stderrW.Close()
|
stderrW.Close()
|
||||||
|
|
||||||
// Drain stderr
|
// Drain stderr
|
||||||
io.Copy(io.Discard, stderrR)
|
_, _ = io.Copy(io.Discard, stderrR)
|
||||||
stderrR.Close()
|
stderrR.Close()
|
||||||
|
|
||||||
if result != tc.expected {
|
if result != tc.expected {
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,10 @@ func TestAuthWebFlowLogoutAndReloginNewUser(t *testing.T) {
|
||||||
|
|
||||||
// Register all clients as user1 (this is where cross-user registration happens)
|
// Register all clients as user1 (this is where cross-user registration happens)
|
||||||
// This simulates: headscale nodes register --user user1 --key <key>
|
// This simulates: headscale nodes register --user user1 --key <key>
|
||||||
scenario.runHeadscaleRegister("user1", body)
|
err = scenario.runHeadscaleRegister("user1", body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to register client %s: %s", client.Hostname(), err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all clients to reach running state
|
// Wait for all clients to reach running state
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,8 @@ func TestResolveMagicDNSExtraRecordsPath(t *testing.T) {
|
||||||
Value: "6.6.6.6",
|
Value: "6.6.6.6",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
b, _ := json.Marshal(extraRecords)
|
b, err := json.Marshal(extraRecords)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv([]tsic.Option{
|
err = scenario.CreateHeadscaleEnv([]tsic.Option{
|
||||||
tsic.WithPackages("python3", "curl", "bind-tools"),
|
tsic.WithPackages("python3", "curl", "bind-tools"),
|
||||||
|
|
@ -133,13 +134,14 @@ func TestResolveMagicDNSExtraRecordsPath(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Write the file directly into place from the docker API.
|
// Write the file directly into place from the docker API.
|
||||||
b0, _ := json.Marshal([]tailcfg.DNSRecord{
|
b0, err := json.Marshal([]tailcfg.DNSRecord{
|
||||||
{
|
{
|
||||||
Name: "docker.myvpn.example.com",
|
Name: "docker.myvpn.example.com",
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Value: "2.2.2.2",
|
Value: "2.2.2.2",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = hs.WriteFile(erPath, b0)
|
err = hs.WriteFile(erPath, b0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
@ -155,7 +157,8 @@ func TestResolveMagicDNSExtraRecordsPath(t *testing.T) {
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Value: "7.7.7.7",
|
Value: "7.7.7.7",
|
||||||
})
|
})
|
||||||
b2, _ := json.Marshal(extraRecords)
|
b2, err := json.Marshal(extraRecords)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = hs.WriteFile(erPath+"2", b2)
|
err = hs.WriteFile(erPath+"2", b2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
@ -169,13 +172,14 @@ func TestResolveMagicDNSExtraRecordsPath(t *testing.T) {
|
||||||
|
|
||||||
// Write a new file and copy it to the path to ensure the reload
|
// Write a new file and copy it to the path to ensure the reload
|
||||||
// works when a file is copied into place.
|
// works when a file is copied into place.
|
||||||
b3, _ := json.Marshal([]tailcfg.DNSRecord{
|
b3, err := json.Marshal([]tailcfg.DNSRecord{
|
||||||
{
|
{
|
||||||
Name: "copy.myvpn.example.com",
|
Name: "copy.myvpn.example.com",
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Value: "8.8.8.8",
|
Value: "8.8.8.8",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = hs.WriteFile(erPath+"3", b3)
|
err = hs.WriteFile(erPath+"3", b3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
@ -187,13 +191,14 @@ func TestResolveMagicDNSExtraRecordsPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write in place to ensure pipe like behaviour works
|
// Write in place to ensure pipe like behaviour works
|
||||||
b4, _ := json.Marshal([]tailcfg.DNSRecord{
|
b4, err := json.Marshal([]tailcfg.DNSRecord{
|
||||||
{
|
{
|
||||||
Name: "docker.myvpn.example.com",
|
Name: "docker.myvpn.example.com",
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Value: "9.9.9.9",
|
Value: "9.9.9.9",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
command := []string{"echo", fmt.Sprintf("'%s'", string(b4)), ">", erPath}
|
command := []string{"echo", fmt.Sprintf("'%s'", string(b4)), ">", erPath}
|
||||||
_, err = hs.Execute([]string{"bash", "-c", strings.Join(command, " ")})
|
_, err = hs.Execute([]string{"bash", "-c", strings.Join(command, " ")})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
||||||
|
|
@ -169,8 +169,8 @@ func NewScenario(spec ScenarioSpec) (*Scenario, error) {
|
||||||
// Opportunity to clean up unreferenced networks.
|
// Opportunity to clean up unreferenced networks.
|
||||||
// This might be a no op, but it is worth a try as we sometime
|
// This might be a no op, but it is worth a try as we sometime
|
||||||
// dont clean up nicely after ourselves.
|
// dont clean up nicely after ourselves.
|
||||||
dockertestutil.CleanUnreferencedNetworks(pool)
|
_ = dockertestutil.CleanUnreferencedNetworks(pool)
|
||||||
dockertestutil.CleanImagesInCI(pool)
|
_ = dockertestutil.CleanImagesInCI(pool)
|
||||||
|
|
||||||
if spec.MaxWait == 0 {
|
if spec.MaxWait == 0 {
|
||||||
pool.MaxWait = dockertestMaxWait()
|
pool.MaxWait = dockertestMaxWait()
|
||||||
|
|
@ -314,8 +314,8 @@ func (s *Scenario) Services(name string) ([]*dockertest.Resource, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
|
func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
|
||||||
defer dockertestutil.CleanUnreferencedNetworks(s.pool)
|
defer func() { _ = dockertestutil.CleanUnreferencedNetworks(s.pool) }()
|
||||||
defer dockertestutil.CleanImagesInCI(s.pool)
|
defer func() { _ = dockertestutil.CleanImagesInCI(s.pool) }()
|
||||||
|
|
||||||
s.controlServers.Range(func(_ string, control ControlServer) bool {
|
s.controlServers.Range(func(_ string, control ControlServer) bool {
|
||||||
stdoutPath, stderrPath, err := control.Shutdown()
|
stdoutPath, stderrPath, err := control.Shutdown()
|
||||||
|
|
@ -920,7 +920,7 @@ func (s *Scenario) RunTailscaleUpWithURL(userStr, loginServer string) error {
|
||||||
// If the URL is not a OIDC URL, then we need to
|
// If the URL is not a OIDC URL, then we need to
|
||||||
// run the register command to fully log in the client.
|
// run the register command to fully log in the client.
|
||||||
if !strings.Contains(loginURL.String(), "/oidc/") {
|
if !strings.Contains(loginURL.String(), "/oidc/") {
|
||||||
s.runHeadscaleRegister(userStr, body)
|
_ = s.runHeadscaleRegister(userStr, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue