account for commands being dequeued in list query (#37505)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #36748 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Updated query behind `fleetctl get mdm-commands` to correctly get completed Windows MDM commands.
|
||||
@@ -246,12 +246,31 @@ WHERE
|
||||
if len(winUUIDs) > 0 {
|
||||
winParams = []any{winUUIDs}
|
||||
winStmt = `
|
||||
SELECT
|
||||
mwe.host_uuid,
|
||||
wq.command_uuid,
|
||||
COALESCE(wcr.updated_at, wc.created_at) AS updated_at,
|
||||
COALESCE(NULLIF(wcr.status_code, ''), '101') AS status,
|
||||
CASE
|
||||
SELECT
|
||||
mwe.host_uuid,
|
||||
wq.command_uuid,
|
||||
wc.created_at AS updated_at,
|
||||
'101' AS status,
|
||||
'pending' AS command_status,
|
||||
wc.target_loc_uri AS request_type
|
||||
FROM
|
||||
windows_mdm_command_queue wq
|
||||
JOIN mdm_windows_enrollments mwe ON mwe.id = wq.enrollment_id
|
||||
JOIN windows_mdm_commands wc ON wc.command_uuid = wq.command_uuid
|
||||
|
||||
WHERE
|
||||
mwe.host_uuid IN (?)
|
||||
|
||||
%[1]s
|
||||
|
||||
UNION
|
||||
|
||||
SELECT
|
||||
mwe.host_uuid,
|
||||
wcr.command_uuid,
|
||||
COALESCE(wcr.updated_at, wc.created_at) AS updated_at,
|
||||
COALESCE(NULLIF(wcr.status_code, ''), '101') AS status,
|
||||
CASE
|
||||
WHEN COALESCE(
|
||||
NULLIF(wcr.status_code, ''),
|
||||
'101'
|
||||
@@ -261,7 +280,7 @@ SELECT
|
||||
NULLIF(wcr.status_code, ''),
|
||||
'101'
|
||||
) AS UNSIGNED
|
||||
) BETWEEN 200 AND 399 THEN 'ran'
|
||||
) BETWEEN 200 AND 399 THEN 'ran'
|
||||
WHEN CAST(
|
||||
COALESCE(
|
||||
NULLIF(wcr.status_code, ''),
|
||||
@@ -269,17 +288,28 @@ SELECT
|
||||
) AS UNSIGNED
|
||||
) >= 400 THEN 'failed'
|
||||
END AS command_status,
|
||||
wc.target_loc_uri AS request_type
|
||||
FROM
|
||||
windows_mdm_command_queue wq
|
||||
JOIN mdm_windows_enrollments mwe ON mwe.id = wq.enrollment_id
|
||||
JOIN windows_mdm_commands wc ON wc.command_uuid = wq.command_uuid
|
||||
LEFT JOIN windows_mdm_command_results wcr ON wcr.command_uuid = wq.command_uuid
|
||||
AND wcr.enrollment_id = wq.enrollment_id
|
||||
WHERE
|
||||
mwe.host_uuid IN (?)`
|
||||
wc.target_loc_uri AS request_type
|
||||
FROM
|
||||
windows_mdm_command_results wcr
|
||||
JOIN mdm_windows_enrollments mwe ON mwe.id = wcr.enrollment_id
|
||||
JOIN windows_mdm_commands wc ON wc.command_uuid = wcr.command_uuid
|
||||
WHERE
|
||||
mwe.host_uuid IN (?)
|
||||
|
||||
%[1]s
|
||||
|
||||
`
|
||||
|
||||
var filterSQL string
|
||||
if listOpts.Filters.RequestType != "" {
|
||||
filterSQL = " AND wc.target_loc_uri = ?"
|
||||
winParams = append(winParams, listOpts.Filters.RequestType, winUUIDs, listOpts.Filters.RequestType)
|
||||
} else {
|
||||
winParams = append(winParams, winUUIDs)
|
||||
}
|
||||
|
||||
winStmt = fmt.Sprintf(winStmt, filterSQL)
|
||||
|
||||
winStmt, winParams = addRequestTypeFilter(winStmt, &listOpts.Filters, winParams)
|
||||
winStmt, winParams, err = sqlx.In(winStmt, winParams...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, ctxerr.Wrap(ctx, err, "prepare query to list MDM commands for Windows devices")
|
||||
|
||||
@@ -188,28 +188,16 @@ func testMDMCommands(t *testing.T, ds *Datastore) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ExecAdhocSQL(t, ds, func(tx sqlx.ExtContext) error {
|
||||
res, err := tx.ExecContext(
|
||||
ctx,
|
||||
`INSERT INTO windows_mdm_responses (enrollment_id, raw_response) VALUES (?, ?)`,
|
||||
windowsEnrollment.ID,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resID, _ := res.LastInsertId()
|
||||
_, err = tx.ExecContext(
|
||||
ctx,
|
||||
`INSERT INTO windows_mdm_command_results (enrollment_id, command_uuid, raw_result, status_code, response_id) VALUES (?, ?, ?, ?, ?)`,
|
||||
windowsEnrollment.ID,
|
||||
winCmd.CommandUUID,
|
||||
"",
|
||||
"200",
|
||||
resID,
|
||||
)
|
||||
return err
|
||||
})
|
||||
err = ds.MDMWindowsSaveResponse(ctx, windowsEnrollment.MDMDeviceID, fleet.EnrichedSyncML{
|
||||
SyncML: &fleet.SyncML{
|
||||
Raw: []byte("<xml></xml>"),
|
||||
},
|
||||
CmdRefUUIDToStatus: map[string]fleet.SyncMLCmd{winCmd.CommandUUID: {
|
||||
Data: ptr.String("200"),
|
||||
}},
|
||||
CmdRefUUIDs: []string{winCmd.CommandUUID},
|
||||
}, []string{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// we get both commands
|
||||
cmds, total, _, err = ds.ListMDMCommands(
|
||||
@@ -286,6 +274,7 @@ func testMDMCommands(t *testing.T, ds *Datastore) {
|
||||
identifier string
|
||||
commandStatus *fleet.MDMCommandStatusFilter
|
||||
expected []string
|
||||
requestType string
|
||||
}{
|
||||
{
|
||||
name: "windows host by hostname ambiguous with macOS host",
|
||||
@@ -300,6 +289,12 @@ func testMDMCommands(t *testing.T, ds *Datastore) {
|
||||
identifier: windowsH.UUID,
|
||||
expected: []string{winCmd.CommandUUID, winCmd2.CommandUUID, winCmd3.CommandUUID},
|
||||
},
|
||||
{
|
||||
name: "windows host by UUID, filter by request type",
|
||||
identifier: windowsH.UUID,
|
||||
expected: []string{winCmd2.CommandUUID},
|
||||
requestType: "./test/uri2",
|
||||
},
|
||||
{
|
||||
name: "windows host by hardware serial",
|
||||
identifier: windowsH.HardwareSerial,
|
||||
@@ -337,9 +332,11 @@ func testMDMCommands(t *testing.T, ds *Datastore) {
|
||||
Filters: fleet.MDMCommandFilters{
|
||||
HostIdentifier: tc.identifier,
|
||||
CommandStatuses: commandStatuses,
|
||||
RequestType: tc.requestType,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, cmds, len(tc.expected))
|
||||
var got []string
|
||||
|
||||
@@ -2467,7 +2467,7 @@ func (ds *Datastore) GetWindowsMDMCommandsForResending(ctx context.Context, fail
|
||||
return []*fleet.MDMWindowsCommand{}, nil
|
||||
}
|
||||
|
||||
stmt := `SELECT command_uuid, raw_command, target_loc_uri, created_at, updated_at
|
||||
stmt := `SELECT command_uuid, raw_command, target_loc_uri, created_at, updated_at
|
||||
FROM windows_mdm_commands WHERE`
|
||||
|
||||
args := []any{}
|
||||
|
||||
Reference in New Issue
Block a user