Skip to content

Commit

Permalink
Fix upcoming activities for automatic installers (#21714)
Browse files Browse the repository at this point in the history
Small fix for #21428.

This is to show the activity the right way (Because installations
triggered by Fleet will have `host_software_installs` with `NULL`
`user_id`.).
  • Loading branch information
lucasmrod authored Aug 30, 2024
1 parent 390c688 commit f30017f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 10 deletions.
12 changes: 8 additions & 4 deletions server/datastore/mysql/activities.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,12 @@ func (ds *Datastore) ListHostUpcomingActivities(ctx context.Context, hostID uint
// list pending software installs
fmt.Sprintf(`SELECT
hsi.execution_id as uuid,
u.name as name,
u.id as user_id,
u.gravatar_url as gravatar_url,
u.email as user_email,
-- policies with automatic installers generate a host_software_installs with (user_id=NULL,self_service=0),
-- thus the user_id for the upcoming activity needs to be the user that uploaded the software installer.
IF(hsi.user_id IS NULL AND NOT hsi.self_service, u2.name, u.name) AS name,
IF(hsi.user_id IS NULL AND NOT hsi.self_service, u2.id, u.id) as user_id,
IF(hsi.user_id IS NULL AND NOT hsi.self_service, u2.gravatar_url, u.gravatar_url) as gravatar_url,
IF(hsi.user_id IS NULL AND NOT hsi.self_service, u2.email, u.email) AS user_email,
:installed_software_type as activity_type,
hsi.created_at as created_at,
JSON_OBJECT(
Expand All @@ -339,6 +341,8 @@ func (ds *Datastore) ListHostUpcomingActivities(ctx context.Context, hostID uint
software_titles st ON st.id = si.title_id
LEFT OUTER JOIN
users u ON u.id = hsi.user_id
LEFT OUTER JOIN
users u2 ON u2.id = si.user_id
LEFT OUTER JOIN
host_display_names hdn ON hdn.host_id = hsi.host_id
WHERE
Expand Down
29 changes: 23 additions & 6 deletions server/datastore/mysql/activities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,10 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
InstallScriptExitCode: ptr.Int(0),
})
require.NoError(t, err)
h1Foo, err := ds.InsertSoftwareInstallRequest(noUserCtx, h1.ID, sw1Meta.InstallerID, false) // no user for this one

// No user for this one and not Self-service, means it was installed by Fleet thus the author was decided to be the admin
// that uploaded the installer.
h1Foo, err := ds.InsertSoftwareInstallRequest(noUserCtx, h1.ID, sw1Meta.InstallerID, false)
require.NoError(t, err)

// create a single pending request for h2, as well as a non-pending one
Expand All @@ -509,6 +512,9 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
// add a pending software install request for h2
h2Bar, err := ds.InsertSoftwareInstallRequest(ctx, h2.ID, sw2Meta.InstallerID, false)
require.NoError(t, err)
// No user for this one and Self-service, means it was installed by the end user, so the user_id should be null/nil.
h2Foo, err := ds.InsertSoftwareInstallRequest(noUserCtx, h2.ID, sw1Meta.InstallerID, true)
require.NoError(t, err)

// nothing for h3

Expand All @@ -517,6 +523,8 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_software_installs", "execution_id", h1FooFailed, h1Bar)
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_script_results", "execution_id", h1C, h1D, h1E)
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_software_installs", "execution_id", h1FooInstalled, h1Foo)
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_software_installs", "execution_id", h1Foo)
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_software_installs", "execution_id", h2Foo)
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_software_installs", "execution_id", h2Bar)
endTime = SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_script_results", "execution_id", h2A, h2F)
SetOrderedCreatedAtTimestamps(t, ds, endTime, "host_vpp_software_installs", "command_uuid", vppCommand1, vppCommand2)
Expand All @@ -529,7 +537,8 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
h1E: false,
h2A: true,
h2F: true,
h1Foo: false,
h1Foo: true,
h2Foo: false,
h1Bar: true,
h2Bar: true,
vppCommand1: true,
Expand All @@ -544,6 +553,10 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
h1Foo: "foo",
h1Bar: "bar",
h2Bar: "bar",
h2Foo: "foo",
}
execIDsWithUserAdminID := map[string]struct{}{
h1Foo: {},
}

cases := []struct {
Expand Down Expand Up @@ -595,10 +608,10 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
wantMeta: &fleet.PaginationMetadata{HasNextResults: false, HasPreviousResults: true, TotalResults: 8},
},
{
opts: fleet.ListOptions{PerPage: 3},
opts: fleet.ListOptions{PerPage: 4},
hostID: h2.ID,
wantExecs: []string{h2Bar, h2A, vppCommand2},
wantMeta: &fleet.PaginationMetadata{HasNextResults: false, HasPreviousResults: false, TotalResults: 3},
wantExecs: []string{h2Foo, h2Bar, h2A, vppCommand2},
wantMeta: &fleet.PaginationMetadata{HasNextResults: false, HasPreviousResults: false, TotalResults: 4},
},
{
opts: fleet.ListOptions{},
Expand Down Expand Up @@ -639,7 +652,11 @@ func testListHostUpcomingActivities(t *testing.T, ds *Datastore) {
case fleet.ActivityTypeInstalledSoftware{}.ActivityName():
require.Equal(t, wantExec, details["install_uuid"], "result %d", i)
require.Equal(t, execIDsSoftwareTitle[wantExec], details["software_title"], "result %d", i)
wantUser = u2
if _, ok := execIDsWithUserAdminID[details["install_uuid"].(string)]; ok {
wantUser = u
} else {
wantUser = u2
}

case fleet.ActivityInstalledAppStoreApp{}.ActivityName():
require.Equal(t, wantExec, details["command_uuid"], "result %d", i)
Expand Down
10 changes: 10 additions & 0 deletions server/service/integration_enterprise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13214,6 +13214,16 @@ func (s *integrationEnterpriseTestSuite) TestPolicyAutomationsSoftwareInstallers
},
), http.StatusOK, &distributedResp)

// Upcoming activities for host1Team1 should show the automatic installation of dummy_installer.pkg.
// Check the author should be the admin that uploaded the installer.
var listUpcomingAct listHostUpcomingActivitiesResponse
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/hosts/%d/activities/upcoming", host1Team1.ID), nil, http.StatusOK, &listUpcomingAct)
require.Len(t, listUpcomingAct.Activities, 1)
require.NotNil(t, listUpcomingAct.Activities[0].ActorID)
require.Equal(t, globalAdmin.ID, *listUpcomingAct.Activities[0].ActorID)
require.Equal(t, globalAdmin.Name, *listUpcomingAct.Activities[0].ActorFullName)
require.Equal(t, globalAdmin.Email, *listUpcomingAct.Activities[0].ActorEmail)

//
// Finally have orbit install the packages and check activities.
//
Expand Down

0 comments on commit f30017f

Please sign in to comment.