mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
[client] Fix/health result in bundle (#5164)
* Add support for optional status refresh callback during debug bundle generation * Always update wg status * Remove duplicated wg status call
This commit is contained in:
@@ -228,6 +228,7 @@ type BundleGenerator struct {
|
|||||||
syncResponse *mgmProto.SyncResponse
|
syncResponse *mgmProto.SyncResponse
|
||||||
logPath string
|
logPath string
|
||||||
cpuProfile []byte
|
cpuProfile []byte
|
||||||
|
refreshStatus func() // Optional callback to refresh status before bundle generation
|
||||||
|
|
||||||
anonymize bool
|
anonymize bool
|
||||||
includeSystemInfo bool
|
includeSystemInfo bool
|
||||||
@@ -248,6 +249,7 @@ type GeneratorDependencies struct {
|
|||||||
SyncResponse *mgmProto.SyncResponse
|
SyncResponse *mgmProto.SyncResponse
|
||||||
LogPath string
|
LogPath string
|
||||||
CPUProfile []byte
|
CPUProfile []byte
|
||||||
|
RefreshStatus func() // Optional callback to refresh status before bundle generation
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGenerator {
|
func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGenerator {
|
||||||
@@ -265,6 +267,7 @@ func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGen
|
|||||||
syncResponse: deps.SyncResponse,
|
syncResponse: deps.SyncResponse,
|
||||||
logPath: deps.LogPath,
|
logPath: deps.LogPath,
|
||||||
cpuProfile: deps.CPUProfile,
|
cpuProfile: deps.CPUProfile,
|
||||||
|
refreshStatus: deps.RefreshStatus,
|
||||||
|
|
||||||
anonymize: cfg.Anonymize,
|
anonymize: cfg.Anonymize,
|
||||||
includeSystemInfo: cfg.IncludeSystemInfo,
|
includeSystemInfo: cfg.IncludeSystemInfo,
|
||||||
@@ -408,6 +411,10 @@ func (g *BundleGenerator) addStatus() error {
|
|||||||
profName = activeProf.Name
|
profName = activeProf.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if g.refreshStatus != nil {
|
||||||
|
g.refreshStatus()
|
||||||
|
}
|
||||||
|
|
||||||
fullStatus := g.statusRecorder.GetFullStatus()
|
fullStatus := g.statusRecorder.GetFullStatus()
|
||||||
protoFullStatus := nbstatus.ToProtoFullStatus(fullStatus)
|
protoFullStatus := nbstatus.ToProtoFullStatus(fullStatus)
|
||||||
protoFullStatus.Events = g.statusRecorder.GetEventHistory()
|
protoFullStatus.Events = g.statusRecorder.GetEventHistory()
|
||||||
|
|||||||
@@ -1050,6 +1050,9 @@ func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobR
|
|||||||
StatusRecorder: e.statusRecorder,
|
StatusRecorder: e.statusRecorder,
|
||||||
SyncResponse: syncResponse,
|
SyncResponse: syncResponse,
|
||||||
LogPath: e.config.LogPath,
|
LogPath: e.config.LogPath,
|
||||||
|
RefreshStatus: func() {
|
||||||
|
e.RunHealthProbes(true)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
bundleJobParams := debug.BundleConfig{
|
bundleJobParams := debug.BundleConfig{
|
||||||
@@ -1827,7 +1830,7 @@ func (e *Engine) getRosenpassAddr() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunHealthProbes executes health checks for Signal, Management, Relay and WireGuard services
|
// RunHealthProbes executes health checks for Signal, Management, Relay, and WireGuard services
|
||||||
// and updates the status recorder with the latest states.
|
// and updates the status recorder with the latest states.
|
||||||
func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
||||||
e.syncMsgMux.Lock()
|
e.syncMsgMux.Lock()
|
||||||
@@ -1841,23 +1844,8 @@ func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
|||||||
stuns := slices.Clone(e.STUNs)
|
stuns := slices.Clone(e.STUNs)
|
||||||
turns := slices.Clone(e.TURNs)
|
turns := slices.Clone(e.TURNs)
|
||||||
|
|
||||||
if e.wgInterface != nil {
|
if err := e.statusRecorder.RefreshWireGuardStats(); err != nil {
|
||||||
stats, err := e.wgInterface.GetStats()
|
log.Debugf("failed to refresh WireGuard stats: %v", err)
|
||||||
if err != nil {
|
|
||||||
log.Warnf("failed to get wireguard stats: %v", err)
|
|
||||||
e.syncMsgMux.Unlock()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, key := range e.peerStore.PeersPubKey() {
|
|
||||||
// wgStats could be zero value, in which case we just reset the stats
|
|
||||||
wgStats, ok := stats[key]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := e.statusRecorder.UpdateWireGuardPeerState(key, wgStats); err != nil {
|
|
||||||
log.Debugf("failed to update wg stats for peer %s: %s", key, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.syncMsgMux.Unlock()
|
e.syncMsgMux.Unlock()
|
||||||
|
|||||||
@@ -1145,6 +1145,38 @@ func (d *Status) PeersStatus() (*configurer.Stats, error) {
|
|||||||
return d.wgIface.FullStats()
|
return d.wgIface.FullStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RefreshWireGuardStats fetches fresh WireGuard statistics from the interface
|
||||||
|
// and updates the cached peer states. This ensures accurate handshake times and
|
||||||
|
// transfer statistics in status reports without running full health probes.
|
||||||
|
func (d *Status) RefreshWireGuardStats() error {
|
||||||
|
d.mux.Lock()
|
||||||
|
defer d.mux.Unlock()
|
||||||
|
|
||||||
|
if d.wgIface == nil {
|
||||||
|
return nil // silently skip if interface not set
|
||||||
|
}
|
||||||
|
|
||||||
|
stats, err := d.wgIface.FullStats()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get wireguard stats: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update each peer's WireGuard statistics
|
||||||
|
for _, peerStats := range stats.Peers {
|
||||||
|
peerState, ok := d.peers[peerStats.PublicKey]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
peerState.LastWireguardHandshake = peerStats.LastHandshake
|
||||||
|
peerState.BytesRx = peerStats.RxBytes
|
||||||
|
peerState.BytesTx = peerStats.TxBytes
|
||||||
|
d.peers[peerStats.PublicKey] = peerState
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type EventQueue struct {
|
type EventQueue struct {
|
||||||
maxSize int
|
maxSize int
|
||||||
events []*proto.SystemEvent
|
events []*proto.SystemEvent
|
||||||
|
|||||||
@@ -34,6 +34,18 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) (
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare refresh callback for health probes
|
||||||
|
var refreshStatus func()
|
||||||
|
if s.connectClient != nil {
|
||||||
|
engine := s.connectClient.Engine()
|
||||||
|
if engine != nil {
|
||||||
|
refreshStatus = func() {
|
||||||
|
log.Debug("refreshing system health status for debug bundle")
|
||||||
|
engine.RunHealthProbes(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bundleGenerator := debug.NewBundleGenerator(
|
bundleGenerator := debug.NewBundleGenerator(
|
||||||
debug.GeneratorDependencies{
|
debug.GeneratorDependencies{
|
||||||
InternalConfig: s.config,
|
InternalConfig: s.config,
|
||||||
@@ -41,6 +53,7 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) (
|
|||||||
SyncResponse: syncResponse,
|
SyncResponse: syncResponse,
|
||||||
LogPath: s.logFile,
|
LogPath: s.logFile,
|
||||||
CPUProfile: cpuProfileData,
|
CPUProfile: cpuProfileData,
|
||||||
|
RefreshStatus: refreshStatus,
|
||||||
},
|
},
|
||||||
debug.BundleConfig{
|
debug.BundleConfig{
|
||||||
Anonymize: req.GetAnonymize(),
|
Anonymize: req.GetAnonymize(),
|
||||||
|
|||||||
@@ -1327,6 +1327,10 @@ func (s *Server) runProbes(waitForProbeResult bool) {
|
|||||||
if engine.RunHealthProbes(waitForProbeResult) {
|
if engine.RunHealthProbes(waitForProbeResult) {
|
||||||
s.lastProbe = time.Now()
|
s.lastProbe = time.Now()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if err := s.statusRecorder.RefreshWireGuardStats(); err != nil {
|
||||||
|
log.Debugf("failed to refresh WireGuard stats: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user