feat(machine id): Add helpers in ddcommon to fetch the machine UUID l…#2163
feat(machine id): Add helpers in ddcommon to fetch the machine UUID l…#2163paullegranddc wants to merge 4 commits into
Conversation
…ike the agent # Motivation We are replicating the agent RC client. One of the thing the agent uses is a stable identity for the agent host, decorrelated from the hostname (as it is not available in som platforms). It fetches the UUID using a library (psutils), for which there exists no strict equivalent in rust. This PR adds code that should be feature equal to the agent # Changes * Add new machine_id module in libdd-common * Fetch machine id on different platform
📚 Documentation Check Results📦
|
Clippy Allow Annotation ReportComparing clippy allow annotations between branches:
Summary by Rule
Annotation Counts by File
Annotation Stats by Crate
About This ReportThis report tracks Clippy allow annotations for specific rules, showing how they've changed in this PR. Decreasing the number of these annotations generally improves code quality. |
🔒 Cargo Deny Results📦
|
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: d1ddfc2 | Docs | Datadog PR Page | Give us feedback! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e17eaed888
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| &mut hkey, | ||
| ) | ||
| }; | ||
| if status != ERROR_SUCCESS as i32 { |
There was a problem hiding this comment.
Keep Windows status comparisons in u32
On Windows this module fails to type-check because windows-sys 0.52 defines RegOpenKeyExW/RegQueryValueExW as returning WIN32_ERROR (u32), but these checks compare that u32 to ERROR_SUCCESS as i32. Any Windows build of libdd-common that includes this new module will fail before use; compare against ERROR_SUCCESS without the cast here and in the two RegQueryValueExW status checks.
Useful? React with 👍 / 👎.
ekump
left a comment
There was a problem hiding this comment.
LGTM FWIW. I found the code confusing, so suggested some more comments.
| } | ||
|
|
||
| pub fn get_machine_id_impl() -> String { | ||
| let access = if cfg!(target_pointer_width = "32") && is_wow64() { |
There was a problem hiding this comment.
nit: Do you need is_wow64()? The agent always does KEY_READ_ | KEY_WOW64_64KEY Won't KEY_WOW64_64KEY be a no-op on 64-bit?
| @@ -0,0 +1,85 @@ | |||
| // Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ | |||
| // SPDX-License-Identifier: Apache-2.0 | |||
|
|
|||
There was a problem hiding this comment.
| //! Windows host machine id: reads `MachineGuid` from //! `HKLM\SOFTWARE\Microsoft\Cryptography` via the raw Win32 registry API. | |
| //! | |
| //! `MachineGuid` lives in the 64-bit registry view, so a 32-bit process under | |
| //! WOW64 must pass `KEY_WOW64_64KEY` or it gets redirected to the (empty) | |
| //! `WOW6432Node` copy. The value is read with the standard two-call Win32 | |
| //! pattern: query the byte size, then read into a right-sized buffer. |
| } | ||
|
|
||
| pub fn get_machine_id_impl() -> String { | ||
| let access = if cfg!(target_pointer_width = "32") && is_wow64() { |
There was a problem hiding this comment.
| let access = if cfg!(target_pointer_width = "32") && is_wow64() { | |
| // MachineGuid is in the 64-bit view; a 32-bit process under WOW64 is | |
| // redirected to WOW6432Node by default, so force the 64-bit view there. | |
| let access = if cfg!(target_pointer_width = "32") && is_wow64() { |
| return String::new(); | ||
| } | ||
|
|
||
| let mut buf: Vec<u16> = vec![0u16; (data_len as usize).div_ceil(2)]; |
There was a problem hiding this comment.
| let mut buf: Vec<u16> = vec![0u16; (data_len as usize).div_ceil(2)]; | |
| // data_len is bytes; REG_SZ holds UTF-16, so the u16 count is bytes/2 (round up). | |
| let mut buf: Vec<u16> = vec![0u16; (data_len as usize).div_ceil(2)]; |
|
|
||
| let mut data_type: u32 = 0; | ||
| let mut data_len: u32 = 0; | ||
| // SAFETY: null data pointer is valid for a size-query call. |
There was a problem hiding this comment.
| // SAFETY: null data pointer is valid for a size-query call. | |
| // SAFETY: null data pointer is valid for a size-query call. | |
| // First call (null data pointer) returns the value's size in bytes. |
| @@ -0,0 +1,39 @@ | |||
| // Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ | |||
| // SPDX-License-Identifier: Apache-2.0 | |||
|
|
|||
There was a problem hiding this comment.
| //! macOS host machine id via `gethostuuid(3)`, returning `IOPlatformUUID`. |
| /// Returns `IOPlatformUUID` via `gethostuuid(3)`, which avoids a fork+exec of `ioreg`. | ||
| pub fn get_machine_id_impl() -> String { | ||
| let mut uuid = [0u8; 16]; | ||
| let wait = libc::timespec { |
There was a problem hiding this comment.
| let wait = libc::timespec { | |
| // Zero timeout: the host UUID is static, so there's nothing to wait for. | |
| let wait = libc::timespec { |
| if rc != 0 { | ||
| return String::new(); | ||
| } | ||
| format!( |
There was a problem hiding this comment.
| format!( | |
| // Assemble the 16 raw bytes into the canonical 8-4-4-4-12 hyphenated UUID. | |
| format!( |
| @@ -0,0 +1,121 @@ | |||
| // Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/ | |||
| // SPDX-License-Identifier: Apache-2.0 | |||
|
|
|||
There was a problem hiding this comment.
| //! Linux host machine id, mirroring gopsutil's fallback order: | |
| //! `/sys/class/dmi/id/product_uuid` (root-only, usually empty otherwise) → | |
| //! `/etc/machine-id` → `/proc/sys/kernel/random/boot_id`. |
| } | ||
| } | ||
|
|
||
| pub fn get_machine_id_impl_paths(dmi_path: &Path, etc_path: &Path, boot_path: &Path) -> String { |
There was a problem hiding this comment.
| pub fn get_machine_id_impl_paths(dmi_path: &Path, etc_path: &Path, boot_path: &Path) -> String { | |
| /// Resolves the id from the three candidate paths in priority order. Paths are | |
| /// parameters so the fallback logic is unit-testable without real `/sys`/`/etc`. | |
| pub fn get_machine_id_impl_paths(dmi_path: &Path, etc_path: &Path, boot_path: &Path) -> String { |
ekump
left a comment
There was a problem hiding this comment.
LGTM FWIW. I found the code confusing, so suggested some more comments.
…ike the agent
Motivation
We are replicating the agent RC client. One of the thing the agent uses is a stable identity for the agent host, decorrelated from the hostname (as it is not available in som platforms).
It fetches the UUID using a library (psutils), for which there exists no strict equivalent in rust.
This PR adds code that should be feature equal to the agent
Changes
What does this PR do?
A brief description of the change being made with this pull request.
Motivation
What inspired you to submit this pull request?
Additional Notes
Anything else we should know when reviewing?
How to test the change?
Describe here in detail how the change can be validated.