-
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 16 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
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,90 @@ | ||
| # Host System Info Payload | ||
|
|
||
| This package populates the host system information fields in the `End User Device Monitoring` product in Datadog. | ||
|
|
||
| This is enabled only for the `end_user_device` infrastructure mode. | ||
|
|
||
| The payload is sent every 1 hour (see `inventories_max_interval` in the config) or whenever it's updated with at most 1 update every 1 hour (see `inventories_min_interval`). | ||
|
|
||
| # Content | ||
|
|
||
| The payload contains physical system identification attributes collected from the host system, including manufacturer details, model information, serial numbers, and chassis type. This information is useful for asset management, hardware inventory tracking, and fleet management in end-user device monitoring scenarios. | ||
|
|
||
| ## System Information Collection | ||
|
|
||
| The system information is collected using platform-specific APIs: | ||
| - **Windows**: WMI queries (`Win32_ComputerSystem`, `Win32_BIOS`, `Win32_SystemEnclosure`) | ||
| - **MacOS**: IOKit queries (`IOPlatformExpertDevice`, `product`) | ||
| - **Linux/Unix**: Will not run as it is currently not implemented | ||
|
|
||
| Collection includes: | ||
| - Manufacturer name (for example, Dell, Lenovo, HP, Amazon EC2) | ||
| - Model number and name | ||
| - Serial number | ||
| - System SKU/Identifier | ||
| - Chassis type (Desktop, Laptop, Virtual Machine, Other) | ||
|
|
||
| ## Configuration | ||
|
|
||
| System info metadata collection can be controlled using: | ||
| - `infrastructure_mode: end_user_device` - Required to enable this feature | ||
|
|
||
| # Format | ||
|
|
||
| The payload is a JSON dict with the following fields: | ||
|
|
||
| - `hostname` - **string**: the hostname of the agent as shown on the status page. | ||
| - `uuid` - **string**: a unique identifier of the agent, used in case the hostname is empty. | ||
| - `timestamp` - **int**: the timestamp when the payload was created (Unix nanoseconds). | ||
| - `host_system_info` - **dict of string to JSON type**: | ||
| - `manufacturer` - **string**: The company brand name under which the device is marketed. | ||
| - `model_number` - **string**: Company's specific model number of device. | ||
| - `serial_number` - **string**: The serial number assigned from the company and is accessible on the exterior of the device. | ||
| - `model_name` - **string**: The model name of the current device. | ||
| - `chassis_type` - **string**: The chassis type of the current device. One of: "Desktop", "Laptop", "Virtual Machine", or "Other". | ||
| - `identifier` - **string**: the system SKU number or other unique identifier. | ||
|
|
||
| ## Virtual Machine Detection | ||
|
|
||
| The payload includes special logic to detect virtual machines: | ||
| - Hyper-V and Azure VMs are detected via the model name "Virtual Machine" | ||
| - AWS EC2 instances are detected via the manufacturer "Amazon EC2" | ||
| - When detected, the `chassis_type` is set to "Virtual Machine" | ||
|
|
||
| ## Example Payload | ||
|
|
||
| Here is an example of a host system info payload for a physical laptop: | ||
|
|
||
| ```json | ||
| { | ||
| "hostname": "LAPTOP-123456", | ||
| "timestamp": 1767996703894578400, | ||
| "host_system_info_metadata": { | ||
| "manufacturer": "LENOVO", | ||
| "model_number": "ABC123", | ||
| "serial_number": "DEF456", | ||
| "model_name": "ThinkPad T14s Gen 5", | ||
| "chassis_type": "Laptop", | ||
| "identifier": "LENOVO_MT_21LS_BU_Think_FM_ThinkPad T14s Gen 5" | ||
| }, | ||
| "uuid": "1234-5678-abcd-efgh" | ||
| } | ||
| ``` | ||
|
|
||
| Here is an example for a virtual machine: | ||
|
|
||
| ```json | ||
| { | ||
| "hostname": "WIN-VM", | ||
| "timestamp": 1767998956607294100, | ||
| "host_system_info_metadata": { | ||
| "manufacturer": "Microsoft Corporation", | ||
| "model_number": "Virtual Machine", | ||
| "serial_number": "XYZ789", | ||
| "model_name": "Virtual Machine", | ||
| "chassis_type": "Virtual Machine", | ||
| "identifier": "None" | ||
| }, | ||
| "uuid": "abcd-1234-efgh-5678" | ||
| } | ||
| ``` |
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,13 @@ | ||
| // 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. | ||
|
|
||
| // Package hostsysteminfo exposes the interface for the component to generate the 'host_system_info' metadata payload for inventory. | ||
| package hostsysteminfo | ||
|
|
||
| // team: windows-products | ||
|
|
||
| // Component is the component type. | ||
| type Component interface { | ||
| } |
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,18 @@ | ||
| // 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 2024-present Datadog, Inc. | ||
|
|
||
| // Package fx provides the fx module for the host system info metadata component | ||
| package fx | ||
|
|
||
| import ( | ||
| hostsysteminfoimpl "github.com/DataDog/datadog-agent/comp/metadata/hostsysteminfo/impl" | ||
| "github.com/DataDog/datadog-agent/pkg/util/fxutil" | ||
| ) | ||
|
|
||
| // Module defines the fx options for this component. | ||
| func Module() fxutil.Module { | ||
| return fxutil.Component( | ||
| fxutil.ProvideComponentConstructor(hostsysteminfoimpl.NewSystemInfoProvider)) | ||
| } |
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,175 @@ | ||
| // 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. | ||
|
|
||
| // Package hostsysteminfoimpl implements a component to generate the 'host_system_info' metadata payload for inventory. | ||
| package hostsysteminfoimpl | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "net/http" | ||
| "runtime" | ||
| "time" | ||
|
|
||
| api "github.com/DataDog/datadog-agent/comp/api/api/def" | ||
| "github.com/DataDog/datadog-agent/comp/core/config" | ||
| flaretypes "github.com/DataDog/datadog-agent/comp/core/flare/types" | ||
| "github.com/DataDog/datadog-agent/comp/core/hostname/hostnameinterface" | ||
| ipc "github.com/DataDog/datadog-agent/comp/core/ipc/def" | ||
| log "github.com/DataDog/datadog-agent/comp/core/log/def" | ||
| hostsysteminfo "github.com/DataDog/datadog-agent/comp/metadata/hostsysteminfo/def" | ||
| "github.com/DataDog/datadog-agent/comp/metadata/internal/util" | ||
| "github.com/DataDog/datadog-agent/comp/metadata/runner/runnerimpl" | ||
| "github.com/DataDog/datadog-agent/pkg/inventory/systeminfo" | ||
| "github.com/DataDog/datadog-agent/pkg/serializer" | ||
| "github.com/DataDog/datadog-agent/pkg/serializer/marshaler" | ||
| httputils "github.com/DataDog/datadog-agent/pkg/util/http" | ||
| "github.com/DataDog/datadog-agent/pkg/util/uuid" | ||
| ) | ||
|
|
||
| const flareFileName = "hostsysteminfo.json" | ||
|
|
||
| type hostSystemInfoMetadata struct { | ||
| Manufacturer string `json:"manufacturer"` | ||
| ModelNumber string `json:"model_number"` | ||
| SerialNumber string `json:"serial_number"` | ||
| ModelName string `json:"model_name"` | ||
| ChassisType string `json:"chassis_type"` | ||
| Identifier string `json:"identifier"` | ||
| } | ||
|
|
||
| type hostSystemInfo struct { | ||
| util.InventoryPayload | ||
|
|
||
| log log.Component | ||
| conf config.Component | ||
| hostname string | ||
| data *hostSystemInfoMetadata | ||
| } | ||
|
|
||
| type Payload struct { | ||
| Hostname string `json:"hostname"` | ||
| Timestamp int64 `json:"timestamp"` | ||
| Metadata *hostSystemInfoMetadata `json:"host_system_info_metadata"` | ||
| UUID string `json:"uuid"` | ||
| } | ||
|
|
||
| func (p *Payload) MarshalJSON() ([]byte, error) { | ||
| type PayloadAlias Payload | ||
| return json.Marshal((*PayloadAlias)(p)) | ||
| } | ||
|
|
||
| type Requires struct { | ||
| Log log.Component | ||
| Config config.Component | ||
| Serializer serializer.MetricSerializer | ||
| Hostname hostnameinterface.Component | ||
| IPCClient ipc.HTTPClient | ||
| } | ||
|
|
||
| type Provides struct { | ||
| Comp hostsysteminfo.Component | ||
| Provider runnerimpl.Provider | ||
| FlareProvider flaretypes.Provider | ||
| Endpoint api.AgentEndpointProvider | ||
| } | ||
|
|
||
| func NewSystemInfoProvider(deps Requires) Provides { | ||
| hname, _ := deps.Hostname.Get(context.Background()) | ||
| hh := &hostSystemInfo{ | ||
| log: deps.Log, | ||
| conf: deps.Config, | ||
| hostname: hname, | ||
| data: &hostSystemInfoMetadata{}, | ||
| } | ||
| hh.InventoryPayload = util.CreateInventoryPayload(deps.Config, deps.Log, deps.Serializer, hh.getPayload, flareFileName) | ||
|
|
||
| // Override default intervals for system info metadata | ||
| // System info changes infrequently, so check less often | ||
| hh.InventoryPayload.MinInterval = 1 * time.Hour | ||
| hh.InventoryPayload.MaxInterval = 1 * time.Hour | ||
|
|
||
| // Only enable system info metadata collection for end user device infrastructure mode on Windows and Darwin | ||
| infraMode := deps.Config.GetString("infrastructure_mode") | ||
| isEndUserDevice := infraMode == "end_user_device" | ||
| isSupportedOS := runtime.GOOS == "windows" || runtime.GOOS == "darwin" | ||
| hh.InventoryPayload.Enabled = hh.InventoryPayload.Enabled && isEndUserDevice && isSupportedOS | ||
|
|
||
| var provider runnerimpl.Provider | ||
| if hh.InventoryPayload.Enabled { | ||
| provider = hh.MetadataProvider() | ||
| deps.Log.Info("System info metadata collection enabled for end user device mode") | ||
| } else { | ||
| if !isSupportedOS { | ||
| deps.Log.Debugf("System info metadata collection disabled: only supported on Windows and macOS (current OS: %s)", runtime.GOOS) | ||
| } else { | ||
| deps.Log.Debugf("System info metadata collection disabled: infrastructure_mode is '%s' (requires 'end_user_device')", infraMode) | ||
| } | ||
| } | ||
|
|
||
| return Provides{ | ||
| Comp: hh, | ||
| Provider: provider, | ||
| FlareProvider: hh.FlareProvider(), | ||
| Endpoint: api.NewAgentEndpointProvider(hh.writePayloadAsJSON, "/metadata/host-system-info", "GET"), | ||
| } | ||
| } | ||
|
|
||
| func (hh *hostSystemInfo) fillData() error { | ||
| // System info collection is only supported on Windows and Darwin | ||
| if runtime.GOOS != "windows" && runtime.GOOS != "darwin" { | ||
| hh.log.Debugf("System information collection not supported on %s", runtime.GOOS) | ||
| hh.data = &hostSystemInfoMetadata{} | ||
| return nil | ||
| } | ||
|
|
||
| sysInfo, err := systeminfo.Collect() | ||
| if err != nil { | ||
| hh.log.Errorf("Failed to collect system information: %v", err) | ||
| hh.data = &hostSystemInfoMetadata{} | ||
| return err | ||
| } | ||
|
|
||
| // Handle case where collection returns nil data | ||
| if sysInfo == nil { | ||
| hh.log.Debug("System information collection returned no data") | ||
| hh.data = &hostSystemInfoMetadata{} | ||
| return nil | ||
| } | ||
|
|
||
| hh.data.Manufacturer = sysInfo.Manufacturer | ||
| hh.data.ModelNumber = sysInfo.ModelNumber | ||
| hh.data.SerialNumber = sysInfo.SerialNumber | ||
| hh.data.ModelName = sysInfo.ModelName | ||
| hh.data.ChassisType = sysInfo.ChassisType | ||
| hh.data.Identifier = sysInfo.Identifier | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (hh *hostSystemInfo) writePayloadAsJSON(w http.ResponseWriter, _ *http.Request) { | ||
| // GetAsJSON calls getPayload which already scrub the data | ||
| scrubbed, err := hh.GetAsJSON() | ||
| if err != nil { | ||
| httputils.SetJSONError(w, err, 500) | ||
| return | ||
| } | ||
| w.Write(scrubbed) | ||
| } | ||
|
|
||
| func (hh *hostSystemInfo) getPayload() marshaler.JSONMarshaler { | ||
| // Try to collect system info data | ||
| if err := hh.fillData(); err != nil { | ||
| hh.log.Debugf("Skipping system info metadata payload due to collection failure: %v", err) | ||
| return nil | ||
| } | ||
|
|
||
| return &Payload{ | ||
| Hostname: hh.hostname, | ||
| Timestamp: time.Now().UnixNano(), | ||
| Metadata: hh.data, | ||
| UUID: uuid.GetUUID(), | ||
| } | ||
| } | ||
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.