diff --git a/pkg/testing/fetcher_artifact.go b/pkg/testing/fetcher_artifact.go index 64ee6ec7646..103ee892dab 100644 --- a/pkg/testing/fetcher_artifact.go +++ b/pkg/testing/fetcher_artifact.go @@ -17,6 +17,9 @@ import ( "sync/atomic" "time" + "github.com/cenkalti/backoff/v5" + + "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact/download" semver "github.com/elastic/elastic-agent/pkg/version" ) @@ -116,21 +119,43 @@ func (r *artifactResult) Fetch(ctx context.Context, l Logger, dir string) error return fmt.Errorf("failed to create path %q: %w", dst, err) } - err = DownloadPackage(ctx, l, r.doer, r.src, dst) + _, err = backoff.Retry(ctx, func() (any, error) { + if err = r.fetch(ctx, l, dst); err != nil { + return nil, err + } + + // check package hash + if err = download.VerifySHA512Hash(dst); err != nil { + l.Logf("inconsistent package hash detected: %s", err) + return nil, fmt.Errorf("inconsistent package hash: %w", err) + } + + return nil, nil + }, + backoff.WithMaxTries(3), + backoff.WithBackOff(backoff.NewConstantBackOff(3*time.Second)), + ) + if err != nil { + return fmt.Errorf("failed to fetch %s: %w", r.src, err) + } + + return nil +} + +func (r *artifactResult) fetch(ctx context.Context, l Logger, dst string) error { + if err := DownloadPackage(ctx, l, r.doer, r.src, dst); err != nil { return fmt.Errorf("failed to download %s: %w", r.src, err) } // fetch package hash - err = DownloadPackage(ctx, l, r.doer, r.src+extHash, dst+extHash) - if err != nil { - return fmt.Errorf("failed to download %s: %w", r.src, err) + if err := DownloadPackage(ctx, l, r.doer, r.src+extHash, dst+extHash); err != nil { + return fmt.Errorf("failed to download %s: %w", r.src+extHash, err) } // fetch package asc - err = DownloadPackage(ctx, l, r.doer, r.src+extAsc, dst+extAsc) - if err != nil { - return fmt.Errorf("failed to download %s: %w", r.src, err) + if err := DownloadPackage(ctx, l, r.doer, r.src+extAsc, dst+extAsc); err != nil { + return fmt.Errorf("failed to download %s: %w", r.src+extAsc, err) } return nil @@ -144,7 +169,12 @@ func findURI(ctx context.Context, doer httpDoer, version *semver.ParsedSemVer) ( return fmt.Sprintf("https://snapshots.elastic.co/%s-%s/downloads/beats/elastic-agent/", version.CoreVersion(), version.BuildMetadata()), nil } - buildID, err := findLatestSnapshot(ctx, doer, version.CoreVersion()) + buildID, err := backoff.Retry(ctx, func() (any, error) { + return findLatestSnapshot(ctx, doer, version.CoreVersion()) + }, + backoff.WithMaxTries(3), + backoff.WithBackOff(backoff.NewConstantBackOff(3*time.Second)), + ) if err != nil { return "", fmt.Errorf("failed to find snapshot information for version %q: %w", version, err) } diff --git a/pkg/testing/fetcher_artifact_test.go b/pkg/testing/fetcher_artifact_test.go index 498a794c4f1..521f78c9d0c 100644 --- a/pkg/testing/fetcher_artifact_test.go +++ b/pkg/testing/fetcher_artifact_test.go @@ -110,16 +110,17 @@ func (c *fakeHttpClient) Do(req *http.Request) (*http.Response, error) { func newFakeHttpClient(t *testing.T) *fakeHttpClient { releaseResponse, err := os.ReadFile("./testdata/release-response.json") - require.NoError(t, err) + require.NoError(t, err, "failed to read release response") snapshotResponse, err := os.ReadFile("./testdata/snapshot-response.json") - require.NoError(t, err) + require.NoError(t, err, "failed to read snapshot response") manifestResponse, err := os.ReadFile("./testdata/build-manifest.json") - require.NoError(t, err) + require.NoError(t, err, "failed to read manifest response") - binaryResponse := "not valid data; but its very fast to download something this small" - hashResponse := "c2f59774022b79b61a7e6bbe28f3388d00a5bc2c7416a5c8fda79042af491d335f9b87adf905d1b154abdd2e31b200e4b1bb23cb472297596b25edef0a3b8d59" + binaryResponse, err := os.ReadFile("./testdata/data.tar.gz") + require.NoError(t, err, "failed to read binary response") + hashResponse := "cc52f8aa1106857dae8d380f6c2cf789d5d52730df0b0e6aba908a5e1f3cb947fda63bb4bc0301a3bc3329ef4b2f3c5fa9be9d8975a4d0f8f43076cfd5a5ec8a" ascResponse := `-----BEGIN PGP SIGNATURE----- wsBcBAABCAAQBQJlTLh5CRD2Vuvax5DnywAAzNcIADKuYov0CMeK938JQEzR4mXP @@ -153,11 +154,11 @@ func newFakeHttpClient(t *testing.T) *fakeHttpClient { // 8.12 release "https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.12.0-linux-x86_64.tar.gz": { StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(binaryResponse))), + Body: io.NopCloser(bytes.NewReader(binaryResponse)), }, "https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.12.0-linux-x86_64.tar.gz.sha512": { StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(hashResponse))), + Body: io.NopCloser(bytes.NewReader([]byte(hashResponse + " elastic-agent-8.12.0-linux-x86_64.tar.gz"))), }, "https://artifacts.elastic.co/downloads/beats/elastic-agent/elastic-agent-8.12.0-linux-x86_64.tar.gz.asc": { StatusCode: 200, @@ -166,11 +167,11 @@ func newFakeHttpClient(t *testing.T) *fakeHttpClient { // 8.13 SNAPSHOT "https://snapshots.elastic.co/8.13.0-yil7wib0/downloads/beats/elastic-agent/elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz": { StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(binaryResponse))), + Body: io.NopCloser(bytes.NewReader(binaryResponse)), }, "https://snapshots.elastic.co/8.13.0-yil7wib0/downloads/beats/elastic-agent/elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz.sha512": { StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(hashResponse))), + Body: io.NopCloser(bytes.NewReader([]byte(hashResponse + " elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz"))), }, "https://snapshots.elastic.co/8.13.0-yil7wib0/downloads/beats/elastic-agent/elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz.asc": { StatusCode: 200, @@ -184,11 +185,11 @@ func newFakeHttpClient(t *testing.T) *fakeHttpClient { // 8.13 build l5snflwr "https://snapshots.elastic.co/8.13.0-l5snflwr/downloads/beats/elastic-agent/elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz": { StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(binaryResponse))), + Body: io.NopCloser(bytes.NewReader(binaryResponse)), }, "https://snapshots.elastic.co/8.13.0-l5snflwr/downloads/beats/elastic-agent/elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz.sha512": { StatusCode: 200, - Body: io.NopCloser(bytes.NewReader([]byte(hashResponse))), + Body: io.NopCloser(bytes.NewReader([]byte(hashResponse + " elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz"))), }, "https://snapshots.elastic.co/8.13.0-l5snflwr/downloads/beats/elastic-agent/elastic-agent-8.13.0-SNAPSHOT-linux-x86_64.tar.gz.asc": { StatusCode: 200, diff --git a/pkg/testing/testdata/data.tar.gz b/pkg/testing/testdata/data.tar.gz new file mode 100644 index 00000000000..8123a6ea354 Binary files /dev/null and b/pkg/testing/testdata/data.tar.gz differ