Skip to content

Commit

Permalink
Modify status code for software batch endpoint (#23711)
Browse files Browse the repository at this point in the history
When using the `fleet/software/batch` endpoint, due to its async nature,
it should return a 202 (Accepted) rather than a 200 (Ok).

#23492

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files)
for more information.
- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
  • Loading branch information
ksykulev authored Nov 13, 2024
1 parent b25034d commit 48b992e
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 19 deletions.
1 change: 1 addition & 0 deletions changes/23492-software-batch-status-code
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Updated software batch endpoint status code from 200 (OK) to 202 (Accepted)
2 changes: 1 addition & 1 deletion docs/Contributing/API-for-contributors.md
Original file line number Diff line number Diff line change
Expand Up @@ -3516,7 +3516,7 @@ This endpoint is asynchronous, meaning it will start a background process to dow

##### Default response

`Status: 200`
`Status: 202`
```json
{
"request_uuid": "ec23c7b6-c336-4109-b89d-6afd859659b4",
Expand Down
36 changes: 18 additions & 18 deletions server/service/integration_enterprise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10934,7 +10934,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {
{URL: srv.URL + "/not_found.pkg"},
}
var batchResponse batchSetSoftwareInstallersResponse
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
message := waitBatchSetSoftwareInstallersFailed(t, s, tm.Name, batchResponse.RequestUUID)
require.NotEmpty(t, message)
require.Contains(t, message, fmt.Sprintf("validation failed: software.url Couldn't edit software. URL (\"%s/not_found.pkg\") returned \"Not Found\". Please make sure that URLs are reachable from your Fleet server.", srv.URL))
Expand All @@ -10944,7 +10944,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {
softwareToInstall = []fleet.SoftwareInstallerPayload{
{URL: rubyURL},
}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages := waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand Down Expand Up @@ -10975,7 +10975,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {
})

// same payload doesn't modify anything
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -10989,7 +10989,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {

// setting self-service to true updates the software title metadata
softwareToInstall[0].SelfService = true
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11004,7 +11004,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {

// empty payload cleans the software items
softwareToInstall = []fleet.SoftwareInstallerPayload{}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Empty(t, packages)
titlesResp = listSoftwareTitlesResponse{}
Expand All @@ -11019,7 +11019,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {
softwareToInstall = []fleet.SoftwareInstallerPayload{
{URL: rubyURL},
}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, "", batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11033,7 +11033,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {
require.Len(t, titlesResp.SoftwareTitles, 1)

// same payload doesn't modify anything
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, "", batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11045,7 +11045,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {

// setting self-service to true updates the software title metadata
softwareToInstall[0].SelfService = true
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, "", batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11058,7 +11058,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallers() {

// empty payload cleans the software items
softwareToInstall = []fleet.SoftwareInstallerPayload{}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, "", batchResponse.RequestUUID)
require.Empty(t, packages)
titlesResp = listSoftwareTitlesResponse{}
Expand Down Expand Up @@ -11133,7 +11133,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersSideEffec
{URL: srv.URL},
}
var batchResponse batchSetSoftwareInstallersResponse
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages := waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand Down Expand Up @@ -11199,7 +11199,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersSideEffec

// Switch self-service flag
softwareToInstall[0].SelfService = true
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11220,7 +11220,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersSideEffec
withUpdatedPreinstallQuery := []fleet.SoftwareInstallerPayload{
{URL: srv.URL, PreInstallQuery: "SELECT * FROM os_version"},
}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: withUpdatedPreinstallQuery}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: withUpdatedPreinstallQuery}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand Down Expand Up @@ -11265,7 +11265,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersSideEffec
withUpdatedInstallScript := []fleet.SoftwareInstallerPayload{
{URL: srv.URL, InstallScript: "apt install ruby"},
}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: withUpdatedInstallScript}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: withUpdatedInstallScript}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11287,7 +11287,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersSideEffec

trailer = " " // add a character to the response for the installer HTTP call to ensure the file hashes differently
// update package
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: withUpdatedInstallScript}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: withUpdatedInstallScript}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand Down Expand Up @@ -11330,7 +11330,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersSideEffec
require.Equal(t, fleet.SoftwareUninstallPending, *afterPreinstallHostResp.Software[0].Status)

// delete all installers
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: []fleet.SoftwareInstallerPayload{}}, http.StatusOK, &batchResponse, "team_name", tm.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: []fleet.SoftwareInstallerPayload{}}, http.StatusAccepted, &batchResponse, "team_name", tm.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, tm.Name, batchResponse.RequestUUID)
require.Len(t, packages, 0)

Expand Down Expand Up @@ -11396,7 +11396,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersWithPolic
},
}
var batchResponse batchSetSoftwareInstallersResponse
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", team1.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", team1.Name)
packages := waitBatchSetSoftwareInstallersCompleted(t, s, team1.Name, batchResponse.RequestUUID)
require.Len(t, packages, 1)
require.NotNil(t, packages[0].TitleID)
Expand All @@ -11413,7 +11413,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersWithPolic
URL: srv.URL + "/ruby.deb",
},
}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", team2.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", team2.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, team2.Name, batchResponse.RequestUUID)
sort.Slice(packages, func(i, j int) bool {
return packages[i].URL < packages[j].URL
Expand Down Expand Up @@ -11456,7 +11456,7 @@ func (s *integrationEnterpriseTestSuite) TestBatchSetSoftwareInstallersWithPolic

// Get rid of all installers in team1.
softwareToInstall = []fleet.SoftwareInstallerPayload{}
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusOK, &batchResponse, "team_name", team1.Name)
s.DoJSON("POST", "/api/latest/fleet/software/batch", batchSetSoftwareInstallersRequest{Software: softwareToInstall}, http.StatusAccepted, &batchResponse, "team_name", team1.Name)
packages = waitBatchSetSoftwareInstallersCompleted(t, s, team1.Name, batchResponse.RequestUUID)
require.Len(t, packages, 0)

Expand Down
1 change: 1 addition & 0 deletions server/service/software_installers.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ type batchSetSoftwareInstallersResponse struct {
}

func (r batchSetSoftwareInstallersResponse) error() error { return r.Err }
func (r batchSetSoftwareInstallersResponse) Status() int { return http.StatusAccepted }

func batchSetSoftwareInstallersEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (errorer, error) {
req := request.(*batchSetSoftwareInstallersRequest)
Expand Down

0 comments on commit 48b992e

Please sign in to comment.