finalize mdm commands part 1: support fleetctl get hosts --mdm and --mdm-pending (#10796)

This commit is contained in:
Martin Angers 2023-03-29 08:30:49 -04:00 committed by GitHub
parent 6d686d188f
commit 0e2c9bb873
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 348 additions and 16 deletions

View file

@ -0,0 +1,2 @@
* Added the `--mdm` and `--mdm-pending` flags to the `fleetctl get hosts` command to list hosts enrolled in Fleet MDM and pending enrollment in Fleet MDM, respectively.
* Added support for the "enrolled" value for the `mdm_enrollment_status` filter and the new `mdm_name` filter for the "List hosts", "Count hosts" and "List hosts in label" endpoints.

View file

@ -638,6 +638,14 @@ func getHostsCommand() *cli.Command {
configFlag(),
contextFlag(),
debugFlag(),
&cli.BoolFlag{
Name: "mdm",
Usage: "Filters hosts by hosts that have MDM turned on in Fleet and are connected to Fleet's MDM server.",
},
&cli.BoolFlag{
Name: "mdm-pending",
Usage: "Filters hosts by hosts ordered via Apple Business Manager (ABM). These will automatically enroll to Fleet and turn on MDM when they're unboxed.",
},
},
Action: func(c *cli.Context) error {
client, err := clientFromCLI(c)
@ -653,6 +661,35 @@ func getHostsCommand() *cli.Command {
if teamID := c.Uint("team"); teamID > 0 {
query.Set("team_id", strconv.FormatUint(uint64(teamID), 10))
}
if c.Bool("mdm") || c.Bool("mdm-pending") {
// print an error if MDM is not configured
appCfg, err := client.GetAppConfig()
if err != nil {
return err
}
if !appCfg.MDM.EnabledAndConfigured {
return errors.New("MDM features aren't turned on. Use `fleetctl generate mdm-apple` and then `fleet serve` with `mdm` configuration to turn on MDM features.")
}
// --mdm and --mdm-pending are mutually exclusive, return an error if
// both are set (one returns the enrolled hosts, the other the pending
// to be enrolled, so it would always return an empty list).
if c.Bool("mdm") && c.Bool("mdm-pending") {
return errors.New("cannot use --mdm and --mdm-pending together")
}
if c.Bool("mdm") {
// hosts enrolled (automatic or manual) in Fleet's MDM server
query.Set("mdm_name", fleet.WellKnownMDMFleet)
query.Set("mdm_enrollment_status", string(fleet.MDMEnrollStatusEnrolled))
}
if c.Bool("mdm-pending") {
// hosts pending enrollment in Fleet's MDM server
query.Set("mdm_name", fleet.WellKnownMDMFleet)
query.Set("mdm_enrollment_status", string(fleet.MDMEnrollStatusPending))
}
}
queryStr := query.Encode()
hosts, err := client.GetHosts(queryStr)

View file

@ -244,8 +244,9 @@ func TestGetTeamsByName(t *testing.T) {
func TestGetHosts(t *testing.T) {
_, ds := runServerWithMockedDS(t)
var mdmEnabled bool
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{}, nil
return &fleet.AppConfig{MDM: fleet.MDM{EnabledAndConfigured: mdmEnabled}}, nil
}
// this func is called when no host is specified i.e. `fleetctl get hosts --json`
@ -356,6 +357,16 @@ func TestGetHosts(t *testing.T) {
+------+------------+----------+-----------------+---------+
`
assert.Equal(t, expectedText, runAppForTest(t, []string{"get", "hosts"}))
_, err := runAppNoChecks([]string{"get", "hosts", "--mdm"})
require.Error(t, err)
assert.ErrorContains(t, err, "MDM features aren't turned on")
_, err = runAppNoChecks([]string{"get", "hosts", "--mdm-pending"})
require.Error(t, err)
assert.ErrorContains(t, err, "MDM features aren't turned on")
jsonPrettify := func(t *testing.T, v string) string {
var i interface{}
err := json.Unmarshal([]byte(v), &i)
@ -427,8 +438,113 @@ func TestGetHosts(t *testing.T) {
}
})
}
}
assert.Equal(t, expectedText, runAppForTest(t, []string{"get", "hosts"}))
func TestGetHostsMDM(t *testing.T) {
_, ds := runServerWithMockedDS(t)
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{MDM: fleet.MDM{EnabledAndConfigured: true}}, nil
}
// this func is called when no host is specified i.e. `fleetctl get hosts --json`
ds.ListHostsFunc = func(ctx context.Context, filter fleet.TeamFilter, opt fleet.HostListOptions) ([]*fleet.Host, error) {
additional := json.RawMessage(`{"query1": [{"col1": "val", "col2": 42}]}`)
hosts := []*fleet.Host{
{
UpdateCreateTimestamps: fleet.UpdateCreateTimestamps{
CreateTimestamp: fleet.CreateTimestamp{CreatedAt: time.Time{}},
UpdateTimestamp: fleet.UpdateTimestamp{UpdatedAt: time.Time{}},
},
HostSoftware: fleet.HostSoftware{},
DetailUpdatedAt: time.Time{},
LabelUpdatedAt: time.Time{},
LastEnrolledAt: time.Time{},
SeenTime: time.Time{},
ComputerName: "test_host",
Hostname: "test_host",
Additional: &additional,
},
{
UpdateCreateTimestamps: fleet.UpdateCreateTimestamps{
CreateTimestamp: fleet.CreateTimestamp{CreatedAt: time.Time{}},
UpdateTimestamp: fleet.UpdateTimestamp{UpdatedAt: time.Time{}},
},
HostSoftware: fleet.HostSoftware{},
DetailUpdatedAt: time.Time{},
LabelUpdatedAt: time.Time{},
LastEnrolledAt: time.Time{},
SeenTime: time.Time{},
ComputerName: "test_host2",
Hostname: "test_host2",
},
}
return hosts, nil
}
ds.LoadHostSoftwareFunc = func(ctx context.Context, host *fleet.Host, includeCVEScores bool) error {
return nil
}
ds.ListLabelsForHostFunc = func(ctx context.Context, hid uint) ([]*fleet.Label, error) {
return make([]*fleet.Label, 0), nil
}
ds.ListPacksForHostFunc = func(ctx context.Context, hid uint) (packs []*fleet.Pack, err error) {
return make([]*fleet.Pack, 0), nil
}
ds.ListHostBatteriesFunc = func(ctx context.Context, hid uint) (batteries []*fleet.HostBattery, err error) {
return nil, nil
}
ds.ListPoliciesForHostFunc = func(ctx context.Context, host *fleet.Host) ([]*fleet.HostPolicy, error) {
return nil, nil
}
tests := []struct {
name string
args []string
goldenFile string
wantErr string
}{
{
name: "get hosts --mdm --mdm-pending",
args: []string{"get", "hosts", "--mdm", "--mdm-pending"},
wantErr: "cannot use --mdm and --mdm-pending together",
},
{
name: "get hosts --mdm --json",
args: []string{"get", "hosts", "--mdm", "--json"},
goldenFile: "expectedListHostsMDM.json",
},
{
name: "get hosts --mdm-pending --yaml",
args: []string{"get", "hosts", "--mdm-pending", "--yaml"},
goldenFile: "expectedListHostsYaml.yml",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := runAppNoChecks(tt.args)
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
} else {
require.NoError(t, err)
}
if tt.goldenFile != "" {
expected, err := ioutil.ReadFile(filepath.Join("testdata", tt.goldenFile))
require.NoError(t, err)
if ext := filepath.Ext(tt.goldenFile); ext == ".json" {
// the output of --json is not a json array, but a list of
// newline-separated json objects. fix that for the assertion,
// turning it into a JSON array.
actual := "[" + strings.ReplaceAll(got.String(), "}\n{", "},{") + "]"
require.JSONEq(t, string(expected), actual)
} else {
require.YAMLEq(t, string(expected), got.String())
}
}
})
}
}
func TestGetConfig(t *testing.T) {

View file

@ -0,0 +1,130 @@
[
{
"kind": "host",
"apiVersion": "v1",
"spec": {
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"id": 0,
"detail_updated_at": "0001-01-01T00:00:00Z",
"label_updated_at": "0001-01-01T00:00:00Z",
"last_enrolled_at": "0001-01-01T00:00:00Z",
"seen_time": "0001-01-01T00:00:00Z",
"software_updated_at": "0001-01-01T00:00:00Z",
"refetch_requested": false,
"hostname": "test_host",
"display_name": "test_host",
"uuid": "",
"platform": "",
"osquery_version": "",
"os_version": "",
"build": "",
"platform_like": "",
"policy_updated_at": "0001-01-01T00:00:00Z",
"code_name": "",
"uptime": 0,
"memory": 0,
"cpu_type": "",
"cpu_subtype": "",
"cpu_brand": "",
"cpu_physical_cores": 0,
"cpu_logical_cores": 0,
"hardware_vendor": "",
"hardware_model": "",
"hardware_version": "",
"hardware_serial": "",
"computer_name": "test_host",
"public_ip": "",
"primary_ip": "",
"primary_mac": "",
"distributed_interval": 0,
"config_tls_refresh": 0,
"logger_tls_period": 0,
"mdm": {
"encryption_key_available": false,
"enrollment_status": null,
"name": "",
"server_url": null
},
"team_id": null,
"pack_stats": null,
"team_name": null,
"additional": {
"query1": [
{
"col1": "val",
"col2": 42
}
]
},
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
},
"status": "offline",
"display_text": "test_host"
}
},
{
"kind": "host",
"apiVersion": "v1",
"spec": {
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"id": 0,
"detail_updated_at": "0001-01-01T00:00:00Z",
"label_updated_at": "0001-01-01T00:00:00Z",
"last_enrolled_at": "0001-01-01T00:00:00Z",
"seen_time": "0001-01-01T00:00:00Z",
"software_updated_at": "0001-01-01T00:00:00Z",
"refetch_requested": false,
"hostname": "test_host2",
"uuid": "",
"platform": "",
"osquery_version": "",
"os_version": "",
"build": "",
"platform_like": "",
"policy_updated_at": "0001-01-01T00:00:00Z",
"code_name": "",
"uptime": 0,
"memory": 0,
"cpu_type": "",
"cpu_subtype": "",
"cpu_brand": "",
"cpu_physical_cores": 0,
"cpu_logical_cores": 0,
"hardware_vendor": "",
"hardware_model": "",
"hardware_version": "",
"hardware_serial": "",
"computer_name": "test_host2",
"display_name": "test_host2",
"public_ip": "",
"primary_ip": "",
"primary_mac": "",
"distributed_interval": 0,
"config_tls_refresh": 0,
"logger_tls_period": 0,
"mdm": {
"encryption_key_available": false,
"enrollment_status": null,
"name": "",
"server_url": null
},
"team_id": null,
"pack_stats": null,
"team_name": null,
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
},
"status": "offline",
"display_text": "test_host2"
}
}
]

View file

@ -1773,8 +1773,9 @@ the `software` table.
| os_version | string | query | The version of the operating system to filter hosts by. `os_name` must also be specified with `os_version` |
| device_mapping | boolean | query | Indicates whether `device_mapping` should be included for each host. See ["Get host's Google Chrome profiles](#get-hosts-google-chrome-profiles) for more information about this feature. |
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| disable_failing_policies| boolean | query | If "true", hosts will return failing policies as 0 regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
@ -1785,7 +1786,7 @@ If `software_id` is specified, an additional top-level key `"software"` is retur
If `mdm_id` is specified, an additional top-level key `"mobile_device_management_solution"` is returned with the information corresponding to the `mdm_id`.
If `mdm_id` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
If `munki_issue_id` is specified, an additional top-level key `"munki_issue"` is returned with the information corresponding to the `munki_issue_id`.
@ -1926,14 +1927,15 @@ Response payload with the `munki_issue_id` filter provided:
| os_version | string | query | The version of the operating system to filter hosts by. `os_name` must also be specified with `os_version` |
| label_id | integer | query | A valid label ID. Can only be used in combination with `order_key`, `order_direction`, `after`, `status`, `query` and `team_id`. |
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
If `additional_info_filters` is not specified, no `additional` information will be returned.
If `mdm_id` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
#### Example
@ -3000,13 +3002,14 @@ requested by a web browser.
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
| os_version | string | query | The version of the operating system to filter hosts by. `os_name` must also be specified with `os_version` |
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| label_id | integer | query | A valid label ID. Can only be used in combination with `order_key`, `order_direction`, `status`, `query` and `team_id`. |
If `mdm_id` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
#### Example
@ -3385,9 +3388,14 @@ Returns a list of the hosts that belong to the specified label.
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, and `ipv4`. |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| disable_failing_policies | boolean | query | If "true", hosts will return failing policies as 0 regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'latest', 'pending', or 'failing'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
#### Example
`GET /api/v1/fleet/labels/6/hosts&query=floobar`

View file

@ -784,19 +784,25 @@ func filterHostsByMDM(sql string, opt fleet.HostListOptions, params []interface{
sql += ` AND hmdm.mdm_id = ?`
params = append(params, *opt.MDMIDFilter)
}
if opt.MDMNameFilter != nil {
sql += ` AND hmdm.name = ?`
params = append(params, *opt.MDMNameFilter)
}
if opt.MDMEnrollmentStatusFilter != "" {
switch opt.MDMEnrollmentStatusFilter {
case fleet.MDMEnrollStatusAutomatic:
sql += ` AND hmdm.enrolled = 1 AND hmdm.installed_from_dep = 1`
case fleet.MDMEnrollStatusManual:
sql += ` AND hmdm.enrolled = 1 AND hmdm.installed_from_dep = 0`
case fleet.MDMEnrollStatusEnrolled:
sql += ` AND hmdm.enrolled = 1`
case fleet.MDMEnrollStatusPending:
sql += ` AND hmdm.enrolled = 0 AND hmdm.installed_from_dep = 1`
case fleet.MDMEnrollStatusUnenrolled:
sql += ` AND hmdm.enrolled = 0 AND hmdm.installed_from_dep = 0`
}
}
if opt.MDMIDFilter != nil || opt.MDMEnrollmentStatusFilter != "" {
if opt.MDMNameFilter != nil || opt.MDMIDFilter != nil || opt.MDMEnrollmentStatusFilter != "" {
sql += ` AND NOT COALESCE(hmdm.is_server, false) `
}
return sql, params

View file

@ -1093,7 +1093,7 @@ func testHostsListMDM(t *testing.T, ds *Datastore) {
hostIDs = append(hostIDs, h.ID)
}
// enrollment: pending
// enrollment: pending (with Fleet mdm)
n, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
{SerialNumber: "532141num832", Model: "MacBook Pro", OS: "OSX", OpType: "added"},
})
@ -1136,11 +1136,32 @@ func testHostsListMDM(t *testing.T, ds *Datastore) {
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusUnenrolled}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusEnrolled}, 3) // 2 auto, 1 manual
assert.Equal(t, 3, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusAutomatic, MDMIDFilter: &kandjiID}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusEnrolled, MDMIDFilter: &kandjiID}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusPending}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMSimpleMDM)}, 2)
assert.Equal(t, 2, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMIDFilter: &simpleMDMID, MDMNameFilter: ptr.String(fleet.WellKnownMDMSimpleMDM), MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusEnrolled}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMKandji)}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMFleet), MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusPending}, 1)
assert.Equal(t, 1, len(hosts))
hosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMJamf)}, 0)
assert.Equal(t, 0, len(hosts))
}
func testHostMDMSelect(t *testing.T, ds *Datastore) {

View file

@ -326,6 +326,8 @@ func testLabelsListHostsInLabel(t *testing.T, db *Datastore) {
listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMIDFilter: ptr.Uint(99)}, 0)
listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMIDFilter: ptr.Uint(simpleMDMID)}, 2)
listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMIDFilter: ptr.Uint(kandjiID)}, 1)
listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMSimpleMDM)}, 2)
listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMSimpleMDM), MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusEnrolled}, 1)
}
func listHostsInLabelCheckCount(

View file

@ -47,6 +47,7 @@ const (
MDMEnrollStatusAutomatic = MDMEnrollStatus("automatic")
MDMEnrollStatusPending = MDMEnrollStatus("pending")
MDMEnrollStatusUnenrolled = MDMEnrollStatus("unenrolled")
MDMEnrollStatusEnrolled = MDMEnrollStatus("enrolled") // combination of "manual" and "automatic"
)
// MacOSSettingsStatus defines the possible statuses of the host's macOS settings, which is derived from the
@ -110,6 +111,9 @@ type HostListOptions struct {
// MDMIDFilter filters the hosts by MDM ID.
MDMIDFilter *uint
// MDMNameFilter filters the hosts by MDM solution name (e.g. one of the
// fleet.WellKnownMDM... constants).
MDMNameFilter *string
// MDMEnrollmentStatusFilter filters the host by their MDM enrollment status.
MDMEnrollmentStatusFilter MDMEnrollStatus
// MunkiIssueIDFilter filters the hosts by munki issue ID.
@ -136,6 +140,7 @@ func (h HostListOptions) Empty() bool {
h.OSVersionFilter == nil &&
h.DisableFailingPolicies == false &&
h.MDMIDFilter == nil &&
h.MDMNameFilter == nil &&
h.MDMEnrollmentStatusFilter == "" &&
h.MunkiIssueIDFilter == nil &&
h.LowDiskSpaceFilter == nil

View file

@ -301,9 +301,14 @@ func hostListOptionsFromRequest(r *http.Request) (fleet.HostListOptions, error)
hopt.MDMIDFilter = &mid
}
if mdmName := r.URL.Query().Get("mdm_name"); mdmName != "" {
hopt.MDMNameFilter = &mdmName
}
enrollmentStatus := r.URL.Query().Get("mdm_enrollment_status")
switch fleet.MDMEnrollStatus(enrollmentStatus) {
case fleet.MDMEnrollStatusManual, fleet.MDMEnrollStatusAutomatic, fleet.MDMEnrollStatusPending, fleet.MDMEnrollStatusUnenrolled:
case fleet.MDMEnrollStatusManual, fleet.MDMEnrollStatusAutomatic,
fleet.MDMEnrollStatusPending, fleet.MDMEnrollStatusUnenrolled, fleet.MDMEnrollStatusEnrolled:
hopt.MDMEnrollmentStatusFilter = fleet.MDMEnrollStatus(enrollmentStatus)
case "":
// No error when unset