-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[EUDM] Collect Mac system information #44301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
gh-worker-dd-mergequeue-cf854d
merged 21 commits into
main
from
brian.tu/host-hardware-mac
Jan 21, 2026
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
05eb48d
adding host hardware metadata component
mrafi97 13cb6c1
adding more data and unit tests
mrafi97 76e2dac
editing error handling
mrafi97 dd507fe
using host_system_info instead of host_hardware
mrafi97 c6392b1
updating codeowners
mrafi97 c9efbc3
fixing some typos
mrafi97 938f592
adding readme
mrafi97 b9a1c50
fixing test and linter errors
mrafi97 c6cee81
adding changelog
mrafi97 7233a28
editing readme
mrafi97 abc4b6d
Apply suggestions from code review
mrafi97 f11f1ef
Merge branch 'main' into mrafi/host-hardware
mrafi97 14f03c0
Collect host hardware info on mac
briantu 73e4595
Add fallback
briantu b6e175d
Update mac implementation
briantu bf805b8
Update README + add release note
briantu 88a01af
Handle string conversion
briantu eace550
Use kIOMasterPortDefault for older versions
briantu 7bbbc2f
Merge branch 'main' into brian.tu/host-hardware-mac
briantu 8a645f0
Missed rebase changes
briantu be0fa7e
Add comments
briantu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| // Unless explicitly stated otherwise all files in this repository are licensed | ||
| // under the Apache License Version 2.0. | ||
| // This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
| // Copyright 2016-present Datadog, Inc. | ||
|
|
||
| //go:build darwin | ||
|
|
||
| package systeminfo | ||
|
|
||
| /* | ||
| #cgo CFLAGS: -x objective-c -fobjc-arc | ||
| #cgo LDFLAGS: -framework Foundation -framework IOKit | ||
| #include <stdlib.h> | ||
| #include "systeminfo_darwin.h" | ||
| */ | ||
| import "C" | ||
| import ( | ||
| "strings" | ||
| "unsafe" | ||
| ) | ||
|
|
||
| func collect() (*SystemInfo, error) { | ||
| cInfo := C.getDeviceInfo() | ||
| defer C.free(unsafe.Pointer(cInfo.modelIdentifier)) | ||
| defer C.free(unsafe.Pointer(cInfo.modelNumber)) | ||
| defer C.free(unsafe.Pointer(cInfo.productName)) | ||
| defer C.free(unsafe.Pointer(cInfo.serialNumber)) | ||
|
|
||
| return &SystemInfo{ | ||
| Manufacturer: "Apple Inc.", | ||
| ModelNumber: C.GoString(cInfo.modelNumber), | ||
| SerialNumber: C.GoString(cInfo.serialNumber), | ||
| ModelName: C.GoString(cInfo.productName), | ||
| ChassisType: getChassisType(C.GoString(cInfo.productName), C.GoString(cInfo.modelIdentifier)), | ||
| Identifier: C.GoString(cInfo.modelIdentifier), | ||
iglendd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, nil | ||
| } | ||
|
|
||
| func getChassisType(productName string, modelIdentifier string) string { | ||
| lowerName := strings.ToLower(productName) | ||
| lowerModel := strings.ToLower(modelIdentifier) | ||
|
|
||
| // Check for virtual machines first | ||
| // VMware VMs have modelIdentifier like "VMware7,1" | ||
| // Apple Silicon VMs have modelIdentifier like "VirtualMac2,1" and productName "Apple Virtual Machine 1" | ||
| // Parallels VMs have "Parallels" in the modelIdentifier | ||
| if strings.Contains(lowerModel, "vmware") || | ||
| strings.Contains(lowerModel, "virtual") || | ||
| strings.Contains(lowerModel, "parallels") || | ||
| strings.Contains(lowerName, "virtual") { | ||
iglendd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return "Virtual Machine" | ||
| } | ||
|
|
||
| if strings.HasPrefix(lowerName, "macbook") { | ||
| return "Laptop" | ||
| } | ||
|
|
||
| if strings.HasPrefix(lowerName, "imac") || | ||
| strings.HasPrefix(lowerName, "mac mini") || | ||
| strings.HasPrefix(lowerName, "mac pro") || | ||
| strings.HasPrefix(lowerName, "mac studio") { | ||
| return "Desktop" | ||
| } | ||
|
|
||
| return "Other" | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| // Unless explicitly stated otherwise all files in this repository are licensed | ||
| // under the Apache License Version 2.0. | ||
| // This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
| // Copyright 2016-present Datadog, Inc. | ||
|
|
||
| //go:build darwin | ||
|
|
||
| package systeminfo | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestCollect(t *testing.T) { | ||
| info, err := Collect() | ||
| require.NoError(t, err, "Collect should not return an error") | ||
| require.NotNil(t, info, "Collect should return system info") | ||
|
|
||
| // On Darwin, manufacturer should always be Apple Inc. | ||
| assert.Equal(t, "Apple Inc.", info.Manufacturer, "Manufacturer should be Apple Inc.") | ||
|
|
||
| // Verify that required fields are populated | ||
| // Note: We don't test exact values as they depend on the test machine | ||
| t.Logf("Collected System Info:") | ||
| t.Logf(" Manufacturer: %s", info.Manufacturer) | ||
| t.Logf(" ModelNumber: %s", info.ModelNumber) | ||
| t.Logf(" SerialNumber: %s", info.SerialNumber) | ||
| t.Logf(" ModelName: %s", info.ModelName) | ||
| t.Logf(" ChassisType: %s", info.ChassisType) | ||
| t.Logf(" Identifier: %s", info.Identifier) | ||
|
|
||
| // Chassis type should be one of the expected values | ||
| validChassisTypes := []string{"Laptop", "Desktop", "Virtual Machine", "Other"} | ||
| assert.Contains(t, validChassisTypes, info.ChassisType, "ChassisType should be a valid type") | ||
| } | ||
|
|
||
| func TestGetChassisType(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| productName string | ||
| modelIdentifier string | ||
| expected string | ||
| }{ | ||
| { | ||
| name: "MacBook Pro", | ||
| productName: "MacBook Pro", | ||
| modelIdentifier: "MacBookPro18,1", | ||
| expected: "Laptop", | ||
| }, | ||
| { | ||
| name: "MacBook Air", | ||
| productName: "MacBook Air", | ||
| modelIdentifier: "MacBookAir10,1", | ||
| expected: "Laptop", | ||
| }, | ||
| { | ||
| name: "MacBook (generic)", | ||
| productName: "MacBook", | ||
| modelIdentifier: "MacBook10,1", | ||
| expected: "Laptop", | ||
| }, | ||
| { | ||
| name: "iMac", | ||
| productName: "iMac", | ||
| modelIdentifier: "iMac21,1", | ||
| expected: "Desktop", | ||
| }, | ||
| { | ||
| name: "Mac mini", | ||
| productName: "Mac mini", | ||
| modelIdentifier: "Macmini9,1", | ||
| expected: "Desktop", | ||
| }, | ||
| { | ||
| name: "Mac Pro", | ||
| productName: "Mac Pro", | ||
| modelIdentifier: "MacPro7,1", | ||
| expected: "Desktop", | ||
| }, | ||
| { | ||
| name: "Mac Studio", | ||
| productName: "Mac Studio", | ||
| modelIdentifier: "Mac13,1", | ||
| expected: "Desktop", | ||
| }, | ||
| { | ||
| name: "VMware VM", | ||
| productName: "VMware Virtual Platform", | ||
| modelIdentifier: "VMware7,1", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "VMware VM (mixed case)", | ||
| productName: "VMware Virtual Platform", | ||
| modelIdentifier: "vmware7,1", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "Apple Virtual Machine", | ||
| productName: "Apple Virtual Machine 1", | ||
| modelIdentifier: "VirtualMac2,1", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "Virtual in model identifier", | ||
| productName: "Some Mac", | ||
| modelIdentifier: "VirtualMac2,1", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "Virtual in product name", | ||
| productName: "Virtual Device", | ||
| modelIdentifier: "Mac1,1", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "Parallels VM", | ||
| productName: "Parallels Virtual Platform", | ||
| modelIdentifier: "Parallels-ARM", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "Parallels in identifier (mixed case)", | ||
| productName: "Some Device", | ||
| modelIdentifier: "parallels-x86", | ||
| expected: "Virtual Machine", | ||
| }, | ||
| { | ||
| name: "Unknown Apple device", | ||
| productName: "Apple Device", | ||
| modelIdentifier: "Unknown1,1", | ||
| expected: "Other", | ||
| }, | ||
| { | ||
| name: "Empty strings", | ||
| productName: "", | ||
| modelIdentifier: "", | ||
| expected: "Other", | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| result := getChassisType(tt.productName, tt.modelIdentifier) | ||
| assert.Equal(t, tt.expected, result, "getChassisType(%q, %q) = %q, want %q", | ||
| tt.productName, tt.modelIdentifier, result, tt.expected) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestGetChassisType_CaseInsensitive(t *testing.T) { | ||
| // Test that the function handles different cases correctly | ||
| testCases := []struct { | ||
| name string | ||
| productName string | ||
| modelIdentifier string | ||
| expected string | ||
| }{ | ||
| {"Uppercase MacBook", "MACBOOK PRO", "MacBookPro18,1", "Laptop"}, | ||
| {"Lowercase macbook", "macbook pro", "MacBookPro18,1", "Laptop"}, | ||
| {"Mixed case macBook", "macBook Pro", "MacBookPro18,1", "Laptop"}, | ||
| {"Uppercase iMac", "IMAC", "iMac21,1", "Desktop"}, | ||
| {"Lowercase imac", "imac", "iMac21,1", "Desktop"}, | ||
| {"Uppercase VM identifier", "Some Device", "VMWARE7,1", "Virtual Machine"}, | ||
| {"Lowercase vm identifier", "Some Device", "vmware7,1", "Virtual Machine"}, | ||
| } | ||
|
|
||
| for _, tt := range testCases { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| result := getChassisType(tt.productName, tt.modelIdentifier) | ||
| assert.Equal(t, tt.expected, result) | ||
| }) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #ifndef SYSTEMINFO_DARWIN_H | ||
| #define SYSTEMINFO_DARWIN_H | ||
|
|
||
| #include <stdbool.h> | ||
|
|
||
| typedef struct { | ||
| char *modelNumber; | ||
| char *serialNumber; | ||
| char *productName; | ||
| char *modelIdentifier; | ||
| } DeviceInfo; | ||
|
|
||
| DeviceInfo getDeviceInfo(void); | ||
|
|
||
| #endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.