Ingest ReleaseId from Windows registry (#8030)
This commit is contained in:
@@ -174,19 +174,55 @@ var hostDetailQueries = map[string]DetailQuery{
|
||||
},
|
||||
"os_version_windows": {
|
||||
// Windows-specific registry query is required to populate `host.OSVersion` for Windows.
|
||||
Query: `SELECT
|
||||
os.name,
|
||||
r.data
|
||||
Query: `
|
||||
WITH dv AS (
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
registry
|
||||
WHERE
|
||||
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion'
|
||||
),
|
||||
rid AS (
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
registry
|
||||
WHERE
|
||||
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ReleaseId'
|
||||
)
|
||||
SELECT
|
||||
(
|
||||
SELECT
|
||||
name
|
||||
FROM
|
||||
os_version os,
|
||||
(
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
registry
|
||||
WHERE
|
||||
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion') r
|
||||
LIMIT 1`,
|
||||
os_version) AS name,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
dv) THEN
|
||||
(
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
dv)
|
||||
ELSE
|
||||
""
|
||||
END AS display_version,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
rid) THEN
|
||||
(
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
rid)
|
||||
ELSE
|
||||
""
|
||||
END AS release_id`,
|
||||
Platforms: []string{"windows"},
|
||||
IngestFunc: func(ctx context.Context, logger log.Logger, host *fleet.Host, rows []map[string]string) error {
|
||||
if len(rows) != 1 {
|
||||
@@ -195,7 +231,25 @@ var hostDetailQueries = map[string]DetailQuery{
|
||||
return nil
|
||||
}
|
||||
|
||||
s := fmt.Sprintf("%v %v", rows[0]["name"], rows[0]["data"])
|
||||
var version string
|
||||
switch {
|
||||
case rows[0]["display_version"] != "":
|
||||
// prefer display version if available
|
||||
version = rows[0]["display_version"]
|
||||
case rows[0]["release_id"] != "":
|
||||
// otherwise release_id if available
|
||||
version = rows[0]["release_id"]
|
||||
default:
|
||||
// empty value
|
||||
}
|
||||
if version == "" {
|
||||
level.Debug(logger).Log(
|
||||
"msg", "unable to identify windows version",
|
||||
"host", host.Hostname,
|
||||
)
|
||||
}
|
||||
|
||||
s := fmt.Sprintf("%v %v", rows[0]["name"], version)
|
||||
// Shorten "Microsoft Windows" to "Windows" to facilitate display and sorting in UI
|
||||
s = strings.Replace(s, "Microsoft Windows", "Windows", 1)
|
||||
host.OSVersion = s
|
||||
@@ -390,23 +444,56 @@ var extraDetailQueries = map[string]DetailQuery{
|
||||
// tables. Separately, the `hosts` table is populated via the `os_version` and
|
||||
// `os_version_windows` detail queries above.
|
||||
Query: `
|
||||
WITH dv AS (
|
||||
SELECT
|
||||
os.name,
|
||||
os.arch,
|
||||
os.platform,
|
||||
r.version AS version,
|
||||
k.version AS kernel_version
|
||||
data
|
||||
FROM
|
||||
os_version os,
|
||||
kernel_info k,
|
||||
registry
|
||||
WHERE
|
||||
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion'
|
||||
),
|
||||
rid AS (
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
registry
|
||||
WHERE
|
||||
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ReleaseId'
|
||||
)
|
||||
SELECT
|
||||
os.name,
|
||||
os.platform,
|
||||
os.arch,
|
||||
k.version as kernel_version,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
dv) THEN
|
||||
(
|
||||
SELECT
|
||||
data AS version
|
||||
data
|
||||
FROM
|
||||
registry
|
||||
WHERE
|
||||
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion') r`,
|
||||
Platforms: []string{"windows"},
|
||||
dv)
|
||||
ELSE
|
||||
""
|
||||
END AS display_version,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
rid) THEN
|
||||
(
|
||||
SELECT
|
||||
data
|
||||
FROM
|
||||
rid)
|
||||
ELSE
|
||||
""
|
||||
END AS release_id
|
||||
FROM
|
||||
os_version os,
|
||||
kernel_info k`,
|
||||
DirectIngestFunc: directIngestOSWindows,
|
||||
},
|
||||
"os_unix_like": {
|
||||
@@ -715,12 +802,30 @@ func directIngestOSWindows(ctx context.Context, logger log.Logger, host *fleet.H
|
||||
|
||||
hostOS := fleet.OperatingSystem{
|
||||
Name: rows[0]["name"],
|
||||
Version: rows[0]["version"],
|
||||
Arch: rows[0]["arch"],
|
||||
KernelVersion: rows[0]["kernel_version"],
|
||||
Platform: rows[0]["platform"],
|
||||
}
|
||||
|
||||
var version string
|
||||
switch {
|
||||
case rows[0]["display_version"] != "":
|
||||
// prefer display version if available
|
||||
version = rows[0]["display_version"]
|
||||
case rows[0]["release_id"] != "":
|
||||
// otherwise release_id if available
|
||||
version = rows[0]["release_id"]
|
||||
default:
|
||||
// empty value
|
||||
}
|
||||
if version == "" {
|
||||
level.Debug(logger).Log(
|
||||
"msg", "unable to identify windows version",
|
||||
"host", host.Hostname,
|
||||
)
|
||||
}
|
||||
hostOS.Version = version
|
||||
|
||||
if err := ds.UpdateHostOperatingSystem(ctx, host.ID, hostOS); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "directIngestOSWindows update host operating system")
|
||||
}
|
||||
|
||||
@@ -431,13 +431,36 @@ func TestDetailQueriesOSVersionWindows(t *testing.T) {
|
||||
"platform": "windows",
|
||||
"platform_like": "windows",
|
||||
"version": "10.0.22000",
|
||||
"data": "21H2"
|
||||
"display_version": "21H2",
|
||||
"release_id": ""
|
||||
}]`),
|
||||
&rows,
|
||||
))
|
||||
|
||||
assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, rows))
|
||||
assert.Equal(t, "Windows 11 Enterprise 21H2", host.OSVersion)
|
||||
|
||||
require.NoError(t, json.Unmarshal([]byte(`
|
||||
[{
|
||||
"hostname": "WinBox",
|
||||
"arch": "64-bit",
|
||||
"build": "17763",
|
||||
"codename": "Microsoft Windows 10 Enterprise LTSC",
|
||||
"major": "10",
|
||||
"minor": "0",
|
||||
"name": "Microsoft Windows 10 Enterprise LTSC",
|
||||
"patch": "",
|
||||
"platform": "windows",
|
||||
"platform_like": "windows",
|
||||
"version": "10.0.17763",
|
||||
"display_version": "",
|
||||
"release_id": "1809"
|
||||
}]`),
|
||||
&rows,
|
||||
))
|
||||
|
||||
assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, rows))
|
||||
assert.Equal(t, "Windows 10 Enterprise LTSC 1809", host.OSVersion)
|
||||
}
|
||||
|
||||
func TestDirectIngestMDM(t *testing.T) {
|
||||
@@ -536,28 +559,49 @@ func TestDirectIngestBattery(t *testing.T) {
|
||||
func TestDirectIngestOSWindows(t *testing.T) {
|
||||
ds := new(mock.Store)
|
||||
|
||||
testHost := fleet.Host{
|
||||
ID: 1,
|
||||
}
|
||||
testOS := fleet.OperatingSystem{
|
||||
Name: "Microsoft Windows 11 Enterprise",
|
||||
Version: "21H2",
|
||||
Arch: "64-bit",
|
||||
KernelVersion: "10.0.22000.795",
|
||||
testCases := []struct {
|
||||
expected fleet.OperatingSystem
|
||||
data []map[string]string
|
||||
}{
|
||||
{
|
||||
expected: fleet.OperatingSystem{
|
||||
Name: "Microsoft Windows 11 Enterprise",
|
||||
Version: "21H2",
|
||||
Arch: "64-bit",
|
||||
KernelVersion: "10.0.22000.795",
|
||||
},
|
||||
data: []map[string]string{
|
||||
{"name": "Microsoft Windows 11 Enterprise", "display_version": "21H2", "release_id": "", "arch": "64-bit", "kernel_version": "10.0.22000.795"},
|
||||
},
|
||||
},
|
||||
{
|
||||
expected: fleet.OperatingSystem{
|
||||
Name: "Microsoft Windows 10 Enterprise LTSC",
|
||||
Version: "1809",
|
||||
Arch: "64-bit",
|
||||
KernelVersion: "10.0.17763",
|
||||
},
|
||||
data: []map[string]string{
|
||||
{"name": "Microsoft Windows 10 Enterprise LTSC", "display_version": "", "release_id": "1809", "arch": "64-bit", "kernel_version": "10.0.17763"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ds.UpdateHostOperatingSystemFunc = func(ctx context.Context, hostID uint, hostOS fleet.OperatingSystem) error {
|
||||
require.Equal(t, testHost.ID, hostID)
|
||||
require.Equal(t, testOS, hostOS)
|
||||
return nil
|
||||
host := fleet.Host{ID: 1}
|
||||
|
||||
for _, tt := range testCases {
|
||||
ds.UpdateHostOperatingSystemFunc = func(ctx context.Context, hostID uint, hostOS fleet.OperatingSystem) error {
|
||||
require.Equal(t, host.ID, hostID)
|
||||
require.Equal(t, tt.expected, hostOS)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := directIngestOSWindows(context.Background(), log.NewNopLogger(), &host, ds, tt.data, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.True(t, ds.UpdateHostOperatingSystemFuncInvoked)
|
||||
ds.UpdateHostOperatingSystemFuncInvoked = false
|
||||
}
|
||||
|
||||
err := directIngestOSWindows(context.Background(), log.NewNopLogger(), &testHost, ds, []map[string]string{
|
||||
{"name": "Microsoft Windows 11 Enterprise", "version": "21H2", "arch": "64-bit", "kernel_version": "10.0.22000.795"},
|
||||
}, false)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.True(t, ds.UpdateHostOperatingSystemFuncInvoked)
|
||||
}
|
||||
|
||||
func TestDirectIngestOSUnixLike(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user