From a4826cfb5fb5e0510f485644583bb14da1aa2ae8 Mon Sep 17 00:00:00 2001 From: Maycon Santos Date: Tue, 3 Dec 2024 10:22:04 +0100 Subject: [PATCH] [client] Get static system info once (#2965) Get static system info once for Windows, Darwin, and Linux nodes This should improve startup and peer authentication times --- client/system/info.go | 8 ++++ client/system/info_darwin.go | 20 +++++----- client/system/info_linux.go | 61 +++++++++++++---------------- client/system/info_windows.go | 53 +++++++++++++------------ client/system/static_info.go | 46 ++++++++++++++++++++++ client/system/sysinfo_linux_test.go | 5 ++- 6 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 client/system/static_info.go diff --git a/client/system/info.go b/client/system/info.go index 2af2e637b..200d835df 100644 --- a/client/system/info.go +++ b/client/system/info.go @@ -61,6 +61,14 @@ type Info struct { Files []File // for posture checks } +// StaticInfo is an object that contains machine information that does not change +type StaticInfo struct { + SystemSerialNumber string + SystemProductName string + SystemManufacturer string + Environment Environment +} + // extractUserAgent extracts Netbird's agent (client) name and version from the outgoing context func extractUserAgent(ctx context.Context) string { md, hasMeta := metadata.FromOutgoingContext(ctx) diff --git a/client/system/info_darwin.go b/client/system/info_darwin.go index 6f4ed173b..13b0a446b 100644 --- a/client/system/info_darwin.go +++ b/client/system/info_darwin.go @@ -10,13 +10,12 @@ import ( "os/exec" "runtime" "strings" + "time" "golang.org/x/sys/unix" log "github.com/sirupsen/logrus" - "github.com/netbirdio/netbird/client/system/detect_cloud" - "github.com/netbirdio/netbird/client/system/detect_platform" "github.com/netbirdio/netbird/version" ) @@ -41,11 +40,10 @@ func GetInfo(ctx context.Context) *Info { log.Warnf("failed to discover network addresses: %s", err) } - serialNum, prodName, manufacturer := sysInfo() - - env := Environment{ - Cloud: detect_cloud.Detect(ctx), - Platform: detect_platform.Detect(ctx), + start := time.Now() + si := updateStaticInfo() + if time.Since(start) > 1*time.Second { + log.Warnf("updateStaticInfo took %s", time.Since(start)) } gio := &Info{ @@ -57,10 +55,10 @@ func GetInfo(ctx context.Context) *Info { CPUs: runtime.NumCPU(), KernelVersion: release, NetworkAddresses: addrs, - SystemSerialNumber: serialNum, - SystemProductName: prodName, - SystemManufacturer: manufacturer, - Environment: env, + SystemSerialNumber: si.SystemSerialNumber, + SystemProductName: si.SystemProductName, + SystemManufacturer: si.SystemManufacturer, + Environment: si.Environment, } systemHostname, _ := os.Hostname() diff --git a/client/system/info_linux.go b/client/system/info_linux.go index b6a142bce..bfc77be19 100644 --- a/client/system/info_linux.go +++ b/client/system/info_linux.go @@ -1,5 +1,4 @@ //go:build !android -// +build !android package system @@ -16,30 +15,13 @@ import ( log "github.com/sirupsen/logrus" "github.com/zcalusic/sysinfo" - "github.com/netbirdio/netbird/client/system/detect_cloud" - "github.com/netbirdio/netbird/client/system/detect_platform" "github.com/netbirdio/netbird/version" ) -type SysInfoGetter interface { - GetSysInfo() SysInfo -} - -type SysInfoWrapper struct { - si sysinfo.SysInfo -} - -func (s SysInfoWrapper) GetSysInfo() SysInfo { - s.si.GetSysInfo() - return SysInfo{ - ChassisSerial: s.si.Chassis.Serial, - ProductSerial: s.si.Product.Serial, - BoardSerial: s.si.Board.Serial, - ProductName: s.si.Product.Name, - BoardName: s.si.Board.Name, - ProductVendor: s.si.Product.Vendor, - } -} +var ( + // it is override in tests + getSystemInfo = defaultSysInfoImplementation +) // GetInfo retrieves and parses the system information func GetInfo(ctx context.Context) *Info { @@ -65,12 +47,10 @@ func GetInfo(ctx context.Context) *Info { log.Warnf("failed to discover network addresses: %s", err) } - si := SysInfoWrapper{} - serialNum, prodName, manufacturer := sysInfo(si.GetSysInfo()) - - env := Environment{ - Cloud: detect_cloud.Detect(ctx), - Platform: detect_platform.Detect(ctx), + start := time.Now() + si := updateStaticInfo() + if time.Since(start) > 1*time.Second { + log.Warnf("updateStaticInfo took %s", time.Since(start)) } gio := &Info{ @@ -85,10 +65,10 @@ func GetInfo(ctx context.Context) *Info { UIVersion: extractUserAgent(ctx), KernelVersion: osInfo[1], NetworkAddresses: addrs, - SystemSerialNumber: serialNum, - SystemProductName: prodName, - SystemManufacturer: manufacturer, - Environment: env, + SystemSerialNumber: si.SystemSerialNumber, + SystemProductName: si.SystemProductName, + SystemManufacturer: si.SystemManufacturer, + Environment: si.Environment, } return gio @@ -108,9 +88,9 @@ func _getInfo() string { return out.String() } -func sysInfo(si SysInfo) (string, string, string) { +func sysInfo() (string, string, string) { isascii := regexp.MustCompile("^[[:ascii:]]+$") - + si := getSystemInfo() serials := []string{si.ChassisSerial, si.ProductSerial} serial := "" @@ -141,3 +121,16 @@ func sysInfo(si SysInfo) (string, string, string) { } return serial, name, manufacturer } + +func defaultSysInfoImplementation() SysInfo { + si := sysinfo.SysInfo{} + si.GetSysInfo() + return SysInfo{ + ChassisSerial: si.Chassis.Serial, + ProductSerial: si.Product.Serial, + BoardSerial: si.Board.Serial, + ProductName: si.Product.Name, + BoardName: si.Board.Name, + ProductVendor: si.Product.Vendor, + } +} diff --git a/client/system/info_windows.go b/client/system/info_windows.go index 68631fe16..28bd3d300 100644 --- a/client/system/info_windows.go +++ b/client/system/info_windows.go @@ -6,13 +6,12 @@ import ( "os" "runtime" "strings" + "time" log "github.com/sirupsen/logrus" "github.com/yusufpapurcu/wmi" "golang.org/x/sys/windows/registry" - "github.com/netbirdio/netbird/client/system/detect_cloud" - "github.com/netbirdio/netbird/client/system/detect_platform" "github.com/netbirdio/netbird/version" ) @@ -42,24 +41,10 @@ func GetInfo(ctx context.Context) *Info { log.Warnf("failed to discover network addresses: %s", err) } - serialNum, err := sysNumber() - if err != nil { - log.Warnf("failed to get system serial number: %s", err) - } - - prodName, err := sysProductName() - if err != nil { - log.Warnf("failed to get system product name: %s", err) - } - - manufacturer, err := sysManufacturer() - if err != nil { - log.Warnf("failed to get system manufacturer: %s", err) - } - - env := Environment{ - Cloud: detect_cloud.Detect(ctx), - Platform: detect_platform.Detect(ctx), + start := time.Now() + si := updateStaticInfo() + if time.Since(start) > 1*time.Second { + log.Warnf("updateStaticInfo took %s", time.Since(start)) } gio := &Info{ @@ -71,10 +56,10 @@ func GetInfo(ctx context.Context) *Info { CPUs: runtime.NumCPU(), KernelVersion: buildVersion, NetworkAddresses: addrs, - SystemSerialNumber: serialNum, - SystemProductName: prodName, - SystemManufacturer: manufacturer, - Environment: env, + SystemSerialNumber: si.SystemSerialNumber, + SystemProductName: si.SystemProductName, + SystemManufacturer: si.SystemManufacturer, + Environment: si.Environment, } systemHostname, _ := os.Hostname() @@ -85,6 +70,26 @@ func GetInfo(ctx context.Context) *Info { return gio } +func sysInfo() (serialNumber string, productName string, manufacturer string) { + var err error + serialNumber, err = sysNumber() + if err != nil { + log.Warnf("failed to get system serial number: %s", err) + } + + productName, err = sysProductName() + if err != nil { + log.Warnf("failed to get system product name: %s", err) + } + + manufacturer, err = sysManufacturer() + if err != nil { + log.Warnf("failed to get system manufacturer: %s", err) + } + + return serialNumber, productName, manufacturer +} + func getOSNameAndVersion() (string, string) { var dst []Win32_OperatingSystem query := wmi.CreateQuery(&dst, "") diff --git a/client/system/static_info.go b/client/system/static_info.go new file mode 100644 index 000000000..fabe65a68 --- /dev/null +++ b/client/system/static_info.go @@ -0,0 +1,46 @@ +//go:build (linux && !android) || windows || (darwin && !ios) + +package system + +import ( + "context" + "sync" + "time" + + "github.com/netbirdio/netbird/client/system/detect_cloud" + "github.com/netbirdio/netbird/client/system/detect_platform" +) + +var ( + staticInfo StaticInfo + once sync.Once +) + +func init() { + go func() { + _ = updateStaticInfo() + }() +} + +func updateStaticInfo() StaticInfo { + once.Do(func() { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + wg := sync.WaitGroup{} + wg.Add(3) + go func() { + staticInfo.SystemSerialNumber, staticInfo.SystemProductName, staticInfo.SystemManufacturer = sysInfo() + wg.Done() + }() + go func() { + staticInfo.Environment.Cloud = detect_cloud.Detect(ctx) + wg.Done() + }() + go func() { + staticInfo.Environment.Platform = detect_platform.Detect(ctx) + wg.Done() + }() + wg.Wait() + }) + return staticInfo +} diff --git a/client/system/sysinfo_linux_test.go b/client/system/sysinfo_linux_test.go index f6a0b7058..ae89bfcf9 100644 --- a/client/system/sysinfo_linux_test.go +++ b/client/system/sysinfo_linux_test.go @@ -183,7 +183,10 @@ func Test_sysInfo(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotSerialNum, gotProdName, gotManufacturer := sysInfo(tt.sysInfo) + getSystemInfo = func() SysInfo { + return tt.sysInfo + } + gotSerialNum, gotProdName, gotManufacturer := sysInfo() if gotSerialNum != tt.wantSerialNum { t.Errorf("sysInfo() gotSerialNum = %v, want %v", gotSerialNum, tt.wantSerialNum) }