From a5a0bf6ff4733c0c6de4ef3032229dbde0d83703 Mon Sep 17 00:00:00 2001 From: "Theodor S. Midtlien" Date: Wed, 20 May 2026 17:45:04 +0200 Subject: [PATCH] Fix daemon and cli version in bundle and status --- client/cmd/debug.go | 4 ++++ client/internal/debug/debug.go | 12 ++++++++---- client/internal/engine.go | 2 ++ client/proto/daemon.pb.go | 15 +++++++++++++-- client/proto/daemon.proto | 1 + client/proto/generate.sh | 13 ++++++------- client/server/debug.go | 3 +++ client/status/status.go | 14 ++++++++++++-- client/ui/debug.go | 3 +++ 9 files changed, 52 insertions(+), 15 deletions(-) diff --git a/client/cmd/debug.go b/client/cmd/debug.go index 2a8cdc887..02a742b28 100644 --- a/client/cmd/debug.go +++ b/client/cmd/debug.go @@ -19,6 +19,7 @@ import ( "github.com/netbirdio/netbird/client/server" mgmProto "github.com/netbirdio/netbird/shared/management/proto" "github.com/netbirdio/netbird/upload-server/types" + "github.com/netbirdio/netbird/version" ) const errCloseConnection = "Failed to close connection: %v" @@ -100,6 +101,7 @@ func debugBundle(cmd *cobra.Command, _ []string) error { Anonymize: anonymizeFlag, SystemInfo: systemInfoFlag, LogFileCount: logFileCount, + CliVersion: version.NetbirdVersion(), } if uploadBundleFlag { request.UploadURL = uploadBundleURLFlag @@ -298,6 +300,7 @@ func runForDuration(cmd *cobra.Command, args []string) error { Anonymize: anonymizeFlag, SystemInfo: systemInfoFlag, LogFileCount: logFileCount, + CliVersion: version.NetbirdVersion(), } if uploadBundleFlag { request.UploadURL = uploadBundleURLFlag @@ -432,6 +435,7 @@ func generateDebugBundle(config *profilemanager.Config, recorder *peer.Status, c SyncResponse: syncResponse, LogPath: logFilePath, CPUProfile: nil, + DaemonVersion: version.NetbirdVersion(), // acting as daemon }, debug.BundleConfig{ IncludeSystemInfo: true, diff --git a/client/internal/debug/debug.go b/client/internal/debug/debug.go index 4f84c2457..a42543b73 100644 --- a/client/internal/debug/debug.go +++ b/client/internal/debug/debug.go @@ -32,7 +32,6 @@ import ( nbstatus "github.com/netbirdio/netbird/client/status" mgmProto "github.com/netbirdio/netbird/shared/management/proto" "github.com/netbirdio/netbird/shared/netiputil" - "github.com/netbirdio/netbird/version" ) const readmeContent = `Netbird debug bundle @@ -255,6 +254,8 @@ type BundleGenerator struct { capturePath string refreshStatus func() // Optional callback to refresh status before bundle generation clientMetrics MetricsExporter + daemonVersion string + cliVersion string anonymize bool includeSystemInfo bool @@ -279,6 +280,8 @@ type GeneratorDependencies struct { CapturePath string RefreshStatus func() ClientMetrics MetricsExporter + DaemonVersion string + CliVersion string } func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGenerator { @@ -300,6 +303,8 @@ func NewBundleGenerator(deps GeneratorDependencies, cfg BundleConfig) *BundleGen capturePath: deps.CapturePath, refreshStatus: deps.RefreshStatus, clientMetrics: deps.ClientMetrics, + daemonVersion: deps.DaemonVersion, + cliVersion: deps.CliVersion, anonymize: cfg.Anonymize, includeSystemInfo: cfg.IncludeSystemInfo, @@ -462,10 +467,9 @@ func (g *BundleGenerator) addStatus() error { overview := nbstatus.ConvertToStatusOutputOverview(protoFullStatus, nbstatus.ConvertOptions{ Anonymize: g.anonymize, ProfileName: profName, - DaemonVersion: version.NetbirdVersion(), + DaemonVersion: g.daemonVersion, }) - // It is always the daemon/engine that generates the bundle, we cannot know if the CLI and daemon version differs. - overview.CliVersion = "N/A" + overview.CliVersion = g.cliVersion statusOutput := overview.FullDetailSummary() statusReader := strings.NewReader(statusOutput) diff --git a/client/internal/engine.go b/client/internal/engine.go index b82eb95b7..acdc1afe1 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -72,6 +72,7 @@ import ( sProto "github.com/netbirdio/netbird/shared/signal/proto" "github.com/netbirdio/netbird/util" "github.com/netbirdio/netbird/util/capture" + "github.com/netbirdio/netbird/version" ) // PeerConnectionTimeoutMax is a timeout of an initial connection attempt to a remote peer. @@ -1141,6 +1142,7 @@ func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobR LogPath: e.config.LogPath, TempDir: e.config.TempDir, ClientMetrics: e.clientMetrics, + DaemonVersion: version.NetbirdVersion(), RefreshStatus: func() { e.RunHealthProbes(true) }, diff --git a/client/proto/daemon.pb.go b/client/proto/daemon.pb.go index 2c054c99a..b96c71cfc 100644 --- a/client/proto/daemon.pb.go +++ b/client/proto/daemon.pb.go @@ -2709,6 +2709,7 @@ type DebugBundleRequest struct { SystemInfo bool `protobuf:"varint,3,opt,name=systemInfo,proto3" json:"systemInfo,omitempty"` UploadURL string `protobuf:"bytes,4,opt,name=uploadURL,proto3" json:"uploadURL,omitempty"` LogFileCount uint32 `protobuf:"varint,5,opt,name=logFileCount,proto3" json:"logFileCount,omitempty"` + CliVersion string `protobuf:"bytes,6,opt,name=cliVersion,proto3" json:"cliVersion,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -2771,6 +2772,13 @@ func (x *DebugBundleRequest) GetLogFileCount() uint32 { return 0 } +func (x *DebugBundleRequest) GetCliVersion() string { + if x != nil { + return x.CliVersion + } + return "" +} + type DebugBundleResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` @@ -6475,14 +6483,17 @@ const file_daemon_proto_rawDesc = "" + "\x12translatedHostname\x18\x04 \x01(\tR\x12translatedHostname\x128\n" + "\x0etranslatedPort\x18\x05 \x01(\v2\x10.daemon.PortInfoR\x0etranslatedPort\"G\n" + "\x17ForwardingRulesResponse\x12,\n" + - "\x05rules\x18\x01 \x03(\v2\x16.daemon.ForwardingRuleR\x05rules\"\x94\x01\n" + + "\x05rules\x18\x01 \x03(\v2\x16.daemon.ForwardingRuleR\x05rules\"\xb4\x01\n" + "\x12DebugBundleRequest\x12\x1c\n" + "\tanonymize\x18\x01 \x01(\bR\tanonymize\x12\x1e\n" + "\n" + "systemInfo\x18\x03 \x01(\bR\n" + "systemInfo\x12\x1c\n" + "\tuploadURL\x18\x04 \x01(\tR\tuploadURL\x12\"\n" + - "\flogFileCount\x18\x05 \x01(\rR\flogFileCount\"}\n" + + "\flogFileCount\x18\x05 \x01(\rR\flogFileCount\x12\x1e\n" + + "\n" + + "cliVersion\x18\x06 \x01(\tR\n" + + "cliVersion\"}\n" + "\x13DebugBundleResponse\x12\x12\n" + "\x04path\x18\x01 \x01(\tR\x04path\x12 \n" + "\vuploadedKey\x18\x02 \x01(\tR\vuploadedKey\x120\n" + diff --git a/client/proto/daemon.proto b/client/proto/daemon.proto index dedff43e2..2a56534a0 100644 --- a/client/proto/daemon.proto +++ b/client/proto/daemon.proto @@ -471,6 +471,7 @@ message DebugBundleRequest { bool systemInfo = 3; string uploadURL = 4; uint32 logFileCount = 5; + string cliVersion = 6; } message DebugBundleResponse { diff --git a/client/proto/generate.sh b/client/proto/generate.sh index e659cef90..1ae55e380 100755 --- a/client/proto/generate.sh +++ b/client/proto/generate.sh @@ -1,17 +1,16 @@ #!/bin/bash set -e -if ! which realpath > /dev/null 2>&1 -then - echo realpath is not installed - echo run: brew install coreutils - exit 1 +if ! which realpath >/dev/null 2>&1; then + echo realpath is not installed + echo run: brew install coreutils + exit 1 fi old_pwd=$(pwd) -script_path=$(dirname $(realpath "$0")) +script_path=$(dirname "$(realpath "$0")") cd "$script_path" go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.6 -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.6.1 protoc -I ./ ./daemon.proto --go_out=../ --go-grpc_out=../ --experimental_allow_proto3_optional cd "$old_pwd" diff --git a/client/server/debug.go b/client/server/debug.go index 33247db5f..14dcaba33 100644 --- a/client/server/debug.go +++ b/client/server/debug.go @@ -14,6 +14,7 @@ import ( "github.com/netbirdio/netbird/client/internal/debug" "github.com/netbirdio/netbird/client/proto" mgmProto "github.com/netbirdio/netbird/shared/management/proto" + "github.com/netbirdio/netbird/version" ) // DebugBundle creates a debug bundle and returns the location. @@ -67,6 +68,8 @@ func (s *Server) DebugBundle(_ context.Context, req *proto.DebugBundleRequest) ( CapturePath: capturePath, RefreshStatus: refreshStatus, ClientMetrics: clientMetrics, + DaemonVersion: version.NetbirdVersion(), + CliVersion: req.CliVersion, }, debug.BundleConfig{ Anonymize: req.GetAnonymize(), diff --git a/client/status/status.go b/client/status/status.go index 11ed06c2d..ed27f06a1 100644 --- a/client/status/status.go +++ b/client/status/status.go @@ -547,6 +547,16 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS goarm = fmt.Sprintf(" (ARMv%s)", os.Getenv("GOARM")) } + daemonVersion := "N/A" + if o.DaemonVersion != "" { + daemonVersion = o.DaemonVersion + } + + cliVersion := version.NetbirdVersion() + if o.CliVersion != "" { + cliVersion = o.CliVersion + } + summary := fmt.Sprintf( "OS: %s\n"+ "Daemon version: %s\n"+ @@ -567,8 +577,8 @@ func (o *OutputOverview) GeneralSummary(showURL bool, showRelays bool, showNameS "%s"+ "Peers count: %s\n", fmt.Sprintf("%s/%s%s", goos, goarch, goarm), - o.DaemonVersion, - version.NetbirdVersion(), + daemonVersion, + cliVersion, o.ProfileName, managementConnString, signalConnString, diff --git a/client/ui/debug.go b/client/ui/debug.go index cf5ac1a75..d3d4fa4f8 100644 --- a/client/ui/debug.go +++ b/client/ui/debug.go @@ -21,6 +21,7 @@ import ( "github.com/netbirdio/netbird/client/internal" "github.com/netbirdio/netbird/client/proto" uptypes "github.com/netbirdio/netbird/upload-server/types" + "github.com/netbirdio/netbird/version" ) // Initial state for the debug collection @@ -462,6 +463,7 @@ func (s *serviceClient) createDebugBundleFromCollection( request := &proto.DebugBundleRequest{ Anonymize: params.anonymize, SystemInfo: params.systemInfo, + CliVersion: version.NetbirdVersion(), } if params.upload { @@ -593,6 +595,7 @@ func (s *serviceClient) createDebugBundle(anonymize bool, systemInfo bool, uploa request := &proto.DebugBundleRequest{ Anonymize: anonymize, SystemInfo: systemInfo, + CliVersion: version.NetbirdVersion(), } if uploadURL != "" {