mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 00:45:19 +00:00
Add mdm solution payload to GET /hosts response when filtering by mdm_id (#7198)
This commit is contained in:
parent
11cefb6c61
commit
b891e0d7f7
@ -1736,9 +1736,12 @@ None.
|
||||
| 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' or 'unenrolled'. |
|
||||
|
||||
### Get host's Google Chrome profiles
|
||||
If `additional_info_filters` is not specified, no `additional` information will be returned.
|
||||
|
||||
If `software_id` is specified, an additional top-level key `"software"` is returned with the software object corresponding to the `software_id`. See [List all software](#list-all-software) response payload for details about this object.
|
||||
|
||||
If `mdm_id` is specified, an additional top-level key `"mobile_device_management_solution"` is returned with the aggregated statistics corresponding to the `mdm_id` (and, if provided, `team_id`). See [Get aggregated host's mobile device management (MDM) and Munki information](#get-aggregated-hosts-mobile-device-management-mdm-and-munki-information) response payload for details about this object. Note that the statistics are for the corresponding `mdm_id` (and `team_id` if provided) only, and do not take into account other potential filters such as `mdm_enrollment_status`.
|
||||
|
||||
#### Example
|
||||
|
||||
`GET /api/v1/fleet/hosts?page=0&per_page=100&order_key=hostname&query=2ce`
|
||||
@ -2546,7 +2549,7 @@ Retrieves the aggregated host OS versions information.
|
||||
| Name | Type | In | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. If not provided, all hosts are included. |
|
||||
| platform | string | query | Filters the hosts to the specified platform |
|
||||
| platform | string | query | Filters the hosts to the specified platform |
|
||||
| operating_system_id | integer | query | Filters the hosts to the specified operating system id |
|
||||
##### Default response
|
||||
|
||||
|
@ -277,6 +277,7 @@ type Service interface {
|
||||
|
||||
MacadminsData(ctx context.Context, id uint) (*MacadminsData, error)
|
||||
AggregatedMacadminsData(ctx context.Context, teamID *uint) (*AggregatedMacadminsData, error)
|
||||
AggregatedMDMSolutions(ctx context.Context, teamID *uint, mdmID uint) (*AggregatedMDMSolutions, error)
|
||||
|
||||
// OSVersions returns a list of operating systems and associated host counts, which may be
|
||||
// filtered using the following optional criteria: team id, platform, or operating system id
|
||||
|
@ -69,7 +69,11 @@ type listHostsRequest struct {
|
||||
type listHostsResponse struct {
|
||||
Hosts []HostResponse `json:"hosts"`
|
||||
Software *fleet.Software `json:"software,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
// MDMSolution is populated with the MDM solution corresponding to the mdm_id
|
||||
// filter if one is provided with the request (and it exists in the
|
||||
// database). It is nil otherwise and absent of the JSON response payload.
|
||||
MDMSolution *fleet.AggregatedMDMSolutions `json:"mobile_device_management_solution,omitempty"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r listHostsResponse) error() error { return r.Err }
|
||||
@ -86,6 +90,15 @@ func listHostsEndpoint(ctx context.Context, request interface{}, svc fleet.Servi
|
||||
}
|
||||
}
|
||||
|
||||
var mdmSolution *fleet.AggregatedMDMSolutions
|
||||
if req.Opts.MDMIDFilter != nil {
|
||||
var err error
|
||||
mdmSolution, err = svc.AggregatedMDMSolutions(ctx, req.Opts.TeamFilter, *req.Opts.MDMIDFilter)
|
||||
if err != nil {
|
||||
return listHostsResponse{Err: err}, nil
|
||||
}
|
||||
}
|
||||
|
||||
hosts, err := svc.ListHosts(ctx, req.Opts)
|
||||
if err != nil {
|
||||
return listHostsResponse{Err: err}, nil
|
||||
@ -100,7 +113,39 @@ func listHostsEndpoint(ctx context.Context, request interface{}, svc fleet.Servi
|
||||
|
||||
hostResponses[i] = *h
|
||||
}
|
||||
return listHostsResponse{Hosts: hostResponses, Software: software}, nil
|
||||
return listHostsResponse{Hosts: hostResponses, Software: software, MDMSolution: mdmSolution}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) AggregatedMDMSolutions(ctx context.Context, teamID *uint, mdmID uint) (*fleet.AggregatedMDMSolutions, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Host{TeamID: teamID}, fleet.ActionList); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if teamID != nil {
|
||||
_, err := svc.ds.Team(ctx, *teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// it is expected that there will be relatively few MDM solutions. This
|
||||
// returns the slice of all aggregated stats (one entry per mdm_id), and we
|
||||
// then iterate to return only the one that was requested (the slice is
|
||||
// stored as-is in a JSON field in the database).
|
||||
sols, _, err := svc.ds.AggregatedMDMSolutions(ctx, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, sol := range sols {
|
||||
// don't take the address of the loop variable (although it could be ok
|
||||
// here, but just bad practice)
|
||||
sol := sol
|
||||
if sol.ID == mdmID {
|
||||
return &sol, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (svc *Service) ListHosts(ctx context.Context, opt fleet.HostListOptions) ([]*fleet.Host, error) {
|
||||
|
@ -957,10 +957,13 @@ func (s *integrationTestSuite) TestListHosts() {
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp)
|
||||
require.Len(t, resp.Hosts, len(hosts))
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "per_page", "1")
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.Nil(t, resp.MDMSolution)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "order_key", "h.id", "after", fmt.Sprint(hosts[1].ID))
|
||||
require.Len(t, resp.Hosts, len(hosts)-2)
|
||||
|
||||
@ -971,6 +974,7 @@ func (s *integrationTestSuite) TestListHosts() {
|
||||
require.NoError(t, s.ds.UpdateHostSoftware(context.Background(), host.ID, software))
|
||||
require.NoError(t, s.ds.LoadHostSoftware(context.Background(), host, false))
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "software_id", fmt.Sprint(host.Software[0].ID))
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Equal(t, host.ID, resp.Hosts[0].ID)
|
||||
@ -986,21 +990,29 @@ func (s *integrationTestSuite) TestListHosts() {
|
||||
|
||||
require.NoError(t, s.ds.RecordPolicyQueryExecutions(context.Background(), host, map[uint]*bool{p.ID: ptr.Bool(false)}, time.Now(), false))
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "software_id", fmt.Sprint(host.Software[0].ID))
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Equal(t, 1, resp.Hosts[0].HostIssues.FailingPoliciesCount)
|
||||
assert.Equal(t, 1, resp.Hosts[0].HostIssues.TotalIssuesCount)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "software_id", fmt.Sprint(host.Software[0].ID), "disable_failing_policies", "true")
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Equal(t, 0, resp.Hosts[0].HostIssues.FailingPoliciesCount)
|
||||
assert.Equal(t, 0, resp.Hosts[0].HostIssues.TotalIssuesCount)
|
||||
|
||||
// filter by MDM criteria without any host having such information
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_id", fmt.Sprint(999))
|
||||
require.Len(t, resp.Hosts, 0)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.Nil(t, resp.MDMSolution)
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_enrollment_status", "manual")
|
||||
require.Len(t, resp.Hosts, 0)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.Nil(t, resp.MDMSolution)
|
||||
|
||||
// set MDM information on a host
|
||||
require.NoError(t, s.ds.SetOrUpdateMDMData(context.Background(), host.ID, true, "https://simplemdm.com", false))
|
||||
@ -1009,18 +1021,45 @@ func (s *integrationTestSuite) TestListHosts() {
|
||||
return sqlx.GetContext(context.Background(), q, &mdmID,
|
||||
`SELECT id FROM mobile_device_management_solutions WHERE name = ? AND server_url = ?`, fleet.WellKnownMDMSimpleMDM, "https://simplemdm.com")
|
||||
})
|
||||
// generate aggregated stats
|
||||
require.NoError(t, s.ds.GenerateAggregatedMunkiAndMDM(context.Background()))
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_enrollment_status", "manual")
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.Nil(t, resp.MDMSolution)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_enrollment_status", "automatic")
|
||||
require.Len(t, resp.Hosts, 0)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.Nil(t, resp.MDMSolution)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_enrollment_status", "unenrolled")
|
||||
require.Len(t, resp.Hosts, 0)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.Nil(t, resp.MDMSolution)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_id", fmt.Sprint(mdmID))
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Nil(t, resp.Software)
|
||||
require.NotNil(t, resp.MDMSolution)
|
||||
assert.Equal(t, mdmID, resp.MDMSolution.ID)
|
||||
assert.Equal(t, 1, resp.MDMSolution.HostsCount)
|
||||
assert.Equal(t, fleet.WellKnownMDMSimpleMDM, resp.MDMSolution.Name)
|
||||
assert.Equal(t, "https://simplemdm.com", resp.MDMSolution.ServerURL)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusOK, &resp, "mdm_id", fmt.Sprint(mdmID), "mdm_enrollment_status", "manual")
|
||||
require.Len(t, resp.Hosts, 1)
|
||||
assert.Nil(t, resp.Software)
|
||||
assert.NotNil(t, resp.MDMSolution)
|
||||
assert.Equal(t, mdmID, resp.MDMSolution.ID)
|
||||
|
||||
resp = listHostsResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/hosts", nil, http.StatusInternalServerError, &resp, "mdm_enrollment_status", "invalid-status") // TODO: to be addressed by #4406
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user