mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
finalize mdm commands part 1: support fleetctl get hosts --mdm and --mdm-pending (#10796)
This commit is contained in:
parent
6d686d188f
commit
0e2c9bb873
10 changed files with 348 additions and 16 deletions
2
changes/issue-9643-add-fleetctl-get-hosts-mdm
Normal file
2
changes/issue-9643-add-fleetctl-get-hosts-mdm
Normal 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.
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
130
cmd/fleetctl/testdata/expectedListHostsMDM.json
vendored
Normal file
130
cmd/fleetctl/testdata/expectedListHostsMDM.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue