From 55b01c668c274141909b61baeb397bbd457b809a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paolo=20Chil=C3=A0?= Date: Thu, 30 Nov 2023 21:39:11 +0100 Subject: [PATCH 1/2] Add check for deadline set in contexts passed to Fixture.Run() (#3849) * Add check for deadline set in contexts passed to Fixture.Run() This change adds a check on the contexts used by integration test fixture when calling `fixture.Run()`, failing the test if no deadline has been specified. This is to avoid having the test hanging on t.Run() when the state specified in the FSM are never reached. * Add timeouts to contexts in integration tests * fixup! Add timeouts to contexts in integration tests --- pkg/testing/fixture.go | 8 ++++ testing/integration/diagnostics_test.go | 9 ++-- testing/integration/endpoint_security_test.go | 8 ++-- testing/integration/fake_test.go | 3 +- testing/integration/fqdn_test.go | 9 ++-- testing/integration/install_test.go | 19 ++++++--- .../integration/install_unprivileged_test.go | 15 +++++-- testing/integration/logs_ingestion_test.go | 5 ++- testing/integration/package_version_test.go | 6 ++- testing/integration/pkgversion_common_test.go | 2 +- testing/integration/proxy_url_test.go | 41 +++++++++++++++---- .../upgrade_broken_package_test.go | 4 +- testing/integration/upgrade_downgrade_test.go | 4 +- testing/integration/upgrade_gpg_test.go | 6 ++- testing/integration/upgrade_rollback_test.go | 5 ++- .../upgrade_standalone_inprogress.go | 3 +- .../upgrade_standalone_retry_test.go | 4 +- .../integration/upgrade_standalone_test.go | 4 +- testing/integration/upgrade_uninstall_test.go | 3 +- 19 files changed, 112 insertions(+), 46 deletions(-) diff --git a/pkg/testing/fixture.go b/pkg/testing/fixture.go index 72c69cdf404..84fa94a3641 100644 --- a/pkg/testing/fixture.go +++ b/pkg/testing/fixture.go @@ -282,6 +282,10 @@ func (f *Fixture) RunBeat(ctx context.Context) error { return errors.New("RunBeat() can't be run against elastic-agent") } + if _, deadlineSet := ctx.Deadline(); !deadlineSet { + f.t.Fatal("Context passed to Fixture.RunBeat() has no deadline set.") + } + var err error err = f.EnsurePrepared(ctx) if err != nil { @@ -366,6 +370,10 @@ func (f *Fixture) RunBeat(ctx context.Context) error { // The `elastic-agent.yml` generated by `Fixture.Configure` is ignored // when `Run` is called. func (f *Fixture) Run(ctx context.Context, states ...State) error { + if _, deadlineSet := ctx.Deadline(); !deadlineSet { + f.t.Fatal("Context passed to Fixture.Run() has no deadline set.") + } + if f.binaryName != "elastic-agent" { return errors.New("Run() can only be used with elastic-agent, use RunBeat()") } diff --git a/testing/integration/diagnostics_test.go b/testing/integration/diagnostics_test.go index c56b89c3e9a..3f5fcdfaf95 100644 --- a/testing/integration/diagnostics_test.go +++ b/testing/integration/diagnostics_test.go @@ -16,6 +16,7 @@ import ( "path/filepath" "strings" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -24,6 +25,7 @@ import ( "github.com/elastic/elastic-agent/pkg/core/process" integrationtest "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" ) const diagnosticsArchiveGlobPattern = "elastic-agent-diagnostics-*.zip" @@ -95,7 +97,7 @@ func TestDiagnosticsOptionalValues(t *testing.T) { fixture, err := define.NewFixture(t, define.Version()) require.NoError(t, err) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() err = fixture.Prepare(ctx, fakeComponent, fakeShipper) require.NoError(t, err) @@ -121,14 +123,11 @@ func TestDiagnosticsCommand(t *testing.T) { f, err := define.NewFixture(t, define.Version()) require.NoError(t, err) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() err = f.Prepare(ctx, fakeComponent, fakeShipper) require.NoError(t, err) - ctx, cancel = context.WithCancel(context.Background()) - defer cancel() - err = f.Run(ctx, integrationtest.State{ Configure: simpleConfig2, AgentState: integrationtest.NewClientState(client.Healthy), diff --git a/testing/integration/endpoint_security_test.go b/testing/integration/endpoint_security_test.go index de326d1b45a..2338cd764e0 100644 --- a/testing/integration/endpoint_security_test.go +++ b/testing/integration/endpoint_security_test.go @@ -241,7 +241,7 @@ func testInstallAndUnenrollWithEndpointSecurity(t *testing.T, info *define.Info, Force: true, } - ctx, cn := context.WithCancel(context.Background()) + ctx, cn := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cn() policy, err := tools.InstallAgentWithPolicy(ctx, t, installOpts, fixture, info.KibanaClient, createPolicyReq) @@ -353,7 +353,7 @@ func testInstallWithEndpointSecurityAndRemoveEndpointIntegration(t *testing.T, i Force: true, } - ctx, cn := context.WithCancel(context.Background()) + ctx, cn := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cn() policy, err := tools.InstallAgentWithPolicy(ctx, t, installOpts, fixture, info.KibanaClient, createPolicyReq) @@ -497,7 +497,7 @@ func TestEndpointSecurityNonDefaultBasePath(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cn := context.WithCancel(context.Background()) + ctx, cn := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cn() // Get path to agent executable. @@ -527,7 +527,7 @@ func TestEndpointSecurityNonDefaultBasePath(t *testing.T) { pkgPolicyResp, err := installElasticDefendPackage(t, info, policyResp.ID) require.NoErrorf(t, err, "Policy Response was: %v", pkgPolicyResp) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() c := fixture.Client() diff --git a/testing/integration/fake_test.go b/testing/integration/fake_test.go index 2a17931f359..cf58ba11c4a 100644 --- a/testing/integration/fake_test.go +++ b/testing/integration/fake_test.go @@ -16,6 +16,7 @@ import ( "github.com/elastic/elastic-agent/pkg/control/v2/client" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" ) var simpleConfig1 = ` @@ -51,7 +52,7 @@ func TestFakeComponent(t *testing.T) { f, err := define.NewFixture(t, define.Version()) require.NoError(t, err) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() err = f.Prepare(ctx, fakeComponent, fakeShipper) require.NoError(t, err) diff --git a/testing/integration/fqdn_test.go b/testing/integration/fqdn_test.go index 4478de0c76b..f3f5712109b 100644 --- a/testing/integration/fqdn_test.go +++ b/testing/integration/fqdn_test.go @@ -27,6 +27,7 @@ import ( "github.com/elastic/elastic-agent/pkg/testing/define" "github.com/elastic/elastic-agent/pkg/testing/tools" "github.com/elastic/elastic-agent/pkg/testing/tools/fleettools" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/go-elasticsearch/v8" ) @@ -52,11 +53,13 @@ func TestFQDN(t *testing.T) { origEtcHosts, err := getEtcHosts() require.NoError(t, err) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + // Save original hostname so we can restore it at the end of each test - origHostname, err := getHostname(context.Background()) + origHostname, err := getHostname(ctx) require.NoError(t, err) - ctx := context.Background() kibClient := info.KibanaClient shortName := strings.ToLower(randStr(6)) @@ -93,7 +96,7 @@ func TestFQDN(t *testing.T) { assert.NoError(t, fleettools.UnEnrollAgent(info.KibanaClient, policy.ID)) t.Log("Restoring hostname...") - err := setHostname(context.Background(), origHostname, t.Log) + err := setHostname(ctx, origHostname, t.Log) require.NoError(t, err) t.Log("Restoring original /etc/hosts...") diff --git a/testing/integration/install_test.go b/testing/integration/install_test.go index 40df66b1d15..8e8407a9dd8 100644 --- a/testing/integration/install_test.go +++ b/testing/integration/install_test.go @@ -18,6 +18,7 @@ import ( atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/stretchr/testify/require" ) @@ -38,8 +39,11 @@ func TestInstallWithoutBasePath(t *testing.T) { fixture, err := define.NewFixture(t, define.Version()) require.NoError(t, err) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + // Prepare the Elastic Agent so the binary is extracted and ready to use. - err = fixture.Prepare(context.Background()) + err = fixture.Prepare(ctx) require.NoError(t, err) // Check that default base path is clean @@ -59,7 +63,7 @@ func TestInstallWithoutBasePath(t *testing.T) { // Run `elastic-agent install`. We use `--force` to prevent interactive // execution. - out, err := fixture.Install(context.Background(), &atesting.InstallOpts{Force: true}) + out, err := fixture.Install(ctx, &atesting.InstallOpts{Force: true}) if err != nil { t.Logf("install output: %s", out) require.NoError(t, err) @@ -67,7 +71,7 @@ func TestInstallWithoutBasePath(t *testing.T) { // Check that Agent was installed in default base path checkInstallSuccess(t, topPath) - t.Run("check agent package version", testAgentPackageVersion(context.Background(), fixture, true)) + t.Run("check agent package version", testAgentPackageVersion(ctx, fixture, true)) } func TestInstallWithBasePath(t *testing.T) { @@ -86,8 +90,11 @@ func TestInstallWithBasePath(t *testing.T) { fixture, err := define.NewFixture(t, define.Version()) require.NoError(t, err) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + // Prepare the Elastic Agent so the binary is extracted and ready to use. - err = fixture.Prepare(context.Background()) + err = fixture.Prepare(ctx) require.NoError(t, err) // Set up random temporary directory to serve as base path for Elastic Agent @@ -97,7 +104,7 @@ func TestInstallWithBasePath(t *testing.T) { // Run `elastic-agent install`. We use `--force` to prevent interactive // execution. - out, err := fixture.Install(context.Background(), &atesting.InstallOpts{ + out, err := fixture.Install(ctx, &atesting.InstallOpts{ BasePath: randomBasePath, Force: true, }) @@ -109,7 +116,7 @@ func TestInstallWithBasePath(t *testing.T) { // Check that Agent was installed in the custom base path topPath := filepath.Join(randomBasePath, "Elastic", "Agent") checkInstallSuccess(t, topPath) - t.Run("check agent package version", testAgentPackageVersion(context.Background(), fixture, true)) + t.Run("check agent package version", testAgentPackageVersion(ctx, fixture, true)) } func checkInstallSuccess(t *testing.T, topPath string) { diff --git a/testing/integration/install_unprivileged_test.go b/testing/integration/install_unprivileged_test.go index a2700870df8..a665a306659 100644 --- a/testing/integration/install_unprivileged_test.go +++ b/testing/integration/install_unprivileged_test.go @@ -23,6 +23,7 @@ import ( "github.com/elastic/elastic-agent/internal/pkg/agent/install" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" ) func TestInstallUnprivilegedWithoutBasePath(t *testing.T) { @@ -49,8 +50,11 @@ func TestInstallUnprivilegedWithoutBasePath(t *testing.T) { fixture, err := define.NewFixture(t, define.Version()) require.NoError(t, err) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + // Prepare the Elastic Agent so the binary is extracted and ready to use. - err = fixture.Prepare(context.Background()) + err = fixture.Prepare(ctx) require.NoError(t, err) // Check that default base path is clean @@ -70,7 +74,7 @@ func TestInstallUnprivilegedWithoutBasePath(t *testing.T) { // Run `elastic-agent install`. We use `--force` to prevent interactive // execution. - out, err := fixture.Install(context.Background(), &atesting.InstallOpts{Force: true, Unprivileged: true}) + out, err := fixture.Install(ctx, &atesting.InstallOpts{Force: true, Unprivileged: true}) if err != nil { t.Logf("install output: %s", out) require.NoError(t, err) @@ -103,8 +107,11 @@ func TestInstallUnprivilegedWithBasePath(t *testing.T) { fixture, err := define.NewFixture(t, define.Version()) require.NoError(t, err) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + // Prepare the Elastic Agent so the binary is extracted and ready to use. - err = fixture.Prepare(context.Background()) + err = fixture.Prepare(ctx) require.NoError(t, err) // Other test `TestInstallWithBasePath` uses a random directory for the base @@ -125,7 +132,7 @@ func TestInstallUnprivilegedWithBasePath(t *testing.T) { // Run `elastic-agent install`. We use `--force` to prevent interactive // execution. - out, err := fixture.Install(context.Background(), &atesting.InstallOpts{ + out, err := fixture.Install(ctx, &atesting.InstallOpts{ BasePath: basePath, Force: true, Unprivileged: true, diff --git a/testing/integration/logs_ingestion_test.go b/testing/integration/logs_ingestion_test.go index ff5c19f0405..74c19c81985 100644 --- a/testing/integration/logs_ingestion_test.go +++ b/testing/integration/logs_ingestion_test.go @@ -33,6 +33,7 @@ import ( "github.com/elastic/elastic-agent/pkg/testing/tools/check" "github.com/elastic/elastic-agent/pkg/testing/tools/estools" "github.com/elastic/elastic-agent/pkg/testing/tools/fleettools" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-transport-go/v8/elastictransport" ) @@ -43,7 +44,9 @@ func TestLogIngestionFleetManaged(t *testing.T) { Local: false, Sudo: true, }) - ctx := context.Background() + + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() agentFixture, err := define.NewFixture(t, define.Version()) require.NoError(t, err) diff --git a/testing/integration/package_version_test.go b/testing/integration/package_version_test.go index b2d560526f5..4280603fa97 100644 --- a/testing/integration/package_version_test.go +++ b/testing/integration/package_version_test.go @@ -10,6 +10,7 @@ import ( "context" "os" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -17,6 +18,7 @@ import ( "github.com/elastic/elastic-agent/pkg/control/v2/client" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/version" ) @@ -29,7 +31,7 @@ func TestPackageVersion(t *testing.T) { f, err := define.NewFixture(t, define.Version()) require.NoError(t, err) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() err = f.Prepare(ctx, fakeComponent, fakeShipper) require.NoError(t, err) @@ -93,7 +95,7 @@ func testAfterRemovingPkgVersionFiles(ctx context.Context, f *atesting.Fixture) } testf := func() error { // check the version returned by the running agent - stdout, stderr, processState := getAgentVersionOutput(t, f, context.Background(), false) + stdout, stderr, processState := getAgentVersionOutput(t, f, ctx, false) binaryActualVersion := unmarshalVersionOutput(t, stdout, "binary") assert.Equal(t, version.GetDefaultVersion(), binaryActualVersion, "binary version does not return default beat version when the package version file is missing") diff --git a/testing/integration/pkgversion_common_test.go b/testing/integration/pkgversion_common_test.go index 7269afce4c9..a8c4285eabc 100644 --- a/testing/integration/pkgversion_common_test.go +++ b/testing/integration/pkgversion_common_test.go @@ -43,7 +43,7 @@ func testAgentPackageVersion(ctx context.Context, f *integrationtest.Fixture, bi require.NotEmpty(t, pkgVersion, "elastic agent has been packaged with an empty package version") // check the version returned by the running agent - actualVersionBytes := getAgentVersion(t, f, context.Background(), binaryOnly) + actualVersionBytes := getAgentVersion(t, f, ctx, binaryOnly) actualVersion := unmarshalVersionOutput(t, actualVersionBytes, "binary") assert.Equal(t, pkgVersion, actualVersion, "binary version does not match package version") diff --git a/testing/integration/proxy_url_test.go b/testing/integration/proxy_url_test.go index c9ae99a248a..7a6672ae84f 100644 --- a/testing/integration/proxy_url_test.go +++ b/testing/integration/proxy_url_test.go @@ -20,6 +20,7 @@ import ( integrationtest "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" "github.com/elastic/elastic-agent/pkg/testing/tools/check" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/testing/fleetservertest" "github.com/elastic/elastic-agent/testing/proxytest" "github.com/elastic/elastic-agent/version" @@ -63,7 +64,7 @@ func SetupTest(t *testing.T) *ProxyURL { integrationtest.WithLogOutput()) require.NoError(t, err, "SetupTest: NewFixture failed") - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() err = f.Prepare(ctx) @@ -79,7 +80,10 @@ func TearDownTest(t *testing.T, p *ProxyURL) { return // nothing to do } - out, err := p.fixture.Uninstall(context.Background(), + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + + out, err := p.fixture.Uninstall(ctx, &integrationtest.UninstallOpts{Force: true}) if err != nil && !errors.Is(err, integrationtest.ErrNotInstalled) && @@ -115,8 +119,11 @@ func TestProxyURL_EnrollProxyAndNoProxyInThePolicy(t *testing.T) { action, ) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + out, err := p.fixture.Install( - context.Background(), + ctx, &integrationtest.InstallOpts{ Force: true, NonInteractive: true, @@ -161,8 +168,12 @@ func TestProxyURL_EnrollProxyAndEmptyProxyInThePolicy(t *testing.T) { 0, action, ) + + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + out, err := p.fixture.Install( - context.Background(), + ctx, &integrationtest.InstallOpts{ Force: true, NonInteractive: true, @@ -207,8 +218,12 @@ func TestProxyURL_ProxyInThePolicyTakesPrecedence(t *testing.T) { 0, action, ) + + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + out, err := p.fixture.Install( - context.Background(), + ctx, &integrationtest.InstallOpts{ Force: true, NonInteractive: true, @@ -267,12 +282,16 @@ func TestProxyURL_NoEnrollProxyAndProxyInThePolicy(t *testing.T) { 0, action, ) + + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + t.Logf("fleet: %s, proxy1: %s, proxy2: %s", p.fleet.LocalhostURL, p.proxy1.LocalhostURL, p.proxy2.LocalhostURL) out, err := p.fixture.Install( - context.Background(), + ctx, &integrationtest.InstallOpts{ Force: true, NonInteractive: true, @@ -331,8 +350,12 @@ func TestProxyURL_RemoveProxyFromThePolicy(t *testing.T) { 0, action, ) + + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) + defer cancel() + out, err := p.fixture.Install( - context.Background(), + ctx, &integrationtest.InstallOpts{ Force: true, NonInteractive: true, @@ -366,7 +389,7 @@ func TestProxyURL_RemoveProxyFromThePolicy(t *testing.T) { } // Assert the proxy is set on the agent - inspect, err := p.fixture.ExecInspect(context.Background()) + inspect, err := p.fixture.ExecInspect(ctx) require.NoError(t, err) assert.Equal(t, *p.policyData.FleetProxyURL, inspect.Fleet.ProxyURL) @@ -389,7 +412,7 @@ func TestProxyURL_RemoveProxyFromThePolicy(t *testing.T) { return p.checkinWithAcker.Acked(actionIDRemoveProxyFromPolicy) }, 30*time.Second, 5*time.Second) - inspect, err = p.fixture.ExecInspect(context.Background()) + inspect, err = p.fixture.ExecInspect(ctx) require.NoError(t, err) assert.Equal(t, inspect.Fleet.ProxyURL, want) diff --git a/testing/integration/upgrade_broken_package_test.go b/testing/integration/upgrade_broken_package_test.go index 635480c0f36..d2cb8c4662b 100644 --- a/testing/integration/upgrade_broken_package_test.go +++ b/testing/integration/upgrade_broken_package_test.go @@ -13,12 +13,14 @@ import ( "os" "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/testing/upgradetest" agtversion "github.com/elastic/elastic-agent/version" ) @@ -30,7 +32,7 @@ func TestUpgradeBrokenPackageVersion(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Start at the build version as we want to test the retry diff --git a/testing/integration/upgrade_downgrade_test.go b/testing/integration/upgrade_downgrade_test.go index 8d8950c52d4..0f36e98a99c 100644 --- a/testing/integration/upgrade_downgrade_test.go +++ b/testing/integration/upgrade_downgrade_test.go @@ -10,6 +10,7 @@ import ( "context" "strings" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -17,6 +18,7 @@ import ( 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/testcontext" "github.com/elastic/elastic-agent/pkg/version" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -36,7 +38,7 @@ func TestStandaloneDowngradeToSpecificSnapshotBuild(t *testing.T) { t.Skipf("Version %s is lower than min version %s", define.Version(), minVersion) } - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // retrieve all the versions of agent from the artifact API diff --git a/testing/integration/upgrade_gpg_test.go b/testing/integration/upgrade_gpg_test.go index 96f7d8b50ea..d1d9b6f3af1 100644 --- a/testing/integration/upgrade_gpg_test.go +++ b/testing/integration/upgrade_gpg_test.go @@ -10,12 +10,14 @@ import ( "context" "strings" "testing" + "time" "github.com/stretchr/testify/require" "github.com/elastic/elastic-agent/internal/pkg/release" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/pkg/version" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -35,7 +37,7 @@ func TestStandaloneUpgradeWithGPGFallback(t *testing.T) { t.Skipf("Version %s is lower than min version %s", define.Version(), minVersion) } - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Start at the build version as we want to test the retry @@ -91,7 +93,7 @@ func TestStandaloneUpgradeWithGPGFallbackOneRemoteFailing(t *testing.T) { t.Skipf("Version %s is lower than min version %s", define.Version(), minVersion) } - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Start at the build version as we want to test the retry diff --git a/testing/integration/upgrade_rollback_test.go b/testing/integration/upgrade_rollback_test.go index fcdfb3d492a..3ebd5b336bd 100644 --- a/testing/integration/upgrade_rollback_test.go +++ b/testing/integration/upgrade_rollback_test.go @@ -25,6 +25,7 @@ import ( "github.com/elastic/elastic-agent/internal/pkg/agent/install" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/pkg/version" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -45,7 +46,7 @@ func TestStandaloneUpgradeRollback(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Upgrade from an old build because the new watcher from the new build will @@ -160,7 +161,7 @@ func TestStandaloneUpgradeRollbackOnRestarts(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Upgrade from an old build because the new watcher from the new build will diff --git a/testing/integration/upgrade_standalone_inprogress.go b/testing/integration/upgrade_standalone_inprogress.go index 53b2c50fbed..754a7ba935b 100644 --- a/testing/integration/upgrade_standalone_inprogress.go +++ b/testing/integration/upgrade_standalone_inprogress.go @@ -17,6 +17,7 @@ import ( atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -31,7 +32,7 @@ func TestStandaloneUpgradeFailsWhenUpgradeIsInProgress(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // For this test we start with a version of Agent that's two minors older diff --git a/testing/integration/upgrade_standalone_retry_test.go b/testing/integration/upgrade_standalone_retry_test.go index 4273452cc50..d935215e2f4 100644 --- a/testing/integration/upgrade_standalone_retry_test.go +++ b/testing/integration/upgrade_standalone_retry_test.go @@ -15,12 +15,14 @@ import ( "path/filepath" "strings" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -31,7 +33,7 @@ func TestStandaloneUpgradeRetryDownload(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Start at the build version as we want to test the retry diff --git a/testing/integration/upgrade_standalone_test.go b/testing/integration/upgrade_standalone_test.go index d79a7f18da3..4519a6611c3 100644 --- a/testing/integration/upgrade_standalone_test.go +++ b/testing/integration/upgrade_standalone_test.go @@ -10,12 +10,14 @@ import ( "context" "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" atesting "github.com/elastic/elastic-agent/pkg/testing" "github.com/elastic/elastic-agent/pkg/testing/define" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/testing/upgradetest" ) @@ -26,7 +28,7 @@ func TestStandaloneUpgrade(t *testing.T) { Sudo: true, // requires Agent installation }) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // test 2 current 8.x version and 1 previous 7.x version diff --git a/testing/integration/upgrade_uninstall_test.go b/testing/integration/upgrade_uninstall_test.go index da3b1cae17d..2ed3e8d4662 100644 --- a/testing/integration/upgrade_uninstall_test.go +++ b/testing/integration/upgrade_uninstall_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/elastic/elastic-agent/pkg/testing/tools/testcontext" "github.com/elastic/elastic-agent/pkg/version" "github.com/stretchr/testify/assert" @@ -35,7 +36,7 @@ func TestStandaloneUpgradeUninstallKillWatcher(t *testing.T) { t.Skipf("Version %s is lower than min version %s; test cannot be performed", define.Version(), upgradetest.Version_8_11_0_SNAPSHOT) } - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute)) defer cancel() // Start at old version, we want this test to upgrade to our From 8d4e3daeca867ea8ad6b4959788adf178f3a2c08 Mon Sep 17 00:00:00 2001 From: Michal Pristas Date: Fri, 1 Dec 2023 10:51:45 +0100 Subject: [PATCH 2/2] Elastic Agent ACI compliant image (#3778) --- ...er-runs-on-Azure-Container-Instances-.yaml | 31 ++++++++++ .../docker/Dockerfile.elastic-agent.tmpl | 60 +++++++++---------- 2 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 changelog/fragments/1689328899-Elastic-Agent-container-runs-on-Azure-Container-Instances-.yaml diff --git a/changelog/fragments/1689328899-Elastic-Agent-container-runs-on-Azure-Container-Instances-.yaml b/changelog/fragments/1689328899-Elastic-Agent-container-runs-on-Azure-Container-Instances-.yaml new file mode 100644 index 00000000000..df24e655971 --- /dev/null +++ b/changelog/fragments/1689328899-Elastic-Agent-container-runs-on-Azure-Container-Instances-.yaml @@ -0,0 +1,31 @@ +# 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 + +# Change summary; a 80ish characters long description of the change. +summary: Elastic-Agent container runs on Azure Container Instances + +# Long description; in case the summary is not enough to describe the change +# this field accommodate a description without length limits. +#description: + +# Affected component; a word indicating the component this changeset affects. +component: elastic-agent + +# PR number; 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: 3576 + +# Issue number; 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: 82 diff --git a/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl b/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl index 1a89be1eaca..9d659fe9cd7 100644 --- a/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl +++ b/dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl @@ -8,12 +8,14 @@ FROM {{ .buildFrom }} AS home COPY beat {{ $beatHome }} -RUN mkdir -p {{ $beatHome }}/data {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/logs && \ - chown -R root:root {{ $beatHome }} && \ +RUN true && \ + # ECE needs to create config here under non-1000 user + chmod 0777 {{ $beatHome}} && \ + mkdir -p {{ $beatHome }}/data {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/logs && \ find {{ $beatHome }} -type d -exec chmod 0755 {} \; && \ find {{ $beatHome }} -type f -exec chmod 0644 {} \; && \ - find {{ $beatHome }}/data -type d -exec chmod 0770 {} \; && \ - find {{ $beatHome }}/data -type f -exec chmod 0660 {} \; && \ + find {{ $beatHome }}/data -type d -exec chmod 0777 {} \; && \ + find {{ $beatHome }}/data -type f -exec chmod 0666 {} \; && \ rm {{ $beatBinary }} && \ ln -s {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/elastic-agent {{ $beatBinary }} && \ chmod 0755 {{ $beatHome }}/data/elastic-agent-*/elastic-agent && \ @@ -27,7 +29,6 @@ RUN mkdir -p {{ $beatHome }}/data {{ $beatHome }}/data/elastic-agent-{{ commit_s (chmod 0755 {{ $beatHome }}/data/elastic-agent-*/components/pf-elastic-collector || true) && \ (chmod 0755 {{ $beatHome }}/data/elastic-agent-*/components/pf-elastic-symbolizer || true) && \ (chmod 0755 {{ $beatHome }}/data/elastic-agent-*/components/pf-host-agent || true) && \ - find {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/components -name "*.yml*" -type f -exec chown root:root {} \; && \ find {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/components -name "*.yml*" -type f -exec chmod 0644 {} \; && \ {{- range $i, $modulesd := .ModulesDirs }} chmod 0775 {{ $beatHome}}/{{ $modulesd }} && \ @@ -111,13 +112,19 @@ RUN set -e ; \ chmod +x /usr/bin/tini COPY docker-entrypoint /usr/local/bin/docker-entrypoint -RUN chmod 755 /usr/local/bin/docker-entrypoint +RUN groupadd --gid 1000 {{ .BeatName }} && \ + useradd -M --uid 1000 --gid 1000 --groups 0 {{ .user }} && \ + chmod 755 /usr/local/bin/docker-entrypoint && \ + true -COPY --from=home {{ $beatHome }} {{ $beatHome }} +COPY --chown={{ .user }}:{{ .user }} --from=home {{ $beatHome }} {{ $beatHome }} # Elastic Agent needs group permissions in the home itself to be able to # create fleet.yml when running as non-root. -RUN chmod 0770 {{ $beatHome }} +RUN chmod 0777 {{ $beatHome }} && \ + usermod -d {{ $beatHome}} {{ .user }} && \ + find {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/components -name "*.yml*" -type f -exec chown root:root {} \; && \ + true RUN mkdir /licenses COPY --from=home {{ $beatHome }}/LICENSE.txt /licenses @@ -127,33 +134,23 @@ COPY --from=home {{ $beatHome }}/NOTICE.txt /licenses COPY --from=home /opt /opt {{- end }} +{{- if contains .image_name "-cloud" }} +# Generate folder for a stub command that will be overwritten at runtime +RUN mkdir /app && \ + chown {{ .user }}:{{ .user }} /app +{{- end }} +# Keep this after any chown command, chown resets any applied capabilities RUN setcap cap_net_raw,cap_setuid+p {{ $beatHome }}/data/elastic-agent-{{ commit_short }}/components/heartbeat && \ {{- if .linux_capabilities }} # Since the beat is stored at the other end of a symlink we must follow the symlink first # For security reasons setcap does not support symlinks. This is smart in the general case # but in our specific case since we're building a trusted image from trusted binaries this is # fine. Thus, we use readlink to follow the link and setcap on the actual binary - readlink -f {{ $beatBinary }} | xargs setcap {{ .linux_capabilities }} && \ + setcap {{ .linux_capabilities }} $(readlink -f {{ $beatBinary }}) && \ {{- end }} true -{{- if eq .user "root" }} -{{- if contains .image_name "-cloud" }} -# Generate folder for a stub command that will be overwritten at runtime -RUN mkdir /app -{{- end }} -{{- else }} -RUN groupadd --gid 1000 {{ .BeatName }} -RUN useradd -M --uid 1000 --gid 1000 --groups 0 --home {{ $beatHome }} {{ .user }} - -{{- if contains .image_name "-cloud" }} -# Generate folder for a stub command that will be overwritten at runtime -RUN mkdir /app -RUN chown {{ .user }} /app -{{- end }} -{{- end }} - {{- if (and (contains .image_name "-complete") (not (contains .from "ubi-minimal"))) }} USER root ENV NODE_PATH={{ $beatHome }}/.node @@ -163,7 +160,7 @@ RUN echo \ {{ $beatHome }}/.synthetics \ {{ $beatHome }}/.npm \ {{ $beatHome }}/.cache \ - | xargs -IDIR sh -c 'mkdir -p DIR && chmod 0770 DIR' + | xargs -IDIR sh -c 'mkdir -p DIR && chmod 0775 DIR' # Setup synthetics env vars ENV ELASTIC_SYNTHETICS_CAPABLE=true @@ -192,14 +189,14 @@ RUN cd {{$beatHome}}/.node \ esac \ && mkdir -p node \ && curl ${NODE_DOWNLOAD_URL} | tar -xJ --strip 1 -C node \ - && chmod ug+rwX -R $NODE_PATH - + && chmod ugo+rwX -R $NODE_PATH \ # Install synthetics as a regular user, installing npm deps as root odesn't work -RUN chown -R {{ .user }} $NODE_PATH + # fix .node .npm and .synthetics + && chown -R {{ .user }}:{{ .user }} $NODE_PATH USER {{ .user }} # If this fails dump the NPM logs -RUN npm i -g --loglevel verbose --engine-strict @elastic/synthetics@stack_release || sh -c 'tail -n +1 /root/.npm/_logs/* && exit 1' -RUN chmod ug+rwX -R $NODE_PATH +RUN (npm i -g --loglevel verbose --engine-strict @elastic/synthetics@stack_release || sh -c 'tail -n +1 /root/.npm/_logs/* && exit 1') && \ + chmod ugo+rwX -R $NODE_PATH USER root # Install the deps as needed by the exact version of playwright elastic synthetics uses @@ -223,6 +220,7 @@ USER {{ .user }} EXPOSE {{ $port }} {{- end }} + # When running under Docker, we must ensure libbeat monitoring pulls cgroup # metrics from /sys/fs/cgroup//, ignoring any paths found in # /proc/self/cgroup.