mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 08:58:41 +00:00
Software SS: Update APIs with self_service (#19187)
This commit is contained in:
parent
b55e2980c5
commit
87c4deb307
7 changed files with 43 additions and 11 deletions
|
|
@ -72,6 +72,7 @@ func (svc *Service) UploadSoftwareInstaller(ctx context.Context, payload *fleet.
|
|||
SoftwarePackage: payload.Filename,
|
||||
TeamName: teamName,
|
||||
TeamID: payload.TeamID,
|
||||
SelfService: payload.SelfService,
|
||||
}); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "creating activity for added software")
|
||||
}
|
||||
|
|
@ -116,6 +117,7 @@ func (svc *Service) DeleteSoftwareInstaller(ctx context.Context, titleID uint, t
|
|||
SoftwarePackage: meta.Name,
|
||||
TeamName: teamName,
|
||||
TeamID: meta.TeamID,
|
||||
SelfService: meta.SelfService,
|
||||
}); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "creating activity for deleted software")
|
||||
}
|
||||
|
|
@ -453,6 +455,7 @@ func (svc *Service) BatchSetSoftwareInstallers(ctx context.Context, tmName strin
|
|||
PreInstallQuery: p.PreInstallQuery,
|
||||
PostInstallScript: p.PostInstallScript,
|
||||
InstallerFile: bytes.NewReader(bodyBytes),
|
||||
SelfService: p.SelfService,
|
||||
}
|
||||
|
||||
// set the filename before adding metadata, as it is used as fallback
|
||||
|
|
|
|||
|
|
@ -104,8 +104,9 @@ INSERT INTO software_installers (
|
|||
install_script_content_id,
|
||||
pre_install_query,
|
||||
post_install_script_content_id,
|
||||
platform
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
platform,
|
||||
self_service
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
|
||||
args := []interface{}{
|
||||
payload.TeamID,
|
||||
|
|
@ -118,6 +119,7 @@ INSERT INTO software_installers (
|
|||
payload.PreInstallQuery,
|
||||
postInstallScriptID,
|
||||
payload.Platform,
|
||||
payload.SelfService,
|
||||
}
|
||||
|
||||
res, err := ds.writer(ctx).ExecContext(ctx, stmt, args...)
|
||||
|
|
@ -204,6 +206,7 @@ SELECT
|
|||
si.pre_install_query,
|
||||
si.post_install_script_content_id,
|
||||
si.uploaded_at,
|
||||
si.self_service,
|
||||
COALESCE(st.name, '') AS software_title
|
||||
%s
|
||||
FROM
|
||||
|
|
@ -299,7 +302,8 @@ SELECT
|
|||
h.team_id AS host_team_id,
|
||||
hsi.user_id AS user_id,
|
||||
hsi.post_install_script_exit_code,
|
||||
hsi.install_script_exit_code
|
||||
hsi.install_script_exit_code,
|
||||
hsi.self_service
|
||||
FROM
|
||||
host_software_installs hsi
|
||||
JOIN hosts h ON h.id = hsi.host_id
|
||||
|
|
|
|||
|
|
@ -1455,6 +1455,7 @@ type ActivityTypeAddedSoftware struct {
|
|||
SoftwarePackage string `json:"software_package"`
|
||||
TeamName *string `json:"team_name"`
|
||||
TeamID *uint `json:"team_id"`
|
||||
SelfService bool `json:"self_service"`
|
||||
}
|
||||
|
||||
func (a ActivityTypeAddedSoftware) ActivityName() string {
|
||||
|
|
@ -1477,6 +1478,7 @@ func (a ActivityTypeAddedSoftware) Documentation() (string, string, string) {
|
|||
}
|
||||
|
||||
type ActivityTypeDeletedSoftware struct {
|
||||
SelfService bool `json:"self_service"`
|
||||
SoftwareTitle string `json:"software_title"`
|
||||
SoftwarePackage string `json:"software_package"`
|
||||
TeamName *string `json:"team_name"`
|
||||
|
|
|
|||
|
|
@ -363,6 +363,7 @@ type SoftwareInstallerPayload struct {
|
|||
PreInstallQuery string `json:"pre_install_query"`
|
||||
InstallScript string `json:"install_script"`
|
||||
PostInstallScript string `json:"post_install_script"`
|
||||
SelfService bool `json:"self_service"`
|
||||
}
|
||||
|
||||
type HostLockWipeStatus struct {
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ type SoftwareInstaller struct {
|
|||
Status *SoftwareInstallerStatusSummary `json:"status,omitempty" db:"-"`
|
||||
// SoftwareTitle is the title of the software pointed installed by this installer.
|
||||
SoftwareTitle string `json:"-" db:"software_title"`
|
||||
// SelfService indicates that the software can be installed by the
|
||||
// end user without admin intervention
|
||||
SelfService bool `json:"-" db:"self_service"`
|
||||
}
|
||||
|
||||
// AuthzType implements authz.AuthzTyper.
|
||||
|
|
@ -175,6 +178,9 @@ type HostSoftwareInstallerResult struct {
|
|||
InstallScriptExitCode *int `json:"-" db:"install_script_exit_code"`
|
||||
// PostInstallScriptExitCode is used internally to determine the output displayed to the user.
|
||||
PostInstallScriptExitCode *int `json:"-" db:"post_install_script_exit_code"`
|
||||
// SelfService indicates that the installation was queued by the
|
||||
// end user and not an administrator
|
||||
SelfService bool `json:"self_service" db:"self_service"`
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
@ -252,6 +258,7 @@ type UploadSoftwareInstallerPayload struct {
|
|||
Version string
|
||||
Source string
|
||||
Platform string
|
||||
SelfService bool
|
||||
}
|
||||
|
||||
// DownloadSoftwareInstallerPayload is the payload for downloading a software installer.
|
||||
|
|
|
|||
|
|
@ -8970,7 +8970,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD
|
|||
s.uploadSoftwareInstaller(payload, http.StatusOK, "")
|
||||
|
||||
// check activity
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeAddedSoftware{}.ActivityName(), `{"software_title": "ruby", "software_package": "ruby.deb", "team_name": null, "team_id": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeAddedSoftware{}.ActivityName(), `{"software_title": "ruby", "software_package": "ruby.deb", "team_name": null, "team_id": null, "self_service": false}`, 0)
|
||||
|
||||
// check the software installer
|
||||
_, titleID := checkSoftwareInstaller(t, payload)
|
||||
|
|
@ -9005,11 +9005,12 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD
|
|||
PostInstallScript: "another post install script",
|
||||
Filename: "ruby.deb",
|
||||
// additional fields below are pre-populated so we can re-use the payload later for the test assertions
|
||||
Title: "ruby",
|
||||
Version: "1:2.5.1",
|
||||
Source: "deb_packages",
|
||||
StorageID: "df06d9ce9e2090d9cb2e8cd1f4d7754a803dc452bf93e3204e3acd3b95508628",
|
||||
Platform: "linux",
|
||||
Title: "ruby",
|
||||
Version: "1:2.5.1",
|
||||
Source: "deb_packages",
|
||||
StorageID: "df06d9ce9e2090d9cb2e8cd1f4d7754a803dc452bf93e3204e3acd3b95508628",
|
||||
Platform: "linux",
|
||||
SelfService: true,
|
||||
}
|
||||
s.uploadSoftwareInstaller(payload, http.StatusOK, "")
|
||||
|
||||
|
|
@ -9017,7 +9018,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD
|
|||
installerID, titleID := checkSoftwareInstaller(t, payload)
|
||||
|
||||
// check activity
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeAddedSoftware{}.ActivityName(), fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": "%s", "team_id": %d}`, createTeamResp.Team.Name, createTeamResp.Team.ID), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeAddedSoftware{}.ActivityName(), fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": "%s", "team_id": %d, "self_service": true}`, createTeamResp.Team.Name, createTeamResp.Team.ID), 0)
|
||||
|
||||
// upload again fails
|
||||
s.uploadSoftwareInstaller(payload, http.StatusConflict, "already exists")
|
||||
|
|
@ -9057,7 +9058,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD
|
|||
s.Do("DELETE", fmt.Sprintf("/api/latest/fleet/software/%d/package", titleID), nil, http.StatusNoContent, "team_id", fmt.Sprintf("%d", *payload.TeamID))
|
||||
|
||||
// check activity
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeDeletedSoftware{}.ActivityName(), fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": "%s", "team_id": %d}`, createTeamResp.Team.Name, createTeamResp.Team.ID), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeDeletedSoftware{}.ActivityName(), fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": "%s", "team_id": %d, "self_service": true}`, createTeamResp.Team.Name, createTeamResp.Team.ID), 0)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -9714,6 +9715,9 @@ func (s *integrationEnterpriseTestSuite) uploadSoftwareInstaller(payload *fleet.
|
|||
require.NoError(t, w.WriteField("install_script", payload.InstallScript))
|
||||
require.NoError(t, w.WriteField("pre_install_query", payload.PreInstallQuery))
|
||||
require.NoError(t, w.WriteField("post_install_script", payload.PostInstallScript))
|
||||
if payload.SelfService {
|
||||
require.NoError(t, w.WriteField("self_service", "true"))
|
||||
}
|
||||
|
||||
w.Close()
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type uploadSoftwareInstallerRequest struct {
|
|||
InstallScript string
|
||||
PreInstallQuery string
|
||||
PostInstallScript string
|
||||
SelfService bool
|
||||
}
|
||||
|
||||
type uploadSoftwareInstallerResponse struct {
|
||||
|
|
@ -79,6 +80,15 @@ func (uploadSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http
|
|||
decoded.PostInstallScript = val[0]
|
||||
}
|
||||
|
||||
val, ok = r.MultipartForm.Value["self_service"]
|
||||
if ok && len(val) > 0 && val[0] != "" {
|
||||
parsed, err := strconv.ParseBool(val[0])
|
||||
if err != nil {
|
||||
return nil, &fleet.BadRequestError{Message: fmt.Sprintf("failed to decode self_service bool in multipart form: %s", err.Error())}
|
||||
}
|
||||
decoded.SelfService = parsed
|
||||
}
|
||||
|
||||
return &decoded, nil
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +109,7 @@ func uploadSoftwareInstallerEndpoint(ctx context.Context, request interface{}, s
|
|||
PostInstallScript: req.PostInstallScript,
|
||||
InstallerFile: ff,
|
||||
Filename: req.File.Filename,
|
||||
SelfService: req.SelfService,
|
||||
}
|
||||
|
||||
if err := svc.UploadSoftwareInstaller(ctx, payload); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue