mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
feat: use a 15 minute timeout for adding a maintained app (#22247)
> Related issue: #22239 # 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] Added/updated tests - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
b45c8b02c9
commit
7f39281937
4 changed files with 38 additions and 9 deletions
|
|
@ -5,7 +5,10 @@ import (
|
|||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
|
|
@ -28,7 +31,13 @@ func (svc *Service) AddFleetMaintainedApp(ctx context.Context, teamID *uint, app
|
|||
}
|
||||
|
||||
// Download installer from the URL
|
||||
installerBytes, filename, err := maintainedapps.DownloadInstaller(ctx, app.InstallerURL)
|
||||
timeout := maintainedapps.InstallerTimeout
|
||||
if v := os.Getenv("FLEET_DEV_MAINTAINED_APPS_INSTALLER_TIMEOUT"); v != "" {
|
||||
timeout, _ = time.ParseDuration(v)
|
||||
}
|
||||
|
||||
client := fleethttp.NewClient(fleethttp.WithTimeout(timeout))
|
||||
installerBytes, filename, err := maintainedapps.DownloadInstaller(ctx, app.InstallerURL, client)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "downloading app installer")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ import (
|
|||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/pkg/fleethttp"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
)
|
||||
|
||||
// InstallerTimeout is the timeout duration for downloading and adding a maintained app.
|
||||
const InstallerTimeout = 15 * time.Minute
|
||||
|
||||
// DownloadInstaller downloads the maintained app installer located at the given URL.
|
||||
func DownloadInstaller(ctx context.Context, installerURL string) ([]byte, string, error) {
|
||||
func DownloadInstaller(ctx context.Context, installerURL string, client *http.Client) ([]byte, string, error) {
|
||||
// validate the URL before doing the request
|
||||
_, err := url.ParseRequestURI(installerURL)
|
||||
if err != nil {
|
||||
|
|
@ -26,8 +28,6 @@ func DownloadInstaller(ctx context.Context, installerURL string) ([]byte, string
|
|||
)
|
||||
}
|
||||
|
||||
client := fleethttp.NewClient(fleethttp.WithTimeout(30 * time.Second))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, installerURL, nil)
|
||||
if err != nil {
|
||||
return nil, "", ctxerr.Wrapf(ctx, err, "creating request for URL %s", installerURL)
|
||||
|
|
|
|||
|
|
@ -14235,11 +14235,15 @@ func (s *integrationEnterpriseTestSuite) TestMaintainedApps() {
|
|||
ctx := context.Background()
|
||||
|
||||
installerBytes := []byte("abc")
|
||||
|
||||
// Mock server to serve the "installers"
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/badinstaller":
|
||||
_, _ = w.Write([]byte("badinstaller"))
|
||||
case "/timeout":
|
||||
time.Sleep(3 * time.Second)
|
||||
_, _ = w.Write([]byte("timeout"))
|
||||
default:
|
||||
_, _ = w.Write(installerBytes)
|
||||
}
|
||||
|
|
@ -14270,6 +14274,8 @@ func (s *integrationEnterpriseTestSuite) TestMaintainedApps() {
|
|||
_, err = q.ExecContext(ctx, "UPDATE fleet_library_apps SET sha256 = ?, installer_url = ?", spoofedSHA, srv.URL+"/installer.zip")
|
||||
require.NoError(t, err)
|
||||
_, err = q.ExecContext(ctx, "UPDATE fleet_library_apps SET installer_url = ? WHERE id = 2", srv.URL+"/badinstaller")
|
||||
require.NoError(t, err)
|
||||
_, err = q.ExecContext(ctx, "UPDATE fleet_library_apps SET installer_url = ? WHERE id = 3", srv.URL+"/timeout")
|
||||
return err
|
||||
})
|
||||
|
||||
|
|
@ -14383,10 +14389,16 @@ func (s *integrationEnterpriseTestSuite) TestMaintainedApps() {
|
|||
r := s.Do("POST", "/api/latest/fleet/software/fleet_maintained_apps", &addFleetMaintainedAppRequest{AppID: 2}, http.StatusInternalServerError)
|
||||
require.Contains(t, extractServerErrorText(r.Body), "mismatch in maintained app SHA256 hash")
|
||||
|
||||
// Should timeout
|
||||
os.Setenv("FLEET_DEV_MAINTAINED_APPS_INSTALLER_TIMEOUT", "1s")
|
||||
r = s.Do("POST", "/api/latest/fleet/software/fleet_maintained_apps", &addFleetMaintainedAppRequest{AppID: 3}, http.StatusGatewayTimeout)
|
||||
os.Unsetenv("FLEET_DEV_MAINTAINED_APPS_INSTALLER_TIMEOUT")
|
||||
require.Contains(t, extractServerErrorText(r.Body), "Couldn't upload. Request timeout. Please make sure your server and load balancer timeout is long enough.")
|
||||
|
||||
// Add a maintained app to no team
|
||||
|
||||
req = &addFleetMaintainedAppRequest{
|
||||
AppID: 3,
|
||||
AppID: 4,
|
||||
SelfService: true,
|
||||
PreInstallQuery: "SELECT 1",
|
||||
InstallScript: "echo foo",
|
||||
|
|
@ -14409,7 +14421,7 @@ func (s *integrationEnterpriseTestSuite) TestMaintainedApps() {
|
|||
"team_id", "0",
|
||||
)
|
||||
|
||||
mapp, err = s.ds.GetMaintainedAppByID(ctx, 3)
|
||||
mapp, err = s.ds.GetMaintainedAppByID(ctx, 4)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, resp.Count)
|
||||
title = resp.SoftwareTitles[0]
|
||||
|
|
@ -14418,9 +14430,9 @@ func (s *integrationEnterpriseTestSuite) TestMaintainedApps() {
|
|||
require.Equal(t, mapp.Version, title.SoftwarePackage.Version)
|
||||
require.Equal(t, "installer.zip", title.SoftwarePackage.Name)
|
||||
|
||||
i, err = s.ds.GetSoftwareInstallerMetadataByID(context.Background(), getSoftwareInstallerIDByMAppID(3))
|
||||
i, err = s.ds.GetSoftwareInstallerMetadataByID(context.Background(), getSoftwareInstallerIDByMAppID(4))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ptr.Uint(3), i.FleetLibraryAppID)
|
||||
require.Equal(t, ptr.Uint(4), i.FleetLibraryAppID)
|
||||
require.Equal(t, mapp.SHA256, i.StorageID)
|
||||
require.Equal(t, "darwin", i.Platform)
|
||||
require.NotEmpty(t, i.InstallScriptContentID)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ package service
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/maintainedapps"
|
||||
)
|
||||
|
||||
type addFleetMaintainedAppRequest struct {
|
||||
|
|
@ -23,8 +25,14 @@ func (r addFleetMaintainedAppResponse) error() error { return r.Err }
|
|||
|
||||
func addFleetMaintainedAppEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (errorer, error) {
|
||||
req := request.(*addFleetMaintainedAppRequest)
|
||||
ctx, cancel := context.WithTimeout(ctx, maintainedapps.InstallerTimeout)
|
||||
defer cancel()
|
||||
err := svc.AddFleetMaintainedApp(ctx, req.TeamID, req.AppID, req.InstallScript, req.PreInstallQuery, req.PostInstallScript, req.SelfService)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
err = fleet.NewGatewayTimeoutError("Couldn't upload. Request timeout. Please make sure your server and load balancer timeout is long enough.", err)
|
||||
}
|
||||
|
||||
return &addFleetMaintainedAppResponse{Err: err}, nil
|
||||
}
|
||||
return &addFleetMaintainedAppResponse{}, nil
|
||||
|
|
|
|||
Loading…
Reference in a new issue