diff --git a/NOTICE.txt b/NOTICE.txt index f1534eb783c..70c8ccb2fc1 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1377,11 +1377,11 @@ Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-l -------------------------------------------------------------------------------- Dependency : github.com/elastic/elastic-agent-system-metrics -Version: v0.8.0 +Version: v0.8.1 Licence type (autodetected): Apache-2.0 -------------------------------------------------------------------------------- -Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-system-metrics@v0.8.0/LICENSE.txt: +Contents of probable licence file $GOMODCACHE/github.com/elastic/elastic-agent-system-metrics@v0.8.1/LICENSE.txt: Apache License Version 2.0, January 2004 diff --git a/changelog/fragments/1700520158-dynamic-timeout-for-diags.yaml b/changelog/fragments/1700520158-dynamic-timeout-for-diags.yaml new file mode 100644 index 00000000000..d56af718c48 --- /dev/null +++ b/changelog/fragments/1700520158-dynamic-timeout-for-diags.yaml @@ -0,0 +1,32 @@ +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: enhancement + +# Change summary; a 80ish characters long description of the change. +summary: Use shorter timeouts for diagnostic requests unless CPU diagnostics are requested + +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment. +description: Use different timeout values for diagnostics requests, depending on if CPU diagnostics are requested + +# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc. +component: diagnostics + +# PR URL; optional; the PR number that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +#pr: https://github.com/owner/repo/1234 + +# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +issue: https://github.com/elastic/elastic-agent/issues/3197 diff --git a/changelog/fragments/1700678892-Fixes-the-Elastic-Agent-ignoring-agent.download.proxy_url-on-policy-update.yaml b/changelog/fragments/1700678892-Fixes-the-Elastic-Agent-ignoring-agent.download.proxy_url-on-policy-update.yaml new file mode 100644 index 00000000000..cc09836a0b5 --- /dev/null +++ b/changelog/fragments/1700678892-Fixes-the-Elastic-Agent-ignoring-agent.download.proxy_url-on-policy-update.yaml @@ -0,0 +1,32 @@ +# Kind can be one of: +# - breaking-change: a change to previously-documented behavior +# - deprecation: functionality that is being removed in a later release +# - bug-fix: fixes a problem in a previous version +# - enhancement: extends functionality but does not break or fix existing behavior +# - feature: new functionality +# - known-issue: problems that we are aware of in a given version +# - security: impacts on the security of a product or a user’s deployment. +# - upgrade: important information for someone upgrading from a prior version +# - other: does not fit into any of the other categories +kind: bug-fix + +# Change summary; a 80ish characters long description of the change. +summary: Fixes the Elastic Agent ignoring agent.download.proxy_url on policy update + +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment. +#description: + +# Affected component; a word indicating the component this changeset affects. +component: Upgrader + +# PR URL; optional; the PR number that added the changeset. +# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added. +# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number. +# Please provide it if you are adding a fragment for a different PR. +#pr: https://github.com/owner/repo/1234 + +# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of). +# If not present is automatically filled by the tooling with the issue linked to the PR number. +issue: https://github.com/elastic/elastic-agent/issues/3560 diff --git a/dev-tools/packaging/packages.yml b/dev-tools/packaging/packages.yml index 597c610271c..83f8e60419a 100644 --- a/dev-tools/packaging/packages.yml +++ b/dev-tools/packaging/packages.yml @@ -421,12 +421,12 @@ shared: - &docker_ubi_spec extra_vars: - image_name: '{{.BeatName}}-ubi9' + image_name: '{{.BeatName}}-ubi' from: 'docker.elastic.co/ubi9/ubi-minimal' - &docker_arm_ubi_spec extra_vars: - image_name: '{{.BeatName}}-ubi9' + image_name: '{{.BeatName}}-ubi' from: 'registry.access.redhat.com/ubi9/ubi-minimal:9.3' - &elastic_docker_spec diff --git a/go.mod b/go.mod index cc11a2faffd..10f09aa94d8 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/elastic/elastic-agent-autodiscover v0.6.5 github.com/elastic/elastic-agent-client/v7 v7.5.0 github.com/elastic/elastic-agent-libs v0.7.2 - github.com/elastic/elastic-agent-system-metrics v0.8.0 + github.com/elastic/elastic-agent-system-metrics v0.8.1 github.com/elastic/elastic-transport-go/v8 v8.3.0 github.com/elastic/go-elasticsearch/v8 v8.11.0 github.com/elastic/go-licenser v0.4.1 diff --git a/go.sum b/go.sum index 92c7a17f67b..ed105c44103 100644 --- a/go.sum +++ b/go.sum @@ -783,8 +783,8 @@ github.com/elastic/elastic-agent-client/v7 v7.5.0 h1:niI3WQ+01Lnp2r5LxK8SyNhrPJe github.com/elastic/elastic-agent-client/v7 v7.5.0/go.mod h1:DYoX95xjC4BW/p2avyu724Qr2+hoUIz9eCU9CVS1d+0= github.com/elastic/elastic-agent-libs v0.7.2 h1:yT0hF0UAxJCdQqhHh6SFpgYrcpB10oFzPj8IaytPS2o= github.com/elastic/elastic-agent-libs v0.7.2/go.mod h1:pVBEElQJUO9mr4WStWNXuQGsJn54lcjAoYAHmsvBLBc= -github.com/elastic/elastic-agent-system-metrics v0.8.0 h1:EsWbtd83JvnaqnL57bKS1E6GhOdemTRbxdFDcenR8zQ= -github.com/elastic/elastic-agent-system-metrics v0.8.0/go.mod h1:9C1UEfj0P687HAzZepHszN6zXA+2tN2Lx3Osvq1zby8= +github.com/elastic/elastic-agent-system-metrics v0.8.1 h1:eg6actuLeGJlIJFotHRdlAsz/3WhX2G8E0qI301IKBA= +github.com/elastic/elastic-agent-system-metrics v0.8.1/go.mod h1:9C1UEfj0P687HAzZepHszN6zXA+2tN2Lx3Osvq1zby8= github.com/elastic/elastic-integration-corpus-generator-tool v0.5.0/go.mod h1:uf9N86y+UACGybdEhZLpwZ93XHWVhsYZAA4c2T2v6YM= github.com/elastic/elastic-package v0.77.0/go.mod h1:Xeqx0OOVnKBfFoSHsHmKI74RxgRGiDhU6yXEu8BkJJM= github.com/elastic/elastic-transport-go/v8 v8.3.0 h1:DJGxovyQLXGr62e9nDMPSxRyWION0Bh6d9eCFBriiHo= diff --git a/internal/pkg/agent/application/upgrade/step_download.go b/internal/pkg/agent/application/upgrade/step_download.go index 9feb765bc60..1623d722600 100644 --- a/internal/pkg/agent/application/upgrade/step_download.go +++ b/internal/pkg/agent/application/upgrade/step_download.go @@ -257,7 +257,8 @@ func (u *Upgrader) downloadWithRetries( } opFailureNotificationFn := func(err error, retryAfter time.Duration) { - u.log.Warnf("%s; retrying (will be retry %d) in %s.", err.Error(), attempt, retryAfter) + u.log.Warnf("download attempt %d failed: %s; retrying in %s.", + attempt, err.Error(), retryAfter) } if err := backoff.RetryNotify(opFn, boCtx, opFailureNotificationFn); err != nil { diff --git a/internal/pkg/agent/application/upgrade/step_download_test.go b/internal/pkg/agent/application/upgrade/step_download_test.go index 2f4500389ac..e9a772a3fc5 100644 --- a/internal/pkg/agent/application/upgrade/step_download_test.go +++ b/internal/pkg/agent/application/upgrade/step_download_test.go @@ -139,7 +139,7 @@ func TestDownloadWithRetries(t *testing.T) { logs := obs.TakeAll() require.Len(t, logs, 3) require.Equal(t, "download attempt 1", logs[0].Message) - require.Contains(t, logs[1].Message, "unable to create fetcher: failed to construct downloader; retrying (will be retry 1)") + require.Contains(t, logs[1].Message, "unable to create fetcher: failed to construct downloader") require.Equal(t, "download attempt 2", logs[2].Message) }) @@ -178,7 +178,7 @@ func TestDownloadWithRetries(t *testing.T) { logs := obs.TakeAll() require.Len(t, logs, 3) require.Equal(t, "download attempt 1", logs[0].Message) - require.Contains(t, logs[1].Message, "unable to download package: download failed; retrying (will be retry 1)") + require.Contains(t, logs[1].Message, "unable to download package: download failed; retrying") require.Equal(t, "download attempt 2", logs[2].Message) }) @@ -207,7 +207,7 @@ func TestDownloadWithRetries(t *testing.T) { require.GreaterOrEqual(t, len(logs), minNmExpectedAttempts*2) for i := 0; i < minNmExpectedAttempts; i++ { require.Equal(t, fmt.Sprintf("download attempt %d", i+1), logs[(2*i)].Message) - require.Contains(t, logs[(2*i+1)].Message, fmt.Sprintf("unable to download package: download failed; retrying (will be retry %d)", i+1)) + require.Contains(t, logs[(2*i+1)].Message, "unable to download package: download failed; retrying") } }) } diff --git a/internal/pkg/agent/application/upgrade/upgrade.go b/internal/pkg/agent/application/upgrade/upgrade.go index a7c3c7e817b..4e9eb72bacd 100644 --- a/internal/pkg/agent/application/upgrade/upgrade.go +++ b/internal/pkg/agent/application/upgrade/upgrade.go @@ -20,6 +20,7 @@ import ( "github.com/elastic/elastic-agent/internal/pkg/agent/application/reexec" "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact" "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details" + "github.com/elastic/elastic-agent/internal/pkg/agent/configuration" "github.com/elastic/elastic-agent/internal/pkg/agent/errors" "github.com/elastic/elastic-agent/internal/pkg/agent/install" "github.com/elastic/elastic-agent/internal/pkg/config" @@ -89,35 +90,39 @@ func (u *Upgrader) SetClient(c fleetclient.Sender) { // Reload reloads the artifact configuration for the upgrader. func (u *Upgrader) Reload(rawConfig *config.Config) error { - type reloadConfig struct { - // SourceURI: source of the artifacts, e.g https://artifacts.elastic.co/downloads/ - SourceURI string `json:"agent.download.sourceURI" config:"agent.download.sourceURI"` + cfg, err := configuration.NewFromConfig(rawConfig) + if err != nil { + return fmt.Errorf("invalid config: %w", err) + } - // FleetSourceURI: source of the artifacts, e.g https://artifacts.elastic.co/downloads/ coming from fleet which uses - // different naming. + // the source URI coming from fleet which uses a different naming. + type fleetCfg struct { + // FleetSourceURI: source of the artifacts, e.g https://artifacts.elastic.co/downloads/ FleetSourceURI string `json:"agent.download.source_uri" config:"agent.download.source_uri"` } - cfg := &reloadConfig{} - if err := rawConfig.Unpack(&cfg); err != nil { + fleetSourceURI := &fleetCfg{} + if err := rawConfig.Unpack(&fleetSourceURI); err != nil { return errors.New(err, "failed to unpack config during reload") } - var newSourceURI string - if cfg.FleetSourceURI != "" { - // fleet configuration takes precedence - newSourceURI = cfg.FleetSourceURI - } else if cfg.SourceURI != "" { - newSourceURI = cfg.SourceURI + // fleet configuration takes precedence + if fleetSourceURI.FleetSourceURI != "" { + cfg.Settings.DownloadConfig.SourceURI = fleetSourceURI.FleetSourceURI } - if newSourceURI != "" { - u.log.Infof("Source URI changed from %q to %q", u.settings.SourceURI, newSourceURI) - u.settings.SourceURI = newSourceURI + if cfg.Settings.DownloadConfig.SourceURI != "" { + u.log.Infof("Source URI changed from %q to %q", + u.settings.SourceURI, + cfg.Settings.DownloadConfig.SourceURI) } else { // source uri unset, reset to default - u.log.Infof("Source URI reset from %q to %q", u.settings.SourceURI, artifact.DefaultSourceURI) - u.settings.SourceURI = artifact.DefaultSourceURI + u.log.Infof("Source URI reset from %q to %q", + u.settings.SourceURI, + artifact.DefaultSourceURI) + cfg.Settings.DownloadConfig.SourceURI = artifact.DefaultSourceURI } + + u.settings = cfg.Settings.DownloadConfig return nil } diff --git a/internal/pkg/agent/application/upgrade/upgrade_test.go b/internal/pkg/agent/application/upgrade/upgrade_test.go index d8de6923cfe..66967de4135 100644 --- a/internal/pkg/agent/application/upgrade/upgrade_test.go +++ b/internal/pkg/agent/application/upgrade/upgrade_test.go @@ -14,15 +14,17 @@ import ( "strings" "testing" - "github.com/elastic/elastic-agent/pkg/control/v2/client" - "github.com/elastic/elastic-agent/pkg/control/v2/client/mocks" - "github.com/elastic/elastic-agent/pkg/control/v2/cproto" - "github.com/gofrs/flock" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/artifact" "github.com/elastic/elastic-agent/internal/pkg/agent/errors" + "github.com/elastic/elastic-agent/internal/pkg/config" "github.com/elastic/elastic-agent/internal/pkg/release" + "github.com/elastic/elastic-agent/pkg/control/v2/client" + "github.com/elastic/elastic-agent/pkg/control/v2/client/mocks" + "github.com/elastic/elastic-agent/pkg/control/v2/cproto" "github.com/elastic/elastic-agent/pkg/core/logger" ) @@ -209,3 +211,67 @@ func TestIsInProgress(t *testing.T) { }) } } + +func TestUpgraderReload(t *testing.T) { + defaultCfg := artifact.DefaultConfig() + tcs := []struct { + name string + sourceURL string + proxyURL string + cfg string + }{ + { + name: "proxy_url is applied", + sourceURL: defaultCfg.SourceURI, + proxyURL: "http://someBrokenURL/", + cfg: ` +agent.download: + proxy_url: http://someBrokenURL/ +`, + }, + { + name: "source_uri has precedence over sourceURI", + sourceURL: "https://this.sourceURI.co/downloads/beats/", + cfg: ` +agent.download: + source_uri: "https://this.sourceURI.co/downloads/beats/" + sourceURI: "https://NOT.sourceURI.co/downloads/beats/" +`}, { + name: "only sourceURI", + sourceURL: "https://this.sourceURI.co/downloads/beats/", + cfg: ` +agent.download: + sourceURI: "https://this.sourceURI.co/downloads/beats/" +`}, { + name: "only source_uri", + sourceURL: "https://this.sourceURI.co/downloads/beats/", + cfg: ` +agent.download: + source_uri: "https://this.sourceURI.co/downloads/beats/" +`}, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + log, _ := logger.NewTesting("") + + u := Upgrader{ + log: log, + settings: artifact.DefaultConfig(), + } + + cfg, err := config.NewConfigFrom(tc.cfg) + require.NoError(t, err, "failed to create new config") + + err = u.Reload(cfg) + require.NoError(t, err, "error reloading config") + + assert.Equal(t, tc.sourceURL, u.settings.SourceURI) + if tc.proxyURL != "" { + require.NotNilf(t, u.settings.Proxy.URL, + "ProxyURI should not be nil, want %s", tc.proxyURL) + assert.Equal(t, tc.proxyURL, u.settings.Proxy.URL.String()) + } + }) + } +} diff --git a/internal/pkg/composable/providers/host/host_test.go b/internal/pkg/composable/providers/host/host_test.go index cfb74bd288c..edb409038df 100644 --- a/internal/pkg/composable/providers/host/host_test.go +++ b/internal/pkg/composable/providers/host/host_test.go @@ -30,7 +30,7 @@ func TestContextProvider(t *testing.T) { require.NoError(t, err) const checkInterval = 50 * time.Millisecond - const testTimeout = 500 * time.Millisecond + const testTimeout = 1 * time.Second c, err := config.NewConfigFrom(map[string]interface{}{ "check_interval": checkInterval, }) diff --git a/pkg/component/runtime/manager.go b/pkg/component/runtime/manager.go index 81fde1090b0..a375ddf816a 100644 --- a/pkg/component/runtime/manager.go +++ b/pkg/component/runtime/manager.go @@ -43,8 +43,11 @@ const ( // maxCheckinMisses is the maximum number of check-in misses a component can miss before it is killed // and restarted. maxCheckinMisses = 3 - // diagnosticTimeout is the maximum amount of time to wait for a diagnostic response from a unit. - diagnosticTimeout = time.Minute + // diagnosticTimeoutCPU is the maximum amount of time to wait for a diagnostic response from a unit while collecting CPU profiles + diagnosticTimeoutCPU = time.Minute + + // diagnosticTimeout is the maximum amount of time to wait for a diagnostic response from a unit + diagnosticTimeout = time.Second * 20 // stopCheckRetryPeriod is a idle time between checks for component stopped state stopCheckRetryPeriod = 200 * time.Millisecond @@ -944,7 +947,15 @@ func (m *Manager) getListenAddr() string { // performDiagAction creates a diagnostic ActionRequest and executes it against the runtime that's mapped to the specified component. // if the specified actionLevel is ActionRequest_COMPONENT, the unit field is ignored. func (m *Manager) performDiagAction(ctx context.Context, comp component.Component, unit component.Unit, actionLevel proto.ActionRequest_Level, params client.DiagnosticParams) ([]*proto.ActionDiagnosticUnitResult, error) { - ctx, cancel := context.WithTimeout(ctx, diagnosticTimeout) + // if we're gathering CPU diagnostics, request a longer timeout; CPU diag collection requires the diagnostic hook to sit and gather a CPU profile. + finalDiagnosticTime := diagnosticTimeout + for _, tag := range params.AdditionalMetrics { + if tag == "CPU" { + finalDiagnosticTime = diagnosticTimeoutCPU + break + } + } + ctx, cancel := context.WithTimeout(ctx, finalDiagnosticTime) defer cancel() id, err := uuid.NewV4() @@ -966,7 +977,7 @@ func (m *Manager) performDiagAction(ctx context.Context, comp component.Componen } if len(params.AdditionalMetrics) > 0 { - m.logger.Debugf("Performing diagnostic action with params: %v", params.AdditionalMetrics) + m.logger.Debugf("Performing diagnostic action with params: %v; will wait %s", params.AdditionalMetrics, finalDiagnosticTime) } marshalParams, err := json.Marshal(params) if err != nil { @@ -989,7 +1000,7 @@ func (m *Manager) performDiagAction(ctx context.Context, comp component.Componen // the only way this can return an error is a context Done(), be sure to make that explicit. if err != nil { if errors.Is(context.DeadlineExceeded, err) { - return nil, fmt.Errorf("diagnostic action timed out, deadline is %s: %w", diagnosticTimeout, err) + return nil, fmt.Errorf("diagnostic action timed out, deadline is %s: %w", finalDiagnosticTime, err) } return nil, fmt.Errorf("error running performAction: %w", err) } diff --git a/pkg/testing/fetcher.go b/pkg/testing/fetcher.go index 414292be5cb..baa734495f9 100644 --- a/pkg/testing/fetcher.go +++ b/pkg/testing/fetcher.go @@ -20,7 +20,8 @@ import ( "github.com/hashicorp/go-multierror" ) -const hashExt = ".sha512" +const extAsc = ".asc" +const extHash = ".sha512" var ( // ErrUnsupportedPlatform returned when the operating system and architecture combination is not supported. @@ -133,7 +134,7 @@ func untar(archivePath string, extractDir string) error { fi := f.FileInfo() mode := fi.Mode() - abs := filepath.Join(extractDir, f.Name) + abs := filepath.Join(extractDir, f.Name) //nolint:gosec // used only in tests switch { case mode.IsRegular(): // just to be sure, it should already be created by Dir type @@ -146,7 +147,7 @@ func untar(archivePath string, extractDir string) error { return fmt.Errorf("failed creating file %s: %w", abs, err) } - _, err = io.Copy(wf, tr) + _, err = io.Copy(wf, tr) //nolint:gosec // used only in tests if closeErr := wf.Close(); closeErr != nil && err == nil { err = closeErr } @@ -193,7 +194,7 @@ func unzip(archivePath string, extractDir string) error { fi := f.FileInfo() mode := fi.Mode() - abs := filepath.Join(extractDir, f.Name) + abs := filepath.Join(extractDir, f.Name) //nolint:gosec // used only in tests switch { case mode.IsRegular(): // just to be sure, it should already be created by Dir type @@ -211,6 +212,7 @@ func unzip(archivePath string, extractDir string) error { } }() + //nolint:gosec // used only in tests if _, err = io.Copy(f, rc); err != nil { return fmt.Errorf("error writing file %s: %w", abs, err) } diff --git a/pkg/testing/fetcher_artifact.go b/pkg/testing/fetcher_artifact.go index 51b26cd28c3..5bbe25d35fe 100644 --- a/pkg/testing/fetcher_artifact.go +++ b/pkg/testing/fetcher_artifact.go @@ -108,7 +108,13 @@ func (r *artifactResult) Fetch(ctx context.Context, l Logger, dir string) error } // fetch package hash - err = DownloadPackage(ctx, l, r.doer, r.src+hashExt, filepath.Join(dir, r.path+hashExt)) + err = DownloadPackage(ctx, l, r.doer, r.src+extHash, filepath.Join(dir, r.path+extHash)) + if err != nil { + return fmt.Errorf("failed to download %s: %w", r.src, err) + } + + // fetch package asc + err = DownloadPackage(ctx, l, r.doer, r.src+extAsc, filepath.Join(dir, r.path+extAsc)) if err != nil { return fmt.Errorf("failed to download %s: %w", r.src, err) } diff --git a/pkg/testing/fetcher_artifact_test.go b/pkg/testing/fetcher_artifact_test.go index 2c6dc42b9cf..0b76fa473cb 100644 --- a/pkg/testing/fetcher_artifact_test.go +++ b/pkg/testing/fetcher_artifact_test.go @@ -7,12 +7,11 @@ package testing import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "os" "path/filepath" "runtime" - "strconv" "testing" "github.com/stretchr/testify/assert" @@ -25,27 +24,9 @@ func TestArtifactFetcher_Name(t *testing.T) { } func TestArtifactFetcher_Default(t *testing.T) { - artifactsResponse := `{"packages":{"elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz.asc","type":"docker","classifier":"docker-build-context","attributes":{"artifactNoKpi":"true","internal":"false","url":"null/null/elastic-agent-ironbank"}},"elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["darwin"]},"elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats-ci","url":"docker.elastic.co/beats-ci/elastic-agent-cloud","repo":"docker.elastic.co"}},"elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent-ubi8","repo":"docker.elastic.co"}},"elastic-agent-8.6.0-x86_64.rpm":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-x86_64.rpm","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-x86_64.rpm.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-x86_64.rpm.asc","type":"rpm","architecture":"x86_64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-8.6.0-windows-x86_64.zip":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-windows-x86_64.zip","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-windows-x86_64.zip.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-windows-x86_64.zip.asc","type":"zip","architecture":"x86_64","os":["windows"]},"elastic-agent-8.6.0-arm64.deb":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-arm64.deb","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-arm64.deb.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-arm64.deb.asc","type":"deb","architecture":"arm64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-shipper-8.6.0-windows-x86_64.zip":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86_64.zip","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86_64.zip.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86_64.zip.asc","type":"zip","architecture":"x86_64","os":["windows"]},"elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz.asc","type":"tar","architecture":"aarch64","os":["darwin"]},"elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz.asc","type":"docker","architecture":"arm64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent","repo":"docker.elastic.co"}},"elastic-agent-8.6.0-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-arm64.tar.gz.asc","type":"tar","architecture":"arm64","os":["linux"]},"elastic-agent-shipper-8.6.0-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-arm64.tar.gz.asc","type":"tar","architecture":"arm64","os":["linux"]},"elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent-complete","repo":"docker.elastic.co"}},"elastic-agent-8.6.0-darwin-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["darwin"]},"elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["linux"]},"elastic-agent-8.6.0-amd64.deb":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-amd64.deb","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-amd64.deb.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-amd64.deb.asc","type":"deb","architecture":"amd64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-shipper-8.6.0-windows-x86.zip":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86.zip","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86.zip.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86.zip.asc","type":"zip","architecture":"x86","os":["windows"]},"elastic-agent-8.6.0-darwin-aarch64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-aarch64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-aarch64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-aarch64.tar.gz.asc","type":"tar","architecture":"aarch64","os":["darwin"]},"elastic-agent-shipper-8.6.0-linux-x86.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86.tar.gz.asc","type":"tar","architecture":"x86","os":["linux"]},"elastic-agent-8.6.0-linux-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["linux"]},"elastic-agent-8.6.0-aarch64.rpm":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-aarch64.rpm","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-aarch64.rpm.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-aarch64.rpm.asc","type":"rpm","architecture":"aarch64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent","repo":"docker.elastic.co"}},"elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz.asc","type":"docker","architecture":"arm64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats-ci","url":"docker.elastic.co/beats-ci/elastic-agent-cloud","repo":"docker.elastic.co"}}},"manifests":{"last-update-time":"Thu, 09 Mar 2023 20:59:39 UTC","seconds-since-last-update":89}}` - binaryResponse := "not valid data; but its very fast to download something this small" - hashResponse := "c2f59774022b79b61a7e6bbe28f3388d00a5bc2c7416a5c8fda79042af491d335f9b87adf905d1b154abdd2e31b200e4b1bb23cb472297596b25edef0a3b8d59" - fakeClient := &fakeHttpClient{responses: []*http.Response{ - { - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader([]byte(artifactsResponse))), - }, - { - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader([]byte(binaryResponse))), - }, - { - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader([]byte(hashResponse))), - }, - }} - f := ArtifactFetcher() af := f.(*artifactFetcher) - af.doer = fakeClient + af.doer = newFakeHttpClient() tmp := t.TempDir() res, err := f.Fetch(context.Background(), runtime.GOOS, runtime.GOARCH, "8.6.0") @@ -55,38 +36,14 @@ func TestArtifactFetcher_Default(t *testing.T) { require.NoError(t, err) _, err = os.Stat(filepath.Join(tmp, res.Name())) require.NoError(t, err) - _, err = os.Stat(filepath.Join(tmp, res.Name()+hashExt)) + _, err = os.Stat(filepath.Join(tmp, res.Name()+extHash)) require.NoError(t, err) } func TestArtifactFetcher_SnapshotOnly(t *testing.T) { - artifactsResponse := `{"packages":{"elastic-agent-8.8.0-SNAPSHOT-arm64.deb":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-arm64.deb","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-arm64.deb.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-arm64.deb.asc","type":"deb","architecture":"arm64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86.zip":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86.zip","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86.zip.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86.zip.asc","type":"zip","architecture":"x86","os":["windows"]},"elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz.asc","type":"docker","architecture":"arm64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats-ci","url":"docker.elastic.co/beats-ci/elastic-agent-cloud","repo":"docker.elastic.co"}},"elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent","repo":"docker.elastic.co"}},"elastic-agent-8.8.0-SNAPSHOT-aarch64.rpm":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-aarch64.rpm","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-aarch64.rpm.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-aarch64.rpm.asc","type":"rpm","architecture":"aarch64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-8.8.0-SNAPSHOT-linux-x86_64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-linux-x86_64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-linux-x86_64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-linux-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["linux"]},"elastic-agent-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz.asc","type":"tar","architecture":"aarch64","os":["darwin"]},"elastic-agent-shipper-8.8.0-SNAPSHOT-linux-arm64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-arm64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-arm64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-arm64.tar.gz.asc","type":"tar","architecture":"arm64","os":["linux"]},"elastic-agent-8.8.0-SNAPSHOT-linux-arm64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-linux-arm64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-linux-arm64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-linux-arm64.tar.gz.asc","type":"tar","architecture":"arm64","os":["linux"]},"elastic-agent-complete-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-complete-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-complete-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-complete-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent-complete","repo":"docker.elastic.co"}},"elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-aarch64.tar.gz.asc","type":"tar","architecture":"aarch64","os":["darwin"]},"elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86.tar.gz.asc","type":"tar","architecture":"x86","os":["linux"]},"elastic-agent-8.8.0-SNAPSHOT-amd64.deb":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-amd64.deb","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-amd64.deb.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-amd64.deb.asc","type":"deb","architecture":"amd64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-8.8.0-SNAPSHOT-x86_64.rpm":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-x86_64.rpm","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-x86_64.rpm.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-x86_64.rpm.asc","type":"rpm","architecture":"x86_64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86_64.zip":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86_64.zip","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86_64.zip.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-windows-x86_64.zip.asc","type":"zip","architecture":"x86_64","os":["windows"]},"elastic-agent-ironbank-8.8.0-SNAPSHOT-docker-build-context.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-ironbank-8.8.0-SNAPSHOT-docker-build-context.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-ironbank-8.8.0-SNAPSHOT-docker-build-context.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-ironbank-8.8.0-SNAPSHOT-docker-build-context.tar.gz.asc","type":"docker","classifier":"docker-build-context","attributes":{"artifactNoKpi":"true","internal":"false","url":"null/null/elastic-agent-ironbank"}},"elastic-agent-ubi8-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-ubi8-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-ubi8-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-ubi8-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent-ubi8","repo":"docker.elastic.co"}},"elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-cloud-8.8.0-SNAPSHOT-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats-ci","url":"docker.elastic.co/beats-ci/elastic-agent-cloud","repo":"docker.elastic.co"}},"elastic-agent-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["darwin"]},"elastic-agent-8.8.0-SNAPSHOT-windows-x86_64.zip":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-windows-x86_64.zip","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-windows-x86_64.zip.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-windows-x86_64.zip.asc","type":"zip","architecture":"x86_64","os":["windows"]},"elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86_64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86_64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86_64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-linux-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["linux"]},"elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/elastic-agent-shipper/elastic-agent-shipper-8.8.0-SNAPSHOT-darwin-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["darwin"]},"elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz":{"url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz","sha_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz.sha512","asc_url":"https://snapshots.elastic.co/8.8.0-ba3f07b2/downloads/beats/elastic-agent/elastic-agent-8.8.0-SNAPSHOT-docker-image-linux-arm64.tar.gz.asc","type":"docker","architecture":"arm64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent","repo":"docker.elastic.co"}}},"manifests":{"last-update-time":"Thu, 09 Mar 2023 20:59:39 UTC","seconds-since-last-update":221}}` - binaryResponse := "not valid data; but its very fast to download something this small" - hashResponse := "c2f59774022b79b61a7e6bbe28f3388d00a5bc2c7416a5c8fda79042af491d335f9b87adf905d1b154abdd2e31b200e4b1bb23cb472297596b25edef0a3b8d59" - fakeClient := &fakeHttpClient{responses: []*http.Response{ - { - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader([]byte(artifactsResponse))), - }, - { - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader([]byte(binaryResponse))), - Header: map[string][]string{ - "Content-Length": []string{strconv.Itoa(len(binaryResponse))}, - }, - }, - { - StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewReader([]byte(hashResponse))), - Header: map[string][]string{ - "Content-Length": []string{strconv.Itoa(len(hashResponse))}, - }, - }, - }} - f := ArtifactFetcher(WithArtifactSnapshotOnly()) af := f.(*artifactFetcher) - af.doer = fakeClient + af.doer = newFakeHttpClient() tmp := t.TempDir() res, err := f.Fetch(context.Background(), runtime.GOOS, runtime.GOARCH, "8.6.0") @@ -96,7 +53,7 @@ func TestArtifactFetcher_SnapshotOnly(t *testing.T) { require.NoError(t, err) _, err = os.Stat(filepath.Join(tmp, res.Name())) require.NoError(t, err) - _, err = os.Stat(filepath.Join(tmp, res.Name()+hashExt)) + _, err = os.Stat(filepath.Join(tmp, res.Name()+extHash)) require.NoError(t, err) assert.Contains(t, res.Name(), "-SNAPSHOT") } @@ -105,7 +62,43 @@ type fakeHttpClient struct { responses []*http.Response } -func (c *fakeHttpClient) Do(_ *http.Request) (resp *http.Response, err error) { - resp, c.responses = c.responses[0], c.responses[1:] - return +func (c *fakeHttpClient) Do(_ *http.Request) (*http.Response, error) { + resp := c.responses[0] + c.responses = c.responses[1:] + return resp, nil +} + +func newFakeHttpClient() *fakeHttpClient { + artifactsResponse := `{"packages":{"elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ironbank-8.6.0-docker-build-context.tar.gz.asc","type":"docker","classifier":"docker-build-context","attributes":{"artifactNoKpi":"true","internal":"false","url":"null/null/elastic-agent-ironbank"}},"elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["darwin"]},"elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats-ci","url":"docker.elastic.co/beats-ci/elastic-agent-cloud","repo":"docker.elastic.co"}},"elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-ubi8-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent-ubi8","repo":"docker.elastic.co"}},"elastic-agent-8.6.0-x86_64.rpm":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-x86_64.rpm","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-x86_64.rpm.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-x86_64.rpm.asc","type":"rpm","architecture":"x86_64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-8.6.0-windows-x86_64.zip":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-windows-x86_64.zip","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-windows-x86_64.zip.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-windows-x86_64.zip.asc","type":"zip","architecture":"x86_64","os":["windows"]},"elastic-agent-8.6.0-arm64.deb":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-arm64.deb","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-arm64.deb.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-arm64.deb.asc","type":"deb","architecture":"arm64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-shipper-8.6.0-windows-x86_64.zip":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86_64.zip","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86_64.zip.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86_64.zip.asc","type":"zip","architecture":"x86_64","os":["windows"]},"elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-darwin-aarch64.tar.gz.asc","type":"tar","architecture":"aarch64","os":["darwin"]},"elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-arm64.tar.gz.asc","type":"docker","architecture":"arm64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent","repo":"docker.elastic.co"}},"elastic-agent-8.6.0-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-arm64.tar.gz.asc","type":"tar","architecture":"arm64","os":["linux"]},"elastic-agent-shipper-8.6.0-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-arm64.tar.gz.asc","type":"tar","architecture":"arm64","os":["linux"]},"elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-complete-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent-complete","repo":"docker.elastic.co"}},"elastic-agent-8.6.0-darwin-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["darwin"]},"elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["linux"]},"elastic-agent-8.6.0-amd64.deb":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-amd64.deb","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-amd64.deb.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-amd64.deb.asc","type":"deb","architecture":"amd64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-shipper-8.6.0-windows-x86.zip":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86.zip","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86.zip.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-windows-x86.zip.asc","type":"zip","architecture":"x86","os":["windows"]},"elastic-agent-8.6.0-darwin-aarch64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-aarch64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-aarch64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-darwin-aarch64.tar.gz.asc","type":"tar","architecture":"aarch64","os":["darwin"]},"elastic-agent-shipper-8.6.0-linux-x86.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/elastic-agent-shipper/elastic-agent-shipper-8.6.0-linux-x86.tar.gz.asc","type":"tar","architecture":"x86","os":["linux"]},"elastic-agent-8.6.0-linux-x86_64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-x86_64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-x86_64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-linux-x86_64.tar.gz.asc","type":"tar","architecture":"x86_64","os":["linux"]},"elastic-agent-8.6.0-aarch64.rpm":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-aarch64.rpm","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-aarch64.rpm.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-aarch64.rpm.asc","type":"rpm","architecture":"aarch64","attributes":{"include_in_repo":"true","oss":"false"}},"elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-8.6.0-docker-image-linux-amd64.tar.gz.asc","type":"docker","architecture":"amd64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats","url":"docker.elastic.co/beats/elastic-agent","repo":"docker.elastic.co"}},"elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz":{"url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz","sha_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz.sha512","asc_url":"https://staging.elastic.co/8.6.0-b6c773f9/downloads/beats/elastic-agent/elastic-agent-cloud-8.6.0-docker-image-linux-arm64.tar.gz.asc","type":"docker","architecture":"arm64","os":["linux"],"classifier":"docker-image","attributes":{"artifactNoKpi":"true","internal":"false","org":"beats-ci","url":"docker.elastic.co/beats-ci/elastic-agent-cloud","repo":"docker.elastic.co"}}},"manifests":{"last-update-time":"Thu, 09 Mar 2023 20:59:39 UTC","seconds-since-last-update":89}}` + binaryResponse := "not valid data; but its very fast to download something this small" + hashResponse := "c2f59774022b79b61a7e6bbe28f3388d00a5bc2c7416a5c8fda79042af491d335f9b87adf905d1b154abdd2e31b200e4b1bb23cb472297596b25edef0a3b8d59" + ascResponse := `-----BEGIN PGP SIGNATURE----- + + wsBcBAABCAAQBQJlTLh5CRD2Vuvax5DnywAAzNcIADKuYov0CMeK938JQEzR4mXP + BoYB7Zz/IkN7A5mMztRnHi1eglr2/begM22AmC5L55OsYG5orNWV83MQPeKIr5Ub + 9gy/BktLAQTePNH6QvRzJKE3LR1pI2TT39svILoOjnPkovH/7ssa6X+/WcNE1/jX + i7St7ZCDRZgDcmWtln7feDcYT7MdMUaQn+WP97KKbwIBTh9kOkHq9ycXnC6qT0/3 + GZT9xXTpBjctewSFja4RNCq8cmZGI2iILzFERH6MSD0iOuBV5cYKOgf/ZWtWGvad + BuQTKP/NxCDmqhnEmJQi7BSP2UPNp+6/G8a38IyC/jlJs/f46fj+lpvQt3yn924= + =fhCM + -----END PGP SIGNATURE-----` + return &fakeHttpClient{responses: []*http.Response{ + { + StatusCode: 200, + Body: io.NopCloser(bytes.NewReader([]byte(artifactsResponse))), + }, + { + StatusCode: 200, + Body: io.NopCloser(bytes.NewReader([]byte(binaryResponse))), + }, + { + StatusCode: 200, + Body: io.NopCloser(bytes.NewReader([]byte(hashResponse))), + }, + { + StatusCode: 200, + Body: io.NopCloser(bytes.NewReader([]byte(ascResponse))), + }, + }} + } diff --git a/pkg/testing/fetcher_local.go b/pkg/testing/fetcher_local.go index 214e63c43a7..6a41d254a16 100644 --- a/pkg/testing/fetcher_local.go +++ b/pkg/testing/fetcher_local.go @@ -107,7 +107,7 @@ func (r *localFetcherResult) Fetch(_ context.Context, _ Logger, dir string) erro } // fetch artifact hash - err = copyFile(fullPath+hashExt, path+hashExt) + err = copyFile(fullPath+extHash, path+extHash) if err != nil { return fmt.Errorf("error copying file: %w", err) } diff --git a/pkg/testing/fetcher_local_test.go b/pkg/testing/fetcher_local_test.go index a97c5db1c9e..d9b6f3d7ca0 100644 --- a/pkg/testing/fetcher_local_test.go +++ b/pkg/testing/fetcher_local_test.go @@ -35,11 +35,11 @@ func TestLocalFetcher(t *testing.T) { snapshotPath := fmt.Sprintf("elastic-agent-%s-SNAPSHOT-%s", baseVersion, suffix) require.NoError(t, os.WriteFile(filepath.Join(testdata, snapshotPath), snapshotContent, 0644)) - snapshotPathHash := fmt.Sprintf("elastic-agent-%s-SNAPSHOT-%s%s", baseVersion, suffix, hashExt) + snapshotPathHash := fmt.Sprintf("elastic-agent-%s-SNAPSHOT-%s%s", baseVersion, suffix, extHash) require.NoError(t, os.WriteFile(filepath.Join(testdata, snapshotPathHash), snapshotContentHash, 0644)) notSnapshotPath := fmt.Sprintf("elastic-agent-%s-%s", baseVersion, suffix) require.NoError(t, os.WriteFile(filepath.Join(testdata, notSnapshotPath), noSnapshotContent, 0644)) - notSnapshotPathHash := fmt.Sprintf("elastic-agent-%s-%s%s", baseVersion, suffix, hashExt) + notSnapshotPathHash := fmt.Sprintf("elastic-agent-%s-%s%s", baseVersion, suffix, extHash) require.NoError(t, os.WriteFile(filepath.Join(testdata, notSnapshotPathHash), noSnapshotContentHash, 0644)) tcs := []struct { @@ -88,7 +88,7 @@ func TestLocalFetcher(t *testing.T) { require.NoError(t, err) assert.Equal(t, string(tc.want), string(content)) - contentHash, err := os.ReadFile(filepath.Join(tmp, got.Name()+hashExt)) + contentHash, err := os.ReadFile(filepath.Join(tmp, got.Name()+extHash)) require.NoError(t, err) assert.Equal(t, string(tc.wantHash), string(contentHash)) diff --git a/pkg/testing/fixture.go b/pkg/testing/fixture.go index 3774808efaa..72c69cdf404 100644 --- a/pkg/testing/fixture.go +++ b/pkg/testing/fixture.go @@ -537,7 +537,7 @@ type ExecErr struct { } func (e *ExecErr) Error() string { - return e.err.Error() + return e.String() } func (e *ExecErr) String() string { diff --git a/pkg/testing/fixture_install.go b/pkg/testing/fixture_install.go index 923356779e9..965d490ef64 100644 --- a/pkg/testing/fixture_install.go +++ b/pkg/testing/fixture_install.go @@ -144,7 +144,7 @@ func (f *Fixture) Install(ctx context.Context, installOpts *InstallOpts, opts .. f.collectDiagnostics() } - // environment variable AGENT_KEEP_INSTALLED=true will skip the uninstall + // environment variable AGENT_KEEP_INSTALLED=true will skip the uninstallation // useful to debug the issue with the Elastic Agent if f.t.Failed() && keepInstalledFlag() { f.t.Logf("skipping uninstall; test failed and AGENT_KEEP_INSTALLED=true") diff --git a/pkg/testing/multipass/provisioner.go b/pkg/testing/multipass/provisioner.go index 43a18987ce0..72267d0dd8f 100644 --- a/pkg/testing/multipass/provisioner.go +++ b/pkg/testing/multipass/provisioner.go @@ -158,14 +158,9 @@ func (p *provisioner) launch(ctx context.Context, cfg runner.Config, batch runne return fmt.Errorf("failed to marshal cloud-init configuration: %w", err) } - p.logger.Logf("Launching multipass instance %s", batch.ID) var output bytes.Buffer - proc, err := process.Start("multipass", - process.WithContext(ctx), - process.WithArgs(args), - process.WithCmdOptions( - runner.AttachOut(&output), - runner.AttachErr(&output))) + p.logger.Logf("Launching multipass image %s", batch.ID) + proc, err := process.Start("multipass", process.WithContext(ctx), process.WithArgs(args), process.WithCmdOptions(runner.AttachOut(&output), runner.AttachErr(&output))) if err != nil { return fmt.Errorf("failed to run multipass launch: %w", err) } diff --git a/pkg/testing/ogc/provisioner.go b/pkg/testing/ogc/provisioner.go index 00a05459881..54054d27bca 100644 --- a/pkg/testing/ogc/provisioner.go +++ b/pkg/testing/ogc/provisioner.go @@ -79,7 +79,7 @@ func (p *provisioner) Provision(ctx context.Context, cfg runner.Config, batches defer upCancel() upOutput, err := p.ogcUp(upCtx) if err != nil { - return nil, err + return nil, fmt.Errorf("ogc up failed: %w", err) } // fetch the machines and run the batches on the machine @@ -100,8 +100,8 @@ func (p *provisioner) Provision(ctx context.Context, cfg runner.Config, batches for _, b := range batches { machine, ok := findMachine(machines, b.ID) if !ok { - // print the output so its clear what went wrong - // without this it's unclear where OGC went wrong it + // print the output so its clear what went wrong. + // Without this it's unclear where OGC went wrong, it // doesn't do a great job of reporting a clean error fmt.Fprintf(os.Stdout, "%s\n", upOutput) return nil, fmt.Errorf("failed to find machine for batch ID: %s", b.ID) diff --git a/pkg/testing/runner/provisioner.go b/pkg/testing/runner/provisioner.go index 7a27ad6697b..37ec7dd0c5c 100644 --- a/pkg/testing/runner/provisioner.go +++ b/pkg/testing/runner/provisioner.go @@ -12,6 +12,9 @@ import ( // Instance represents a provisioned instance. type Instance struct { + // Provider is the instance provider for the instance. + // See INSTANCE_PROVISIONER environment variable for the supported providers. + Provider string `yaml:"provider"` // ID is the identifier of the instance. // // This must be the same ID of the OSBatch. diff --git a/pkg/testing/runner/runner_test.go b/pkg/testing/runner/runner_test.go index c638b291bd4..8eaf9239af8 100644 --- a/pkg/testing/runner/runner_test.go +++ b/pkg/testing/runner/runner_test.go @@ -99,19 +99,19 @@ type fakeInstanceProvisioner struct { instances []Instance } -func (f *fakeInstanceProvisioner) Name() string { +func (p *fakeInstanceProvisioner) Name() string { return "fake" } -func (f *fakeInstanceProvisioner) SetLogger(_ Logger) { +func (p *fakeInstanceProvisioner) SetLogger(_ Logger) { } -func (f *fakeInstanceProvisioner) Supported(_ define.OS) bool { +func (p *fakeInstanceProvisioner) Supported(_ define.OS) bool { return true } -func (f *fakeInstanceProvisioner) Provision(_ context.Context, _ Config, batches []OSBatch) ([]Instance, error) { - f.batches = batches +func (p *fakeInstanceProvisioner) Provision(_ context.Context, _ Config, batches []OSBatch) ([]Instance, error) { + p.batches = batches var instances []Instance for _, batch := range batches { instances = append(instances, Instance{ @@ -126,8 +126,8 @@ func (f *fakeInstanceProvisioner) Provision(_ context.Context, _ Config, batches return instances, nil } -func (f *fakeInstanceProvisioner) Clean(_ context.Context, _ Config, instances []Instance) error { - f.instances = instances +func (p *fakeInstanceProvisioner) Clean(_ context.Context, _ Config, instances []Instance) error { + p.instances = instances return nil } @@ -137,17 +137,17 @@ type fakeStackProvisioner struct { deletedStacks []Stack } -func (f *fakeStackProvisioner) Name() string { +func (p *fakeStackProvisioner) Name() string { return "fake" } -func (f *fakeStackProvisioner) SetLogger(_ Logger) { +func (p *fakeStackProvisioner) SetLogger(_ Logger) { } -func (f *fakeStackProvisioner) Create(_ context.Context, request StackRequest) (Stack, error) { - f.mx.Lock() - defer f.mx.Unlock() - f.requests = append(f.requests, request) +func (p *fakeStackProvisioner) Create(_ context.Context, request StackRequest) (Stack, error) { + p.mx.Lock() + defer p.mx.Unlock() + p.requests = append(p.requests, request) return Stack{ ID: request.ID, Version: request.Version, @@ -160,14 +160,14 @@ func (f *fakeStackProvisioner) Create(_ context.Context, request StackRequest) ( }, nil } -func (f *fakeStackProvisioner) WaitForReady(_ context.Context, stack Stack) (Stack, error) { +func (p *fakeStackProvisioner) WaitForReady(_ context.Context, stack Stack) (Stack, error) { stack.Ready = true return stack, nil } -func (f *fakeStackProvisioner) Delete(_ context.Context, stack Stack) error { - f.mx.Lock() - defer f.mx.Unlock() - f.deletedStacks = append(f.deletedStacks, stack) +func (p *fakeStackProvisioner) Delete(_ context.Context, stack Stack) error { + p.mx.Lock() + defer p.mx.Unlock() + p.deletedStacks = append(p.deletedStacks, stack) return nil } diff --git a/pkg/testing/tools/artifacts_api.go b/pkg/testing/tools/artifacts_api.go index bbf79eab032..8af95a645f6 100644 --- a/pkg/testing/tools/artifacts_api.go +++ b/pkg/testing/tools/artifacts_api.go @@ -244,7 +244,7 @@ type logger interface { Logf(format string, args ...any) } -func GetLatestSnapshotVersion(ctx context.Context, log logger, aac *ArtifactAPIClient) (*version.ParsedSemVer, error) { +func (aac ArtifactAPIClient) GetLatestSnapshotVersion(ctx context.Context, log logger) (*version.ParsedSemVer, error) { vList, err := aac.GetVersions(ctx) if err != nil { return nil, err diff --git a/pkg/testing/tools/fleettools/fleet.go b/pkg/testing/tools/fleettools/fleet.go index 77c64069e41..ff482eedc01 100644 --- a/pkg/testing/tools/fleettools/fleet.go +++ b/pkg/testing/tools/fleettools/fleet.go @@ -21,6 +21,7 @@ func GetAgentByPolicyIDAndHostnameFromList(client *kibana.Client, policyID, host return nil, err } + var agentHostnames []string hostnameAgents := make([]*kibana.AgentExisting, 0) for i, item := range listAgentsResp.Items { agentHostname := item.LocalMetadata.Host.Hostname @@ -32,7 +33,8 @@ func GetAgentByPolicyIDAndHostnameFromList(client *kibana.Client, policyID, host } if len(hostnameAgents) == 0 { - return nil, fmt.Errorf("unable to find agent with hostname [%s]", hostname) + return nil, fmt.Errorf("unable to find agent with hostname [%s] for policy [%s]. Found: %v", + hostname, policyID, agentHostnames) } if len(hostnameAgents) > 1 { diff --git a/testing/integration/upgrade_downgrade_test.go b/testing/integration/upgrade_downgrade_test.go index 0fa42552340..ef4afd4ae41 100644 --- a/testing/integration/upgrade_downgrade_test.go +++ b/testing/integration/upgrade_downgrade_test.go @@ -40,7 +40,7 @@ func TestStandaloneDowngradeToSpecificSnapshotBuild(t *testing.T) { // retrieve all the versions of agent from the artifact API aac := tools.NewArtifactAPIClient() - latestSnapshotVersion, err := tools.GetLatestSnapshotVersion(ctx, t, aac) + latestSnapshotVersion, err := aac.GetLatestSnapshotVersion(ctx, t) require.NoError(t, err) // get all the builds of the snapshot version (need to pass x.y.z-SNAPSHOT format) diff --git a/testing/integration/upgrade_fleet_test.go b/testing/integration/upgrade_fleet_test.go index 9c44386eb87..8d4f3b3c88d 100644 --- a/testing/integration/upgrade_fleet_test.go +++ b/testing/integration/upgrade_fleet_test.go @@ -8,7 +8,15 @@ package integration import ( "context" + "errors" + "fmt" + "net" + "net/http" + "net/http/httptest" "os" + "os/exec" + "path/filepath" + "runtime" "strings" "testing" "time" @@ -18,11 +26,12 @@ import ( "github.com/stretchr/testify/require" "github.com/elastic/elastic-agent-libs/kibana" - "github.com/elastic/elastic-agent/pkg/testing/tools/check" - "github.com/elastic/elastic-agent/pkg/testing/tools/fleettools" - atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools" + "github.com/elastic/elastic-agent/pkg/testing/tools/check" + "github.com/elastic/elastic-agent/pkg/testing/tools/fleettools" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/pkg/version" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -62,20 +71,112 @@ func TestFleetManagedUpgrade(t *testing.T) { atesting.WithFetcher(atesting.ArtifactFetcher()), ) require.NoError(t, err) + err = endFixture.Prepare(ctx) require.NoError(t, err) + endVersionInfo, err := endFixture.ExecVersion(ctx) require.NoError(t, err) - if startVersionInfo.Binary.String() == endVersionInfo.Binary.String() && startVersionInfo.Binary.Commit == endVersionInfo.Binary.Commit { - t.Skipf("Build under test is the same as the build from the artifacts repository (version: %s) [commit: %s]", startVersionInfo.Binary.String(), startVersionInfo.Binary.Commit) + if startVersionInfo.Binary.String() == endVersionInfo.Binary.String() && + startVersionInfo.Binary.Commit == endVersionInfo.Binary.Commit { + t.Skipf("Build under test is the same as the build from the artifacts repository (version: %s) [commit: %s]", + startVersionInfo.Binary.String(), startVersionInfo.Binary.Commit) + } + + t.Logf("Testing Elastic Agent upgrade from %s to %s with Fleet...", + define.Version(), endVersionInfo.Binary.String()) + + testUpgradeFleetManagedElasticAgent(ctx, t, info, startFixture, endFixture, defaultPolicy()) +} + +func TestFleetAirGappedUpgrade(t *testing.T) { + stack := define.Require(t, define.Requirements{ + Stack: &define.Stack{}, + // The test uses iptables to simulate the air-gaped environment. + OS: []define.OS{{Type: define.Linux}}, + Isolate: true, // Needed as the test blocks IPs using iptables. + Local: false, // Needed as the test requires Agent installation + Sudo: true, // Needed as the test uses iptables and installs the Agent + }) + + ctx, _ := testcontext.WithDeadline( + t, context.Background(), time.Now().Add(10*time.Minute)) + + artifactAPI := tools.NewArtifactAPIClient() + latest, err := artifactAPI.GetLatestSnapshotVersion(ctx, t) + require.NoError(t, err, "could not fetch latest version from artifacts API") + + // We need to prepare it first because it'll download the artifact, and it + // has to happen before we block the artifacts API IPs. + // The test does not need a fixture, but testUpgradeFleetManagedElasticAgent + // uses it to get some information about the agent version. + upgradeTo, err := atesting.NewFixture( + t, + latest.String(), + atesting.WithFetcher(atesting.ArtifactFetcher()), + ) + require.NoError(t, err) + err = upgradeTo.Prepare(ctx) + require.NoError(t, err) + + s := newArtifactsServer(ctx, t, latest.String()) + host := "artifacts.elastic.co" + simulateAirGapedEnvironment(t, host) + + rctx, cancel := context.WithTimeout(ctx, time.Second) + defer cancel() + req, err := http.NewRequestWithContext(rctx, http.MethodGet, "https://"+host, nil) + _, err = http.DefaultClient.Do(req) + if !(errors.Is(err, context.DeadlineExceeded) || + errors.Is(err, os.ErrDeadlineExceeded)) { + t.Fatalf( + "request to %q should have failed, iptables rules should have blocked it", + host) + } + + _, err = stack.ESClient.Info() + require.NoErrorf(t, err, + "failed to interact with ES after blocking %q through iptables", host) + _, body, err := stack.KibanaClient.Request(http.MethodGet, "/api/features", + nil, nil, nil) + require.NoErrorf(t, err, + "failed to interact with Kibana after blocking %q through iptables. "+ + "It should not affect the connection to the stack. Host: %s, response body: %s", + stack.KibanaClient.URL, host, body) + + fixture, err := define.NewFixture(t, define.Version()) + require.NoError(t, err) + err = fixture.Prepare(ctx) + require.NoError(t, err) + + t.Logf("Testing Elastic Agent upgrade from %s to %s with Fleet...", + define.Version(), latest) + + downloadSource := kibana.DownloadSource{ + Name: "local-air-gaped-" + uuid.NewString(), + Host: s.URL + "/downloads/beats/elastic-agent/", + IsDefault: false, // other tests reuse the stack, let's not mess things up } + t.Logf("creating download source %q, using %q.", + downloadSource.Name, downloadSource.Host) + src, err := stack.KibanaClient.CreateDownloadSource(ctx, downloadSource) + require.NoError(t, err, "could not create download source") - t.Logf("Testing Elastic Agent upgrade from %s to %s with Fleet...", define.Version(), endVersionInfo.Binary.String()) + policy := defaultPolicy() + policy.DownloadSourceID = src.Item.ID - testUpgradeFleetManagedElasticAgent(ctx, t, info, startFixture, endFixture) + testUpgradeFleetManagedElasticAgent(ctx, t, stack, fixture, upgradeTo, policy) } -func testUpgradeFleetManagedElasticAgent(ctx context.Context, t *testing.T, info *define.Info, startFixture *atesting.Fixture, endFixture *atesting.Fixture) { +func testUpgradeFleetManagedElasticAgent( + ctx context.Context, + t *testing.T, + info *define.Info, + startFixture *atesting.Fixture, + endFixture *atesting.Fixture, + policy kibana.AgentPolicy) { + kibClient := info.KibanaClient + startVersionInfo, err := startFixture.ExecVersion(ctx) require.NoError(t, err) startParsedVersion, err := version.ParseVersion(startVersionInfo.Binary.String()) @@ -83,34 +184,23 @@ func testUpgradeFleetManagedElasticAgent(ctx context.Context, t *testing.T, info endVersionInfo, err := endFixture.ExecVersion(ctx) require.NoError(t, err) - kibClient := info.KibanaClient - policyUUID := uuid.New().String() - t.Log("Creating Agent policy...") - createPolicyReq := kibana.AgentPolicy{ - Name: "test-policy-" + policyUUID, - Namespace: "default", - Description: "Test policy " + policyUUID, - MonitoringEnabled: []kibana.MonitoringEnabledOption{ - kibana.MonitoringEnabledLogs, - kibana.MonitoringEnabledMetrics, - }, - } - policy, err := kibClient.CreatePolicy(ctx, createPolicyReq) - require.NoError(t, err) + policyResp, err := kibClient.CreatePolicy(ctx, policy) + require.NoError(t, err, "failed creating policy") + policy = policyResp.AgentPolicy t.Log("Creating Agent enrollment API key...") createEnrollmentApiKeyReq := kibana.CreateEnrollmentAPIKeyRequest{ - PolicyID: policy.ID, + PolicyID: policyResp.ID, } enrollmentToken, err := kibClient.CreateEnrollmentAPIKey(ctx, createEnrollmentApiKeyReq) - require.NoError(t, err) + require.NoError(t, err, "failed creating enrollment API key") t.Log("Getting default Fleet Server URL...") fleetServerURL, err := fleettools.DefaultURL(kibClient) - require.NoError(t, err) + require.NoError(t, err, "failed getting Fleet Server URL") - t.Log("Enrolling Elastic Agent...") + t.Log("Installing Elastic Agent...") var nonInteractiveFlag bool if upgradetest.Version_8_2_0.Less(*startParsedVersion) { nonInteractiveFlag = true @@ -125,35 +215,41 @@ func testUpgradeFleetManagedElasticAgent(ctx context.Context, t *testing.T, info } output, err := startFixture.Install(ctx, &installOpts) require.NoError(t, err, "failed to install start agent [output: %s]", string(output)) - t.Cleanup(func() { - t.Log("Un-enrolling Elastic Agent...") - assert.NoError(t, fleettools.UnEnrollAgent(info.KibanaClient, policy.ID)) - }) t.Log("Waiting for Agent to be correct version and healthy...") err = upgradetest.WaitHealthyAndVersion(ctx, startFixture, startVersionInfo.Binary, 2*time.Minute, 10*time.Second, t) require.NoError(t, err) t.Log("Waiting for enrolled Agent status to be online...") - require.Eventually(t, check.FleetAgentStatus(t, kibClient, policy.ID, "online"), 2*time.Minute, 10*time.Second, "Agent status is not online") + require.Eventually(t, + check.FleetAgentStatus( + t, kibClient, policyResp.ID, "online"), + 2*time.Minute, + 10*time.Second, + "Agent status is not online") - t.Logf("Upgrading from version %q to version %q...", startParsedVersion, endVersionInfo.Binary.String()) - err = fleettools.UpgradeAgent(kibClient, policy.ID, endVersionInfo.Binary.String(), true) + t.Logf("Upgrading from version \"%s-%s\" to version \"%s-%s\"...", + startParsedVersion, startVersionInfo.Binary.Commit, + endVersionInfo.Binary.String(), endVersionInfo.Binary.Commit) + err = fleettools.UpgradeAgent(kibClient, policyResp.ID, endVersionInfo.Binary.String(), true) require.NoError(t, err) t.Log("Waiting from upgrade details to show up in Fleet") hostname, err := os.Hostname() require.NoError(t, err) - require.Eventually(t, func() bool { - agent, err := fleettools.GetAgentByPolicyIDAndHostnameFromList(kibClient, policy.ID, hostname) + var agent *kibana.AgentExisting + require.Eventuallyf(t, func() bool { + agent, err = fleettools.GetAgentByPolicyIDAndHostnameFromList(kibClient, policy.ID, hostname) return err == nil && agent.UpgradeDetails != nil - - }, 5*time.Minute, time.Second) + }, + 5*time.Minute, time.Second, + "last error: %v. agent.UpgradeDetails: %s", + err, agentUpgradeDetailsString(agent)) // wait for the watcher to show up t.Logf("Waiting for upgrade watcher to start...") err = upgradetest.WaitForWatcher(ctx, 5*time.Minute, 10*time.Second) - require.NoError(t, err) + require.NoError(t, err, "upgrade watcher did not start") t.Logf("Upgrade watcher started") // wait for the agent to be healthy and correct version @@ -161,12 +257,12 @@ func testUpgradeFleetManagedElasticAgent(ctx context.Context, t *testing.T, info require.NoError(t, err) t.Log("Waiting for enrolled Agent status to be online...") - require.Eventually(t, check.FleetAgentStatus(t, kibClient, policy.ID, "online"), 10*time.Minute, 15*time.Second, "Agent status is not online") + require.Eventually(t, check.FleetAgentStatus(t, kibClient, policyResp.ID, "online"), 10*time.Minute, 15*time.Second, "Agent status is not online") // wait for version require.Eventually(t, func() bool { t.Log("Getting Agent version...") - newVersion, err := fleettools.GetAgentVersion(kibClient, policy.ID) + newVersion, err := fleettools.GetAgentVersion(kibClient, policyResp.ID) if err != nil { t.Logf("error getting agent version: %v", err) return false @@ -184,3 +280,107 @@ func testUpgradeFleetManagedElasticAgent(ctx context.Context, t *testing.T, info err = upgradetest.CheckHealthyAndVersion(ctx, startFixture, endVersionInfo.Binary) assert.NoError(t, err) } + +func defaultPolicy() kibana.AgentPolicy { + policyUUID := uuid.New().String() + + policy := kibana.AgentPolicy{ + Name: "test-policy-" + policyUUID, + Namespace: "default", + Description: "Test policy " + policyUUID, + MonitoringEnabled: []kibana.MonitoringEnabledOption{ + kibana.MonitoringEnabledLogs, + kibana.MonitoringEnabledMetrics, + }, + } + return policy +} + +// simulateAirGapedEnvironment uses iptables to block outgoing packages to the +// IPs (v4 and v6) associated with host. +func simulateAirGapedEnvironment(t *testing.T, host string) { + ips, err := net.LookupIP(host) + require.NoErrorf(t, err, "could not get IPs for host %q", host) + + // iptables -A OUTPUT -j DROP -d IP + t.Logf("found %v IPs for %q, blocking them...", ips, host) + var toCleanUp [][]string + const iptables = "iptables" + const ip6tables = "ip6tables" + var cmd string + for _, ip := range ips { + cmd = iptables + if ip.To4() == nil { + cmd = ip6tables + } + args := []string{"-A", "OUTPUT", "-j", "DROP", "-d", ip.String()} + + out, err := exec.Command( + cmd, args...). + CombinedOutput() + if err != nil { + fmt.Println("FAILED:", cmd, args) + fmt.Println(string(out)) + } + t.Logf("added iptables rule %v", args[1:]) + toCleanUp = append(toCleanUp, append([]string{cmd, "-D"}, args[1:]...)) + + // Just in case someone executes the test locally. + t.Logf("use \"%s -D %s\" to remove it", cmd, strings.Join(args[1:], " ")) + } + t.Cleanup(func() { + for _, c := range toCleanUp { + cmd := c[0] + args := c[1:] + + out, err := exec.Command( + cmd, args...). + CombinedOutput() + if err != nil { + fmt.Println("clean up FAILED:", cmd, args) + fmt.Println(string(out)) + } + } + }) +} + +func newArtifactsServer(ctx context.Context, t *testing.T, version string) *httptest.Server { + fileServerDir := t.TempDir() + downloadAt := filepath.Join(fileServerDir, "downloads", "beats", "elastic-agent", "beats", "elastic-agent") + err := os.MkdirAll(downloadAt, 0700) + require.NoError(t, err, "could not create directory structure for file server") + + fetcher := atesting.ArtifactFetcher() + fr, err := fetcher.Fetch(ctx, runtime.GOOS, runtime.GOARCH, version) + require.NoErrorf(t, err, "could not prepare fetcher to download agent %s", + version) + err = fr.Fetch(ctx, t, downloadAt) + require.NoError(t, err, "could not download agent %s", version) + + // it's useful for debugging + dl, err := os.ReadDir(downloadAt) + require.NoError(t, err) + var files []string + for _, d := range dl { + files = append(files, d.Name()) + } + fmt.Printf("ArtifactsServer root dir %q, served files %q\n", + fileServerDir, files) + + fs := http.FileServer(http.Dir(fileServerDir)) + + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fs.ServeHTTP(w, r) + })) +} + +func agentUpgradeDetailsString(a *kibana.AgentExisting) string { + if a == nil { + return "agent is NIL" + } + if a.UpgradeDetails == nil { + return "upgrade details is NIL" + } + + return fmt.Sprintf("%#v", *a.UpgradeDetails) +} diff --git a/testing/upgradetest/upgrader.go b/testing/upgradetest/upgrader.go index 93aeed622a5..1a89b40a50c 100644 --- a/testing/upgradetest/upgrader.go +++ b/testing/upgradetest/upgrader.go @@ -211,7 +211,7 @@ func PerformUpgrade( sourceURI := "file://" + filepath.Dir(srcPkg) upgradeCmdArgs = append(upgradeCmdArgs, "--source-uri", sourceURI) } else if *upgradeOpts.sourceURI != "" { - // specific ---source-uri + // specific --source-uri upgradeCmdArgs = append(upgradeCmdArgs, "--source-uri", *upgradeOpts.sourceURI) } @@ -298,16 +298,20 @@ func CheckHealthyAndVersion(ctx context.Context, f *atesting.Fixture, versionInf return err } if status.Info.Version != versionInfo.Version { - return fmt.Errorf("versions don't match: %s != %s", status.Info.Version, versionInfo.Version) + return fmt.Errorf("versions don't match: got %s, want %s", + status.Info.Version, versionInfo.Version) } if status.Info.Snapshot != versionInfo.Snapshot { - return fmt.Errorf("snapshots don't match: %t != %t", status.Info.Snapshot, versionInfo.Snapshot) + return fmt.Errorf("snapshots don't match: got %t, want %t", + status.Info.Snapshot, versionInfo.Snapshot) } if status.Info.Commit != versionInfo.Commit { - return fmt.Errorf("commits don't match: %s != %s", status.Info.Commit, versionInfo.Commit) + return fmt.Errorf("commits don't match: got %s, want %s", + status.Info.Commit, versionInfo.Commit) } if status.State != int(v2proto.State_HEALTHY) { - return fmt.Errorf("agent state is not healthy: got %d", status.State) + return fmt.Errorf("agent state is not healthy: got %d", + status.State) } return nil } @@ -334,16 +338,20 @@ func CheckHealthyAndVersion(ctx context.Context, f *atesting.Fixture, versionInf } if versionOut.Binary.Version != versionInfo.Version { - return fmt.Errorf("versions don't match: %s != %s", versionOut.Binary.Version, versionInfo.Version) + return fmt.Errorf("versions don't match: got %s, want %s", + versionOut.Binary.Version, versionInfo.Version) } if versionOut.Binary.Snapshot != versionInfo.Snapshot { - return fmt.Errorf("snapshots don't match: %t != %t", versionOut.Binary.Snapshot, versionInfo.Snapshot) + return fmt.Errorf("snapshots don't match: got %t, want %t", + versionOut.Binary.Snapshot, versionInfo.Snapshot) } if versionOut.Binary.Commit != versionInfo.Commit { - return fmt.Errorf("commits don't match: %s != %s", versionOut.Binary.Commit, versionInfo.Commit) + return fmt.Errorf("commits don't match: got %s, want %s", + versionOut.Binary.Commit, versionInfo.Commit) } if state.Status != v1client.Healthy { - return fmt.Errorf("agent state is not healthy: got %d", state.Status) + return fmt.Errorf("agent state is not healthy: got %d", + state.Status) } return nil }