Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update serverless support in integration tests, expand test tooling, add support for beats testing #3486

Merged
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
c55bbde
cleaning up
fearful-symmetry Aug 15, 2023
12ac235
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Aug 15, 2023
e939383
final bit of cleanup
fearful-symmetry Aug 16, 2023
2afe998
fix magefile, cleanup docs
fearful-symmetry Aug 16, 2023
413c0d7
clean up errors, make linter happy
fearful-symmetry Aug 16, 2023
a16767d
fix headers
fearful-symmetry Aug 16, 2023
7e8970a
fix fields in runner config
fearful-symmetry Aug 16, 2023
9e26b7c
add dashboard checks
fearful-symmetry Aug 17, 2023
3aab6e6
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Aug 17, 2023
369f62e
clean up, refactor
fearful-symmetry Aug 25, 2023
0b7afae
clean up
fearful-symmetry Aug 25, 2023
ef23b3a
tinker with env vars
fearful-symmetry Aug 28, 2023
a20930d
fix defaults in fixture
fearful-symmetry Aug 29, 2023
7d5da83
check binary name in test setup
fearful-symmetry Aug 29, 2023
e75b495
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Sep 5, 2023
85b4ba5
allow ilm override in tests
fearful-symmetry Sep 6, 2023
0051120
fix filebeat tests, add cleanup
fearful-symmetry Sep 6, 2023
fd88bf2
tinker with dashboards
fearful-symmetry Sep 11, 2023
ec9c8c5
fix ilm tests
fearful-symmetry Sep 13, 2023
e312d0b
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Sep 13, 2023
27f8814
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Sep 21, 2023
5611ff9
Merge remote-tracking branch 'origin/serverless-tests' into serverles…
fearful-symmetry Sep 21, 2023
8267e47
use API keys for auth
fearful-symmetry Sep 26, 2023
a733070
Merge remote-tracking branch 'origin/serverless-tests' into serverles…
fearful-symmetry Sep 26, 2023
acff625
add additional integration tests
fearful-symmetry Sep 27, 2023
3196a39
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Sep 28, 2023
a79b814
Merge remote-tracking branch 'upstream/main' into serverless-tests
fearful-symmetry Sep 28, 2023
de89941
remove beats-specific code
fearful-symmetry Sep 28, 2023
6a5277b
hack in serverless tests
fearful-symmetry Sep 29, 2023
a5039e6
tinker with tests
fearful-symmetry Sep 29, 2023
5a49c56
change env var naming
fearful-symmetry Sep 29, 2023
918fec6
actually use correct provisioner name
fearful-symmetry Sep 29, 2023
459206a
tinker with buildkite again
fearful-symmetry Oct 2, 2023
a7c0c0a
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 2, 2023
d158d76
fix things after refactor
fearful-symmetry Oct 3, 2023
b2e4e87
fix buildkite
fearful-symmetry Oct 3, 2023
f359ef0
fix my bash scripts
fearful-symmetry Oct 3, 2023
bf3e5f4
my bash is a tad rusty
fearful-symmetry Oct 3, 2023
1e00bd0
tinker with script hooks
fearful-symmetry Oct 3, 2023
203491c
not sure what ci role I broke
fearful-symmetry Oct 3, 2023
0903608
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 4, 2023
875bbd1
clean up es handlers
fearful-symmetry Oct 5, 2023
c1cadb1
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 5, 2023
2b0d84d
deal with recent refactor
fearful-symmetry Oct 5, 2023
8c07f05
fix my broken refactor
fearful-symmetry Oct 5, 2023
9edc32c
change url, see what happens
fearful-symmetry Oct 5, 2023
0c7d0cb
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 6, 2023
ea4d684
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 9, 2023
4fe9a58
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 10, 2023
c3c8255
tinker with tests more
fearful-symmetry Oct 10, 2023
0a0ea06
swap pipelines, see what happens
fearful-symmetry Oct 10, 2023
d9b62c0
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 10, 2023
4165bdb
break apart beat runners
fearful-symmetry Oct 11, 2023
17cf6d4
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 12, 2023
0bda272
fix a few serverless bugs, timeout
fearful-symmetry Oct 13, 2023
23ec4aa
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 16, 2023
9794006
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 19, 2023
3848c41
remove os restriction
fearful-symmetry Oct 19, 2023
92aacb4
increase timeouts
fearful-symmetry Oct 19, 2023
b380976
Merge remote-tracking branch 'upstream/main' into support-serverless-…
fearful-symmetry Oct 23, 2023
0bc94bb
revert timeout change
fearful-symmetry Oct 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .buildkite/hooks/pre-command
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-agent-package" ]]; then
fi
fi

if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-agent" && "$BUILDKITE_STEP_KEY" == "integration-tests" ]]; then
if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-agent" && "$BUILDKITE_STEP_KEY" == *"integration-tests"* ]]; then
# Set GCP credentials
export GOOGLE_APPLICATION_GCP_SECRET=$(retry 5 vault kv get -format=json -field=data ${CI_GCP_OBS_PATH})
echo "${GOOGLE_APPLICATION_GCP_SECRET}" > ./gcp.json
Expand Down
2 changes: 1 addition & 1 deletion .buildkite/hooks/pre-exit
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -eo pipefail

if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-agent" && "$BUILDKITE_STEP_KEY" == "integration-tests" ]]; then
if [[ "$BUILDKITE_PIPELINE_SLUG" == "elastic-agent" && "$BUILDKITE_STEP_KEY" == *"integration-tests"* ]]; then
if [[ -z "${WORKSPACE-""}" ]]; then
WORKSPACE=$(git rev-parse --show-toplevel)
fi
Expand Down
10 changes: 10 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ steps:
provider: "gcp"
machineType: "n1-standard-8"

- label: "Serverless integration test"
key: "serverless-integration-tests"
command: ".buildkite/scripts/steps/integration_tests.sh serverless integration:single TestMonitoringLogsShipped"
belimawr marked this conversation as resolved.
Show resolved Hide resolved
artifact_paths:
- "build/TEST-**"
- "build/diagnostics/*"
agents:
provider: "gcp"
machineType: "n1-standard-8"

- wait: ~
continue_on_failure: true
- label: "Processing test results"
Expand Down
7 changes: 6 additions & 1 deletion .buildkite/scripts/steps/integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ set -euo pipefail

source .buildkite/scripts/common.sh

STACK_PROVISIONER="${1:-"stateful"}"
MAGE_TARGET="${2:-"integration:test"}"
MAGE_SUBTARGET="${3:-""}"


# Override the agent package version using a string with format <major>.<minor>.<patch>
# NOTE: use only after version bump when the new version is not yet available, for example:
# OVERRIDE_AGENT_PACKAGE_VERSION="8.10.3"
Expand All @@ -18,7 +23,7 @@ AGENT_PACKAGE_VERSION="${OVERRIDE_AGENT_PACKAGE_VERSION}" DEV=true EXTERNAL=true

# Run integration tests
set +e
AGENT_VERSION="${OVERRIDE_TEST_AGENT_VERSION}" TEST_INTEG_CLEAN_ON_EXIT=true SNAPSHOT=true mage integration:test
AGENT_VERSION="${OVERRIDE_TEST_AGENT_VERSION}" TEST_INTEG_CLEAN_ON_EXIT=true STACK_PROVISIONER="$STACK_PROVISIONER" SNAPSHOT=true mage $MAGE_TARGET $MAGE_SUBTARGET
TESTS_EXIT_STATUS=$?
set -e

Expand Down
54 changes: 35 additions & 19 deletions magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,7 @@ func majorMinor() string {

// Clean cleans up the integration testing leftovers
func (Integration) Clean() error {
fmt.Println("--- Clean mage artifacts")
_ = os.RemoveAll(".agent-testing")

// Clean out .integration-cache/.ogc-cache always
Expand Down Expand Up @@ -1690,6 +1691,7 @@ func createTestRunner(matrix bool, singleTest string, goTestFlags string, batche
if err != nil {
return nil, err
}

agentStackVersion := os.Getenv("AGENT_STACK_VERSION")
agentVersion := os.Getenv("AGENT_VERSION")
if agentVersion == "" {
Expand All @@ -1707,6 +1709,7 @@ func createTestRunner(matrix bool, singleTest string, goTestFlags string, batche
agentVersion = fmt.Sprintf("%s-SNAPSHOT", agentVersion)
}
}

if agentStackVersion == "" {
agentStackVersion = agentVersion
}
Expand Down Expand Up @@ -1744,15 +1747,15 @@ func createTestRunner(matrix bool, singleTest string, goTestFlags string, batche
instanceProvisionerMode = "ogc"
}
if instanceProvisionerMode != "ogc" && instanceProvisionerMode != "multipass" {
return nil, errors.New("INSTANCE_PROVISIONER environment variable must be one of 'ogc' or 'multipass'")
return nil, fmt.Errorf("INSTANCE_PROVISIONER environment variable must be one of 'ogc' or 'multipass', not %s", instanceProvisionerMode)
}
fmt.Printf(">>>> Using %s instance provisioner\n", instanceProvisionerMode)
stackProvisionerMode := os.Getenv("STACK_PROVISIONER")
if stackProvisionerMode == "" {
stackProvisionerMode = "ess"
stackProvisionerMode = "stateful"
}
if stackProvisionerMode != "ess" && stackProvisionerMode != "serverless" {
return nil, errors.New("STACK_PROVISIONER environment variable must be one of 'serverless' or 'ess'")
if stackProvisionerMode != "stateful" && stackProvisionerMode != "serverless" {
return nil, fmt.Errorf("STACK_PROVISIONER environment variable must be one of 'serverless' or 'stateful', not %s", stackProvisionerMode)
}
fmt.Printf(">>>> Using %s stack provisioner\n", stackProvisionerMode)

Expand All @@ -1766,24 +1769,37 @@ func createTestRunner(matrix bool, singleTest string, goTestFlags string, batche
extraEnv["AGENT_KEEP_INSTALLED"] = os.Getenv("AGENT_KEEP_INSTALLED")
}

// these following two env vars are currently not used by anything, but can be used in the future to test beats or
// other binaries, see https://github.com/elastic/elastic-agent/pull/3258
binaryName := os.Getenv("TEST_BINARY_NAME")
if binaryName == "" {
binaryName = "elastic-agent"
}

repoDir := os.Getenv("TEST_INTEG_REPO_PATH")
if repoDir == "" {
repoDir = "."
}

diagDir := filepath.Join("build", "diagnostics")
_ = os.MkdirAll(diagDir, 0755)

cfg := runner.Config{
AgentVersion: agentVersion,
AgentStackVersion: agentStackVersion,
BuildDir: agentBuildDir,
GOVersion: goVersion,
RepoDir: ".",
StateDir: ".integration-cache",
DiagnosticsDir: diagDir,
Platforms: testPlatforms(),
Matrix: matrix,
SingleTest: singleTest,
VerboseMode: mg.Verbose(),
Timestamp: timestamp,
TestFlags: goTestFlags,
ExtraEnv: extraEnv,
AgentVersion: agentVersion,
StackVersion: agentStackVersion,
BuildDir: agentBuildDir,
GOVersion: goVersion,
RepoDir: repoDir,
DiagnosticsDir: diagDir,
StateDir: ".integration-cache",
Platforms: testPlatforms(),
Matrix: matrix,
SingleTest: singleTest,
VerboseMode: mg.Verbose(),
Timestamp: timestamp,
TestFlags: goTestFlags,
ExtraEnv: extraEnv,
BinaryName: binaryName,
}
ogcCfg := ogc.Config{
ServiceTokenPath: serviceTokenPath,
Expand Down Expand Up @@ -1812,7 +1828,7 @@ func createTestRunner(matrix bool, singleTest string, goTestFlags string, batche
Region: essRegion,
}
var stackProvisioner runner.StackProvisioner
if stackProvisionerMode == "ess" {
if stackProvisionerMode == "stateful" {
stackProvisioner, err = ess.NewProvisioner(provisionCfg)
if err != nil {
return nil, err
Expand Down
18 changes: 14 additions & 4 deletions pkg/testing/define/define.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,29 @@ func NewFixture(t *testing.T, version string, opts ...atesting.FixtureOpt) (*ate
buildsDir = filepath.Join(projectDir, "build", "distributions")
}

return NewFixtureWithBinary(t, version, "elastic-agent", buildsDir)

}

// NewFixture returns a new Elastic Agent testing fixture with a LocalFetcher and
// the agent logging to the test logger.
func NewFixtureWithBinary(t *testing.T, version string, binary string, buildsDir string, opts ...atesting.FixtureOpt) (*atesting.Fixture, error) {
ver, err := semver.ParseVersion(version)
if err != nil {
return nil, fmt.Errorf("%q is an invalid agent version: %w", version, err)
}

var f atesting.Fetcher
var binFetcher atesting.Fetcher
if ver.IsSnapshot() {
f = atesting.LocalFetcher(buildsDir, atesting.WithLocalSnapshotOnly())
binFetcher = atesting.LocalFetcher(buildsDir, atesting.WithLocalSnapshotOnly(), atesting.WithCustomBinaryName(binary))
} else {
f = atesting.LocalFetcher(buildsDir)
binFetcher = atesting.LocalFetcher(buildsDir, atesting.WithCustomBinaryName(binary))
}

opts = append(opts, atesting.WithFetcher(f), atesting.WithLogOutput())
opts = append(opts, atesting.WithFetcher(binFetcher), atesting.WithLogOutput())
if binary != "elastic-agent" {
opts = append(opts, atesting.WithBinaryName(binary))
}
return atesting.NewFixture(t, version, opts...)
}

Expand Down
69 changes: 53 additions & 16 deletions pkg/testing/ess/serverless.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/elastic/elastic-agent/pkg/testing/runner"
)

var serverlessURL = "https://global.qa.cld.elstc.co"
var serverlessURL = "https://staging.found.no"

// ServerlessClient is the handler the serverless ES instance
type ServerlessClient struct {
Expand Down Expand Up @@ -54,6 +54,13 @@ type Project struct {
} `json:"endpoints"`
}

// CredResetResponse contains the new auth details for a
// stack credential reset
type CredResetResponse struct {
Password string `json:"password"`
Username string `json:"username"`
}

// NewServerlessClient creates a new instance of the serverless client
func NewServerlessClient(region, projectType, api string, logger runner.Logger) *ServerlessClient {
return &ServerlessClient{
Expand Down Expand Up @@ -97,6 +104,16 @@ func (srv *ServerlessClient) DeployStack(ctx context.Context, req ServerlessRequ
return Project{}, fmt.Errorf("error decoding JSON response: %w", err)
}
srv.proj = serverlessHandle

// as of 8/8-ish, the serverless ESS cloud no longer provides credentials on the first POST request, we must send an additional POST
// to reset the credentials
updated, err := srv.ResetCredentials(ctx)
if err != nil {
return serverlessHandle, fmt.Errorf("error resetting credentials: %w", err)
}
srv.proj.Credentials.Username = updated.Username
srv.proj.Credentials.Password = updated.Password

return serverlessHandle, nil
}

Expand Down Expand Up @@ -181,27 +198,15 @@ func (srv *ServerlessClient) WaitForEndpoints(ctx context.Context) error {

// WaitForElasticsearch waits until the ES endpoint is healthy
func (srv *ServerlessClient) WaitForElasticsearch(ctx context.Context) error {
endpoint := fmt.Sprintf("%s/_cluster/health", srv.proj.Endpoints.Elasticsearch)
req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
req, err := http.NewRequestWithContext(ctx, "GET", srv.proj.Endpoints.Elasticsearch, nil)
if err != nil {
return fmt.Errorf("error creating HTTP request: %w", err)
}
req.SetBasicAuth(srv.proj.Credentials.Username, srv.proj.Credentials.Password)

// _cluster/health no longer works on serverless, just check response code
readyFunc := func(resp *http.Response) bool {
var health struct {
Status string `json:"status"`
}
err = json.NewDecoder(resp.Body).Decode(&health)
resp.Body.Close()
if err != nil {
srv.log.Logf("response decoding error: %v", err)
return false
}
if health.Status == "green" {
return true
}
return false
return resp.StatusCode == 200
}

err = srv.waitForRemoteState(ctx, req, time.Second*5, readyFunc)
Expand Down Expand Up @@ -243,6 +248,38 @@ func (srv *ServerlessClient) WaitForKibana(ctx context.Context) error {
return nil
}

// ResetCredentials resets the credentials for the given ESS instance
func (srv *ServerlessClient) ResetCredentials(ctx context.Context) (CredResetResponse, error) {
resetURL := fmt.Sprintf("%s/api/v1/serverless/projects/%s/%s/_reset-credentials", serverlessURL, srv.projectType, srv.proj.ID)

resetHandler, err := http.NewRequestWithContext(ctx, "POST", resetURL, nil)
if err != nil {
return CredResetResponse{}, fmt.Errorf("error creating new httpRequest: %w", err)
}

resetHandler.Header.Set("Content-Type", "application/json")
resetHandler.Header.Set("Authorization", fmt.Sprintf("ApiKey %s", srv.api))

resp, err := http.DefaultClient.Do(resetHandler)
if err != nil {
return CredResetResponse{}, fmt.Errorf("error performing HTTP request: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
p, _ := io.ReadAll(resp.Body)
return CredResetResponse{}, fmt.Errorf("Non-200 status code returned by server: %d, body: %s", resp.StatusCode, string(p))
}

updated := CredResetResponse{}
err = json.NewDecoder(resp.Body).Decode(&updated)
if err != nil {
return CredResetResponse{}, fmt.Errorf("error decoding JSON response: %w", err)
}

return updated, nil
}

func (srv *ServerlessClient) waitForRemoteState(ctx context.Context, httpHandler *http.Request, tick time.Duration, isReady func(*http.Response) bool) error {
timer := time.NewTimer(time.Millisecond)
// in cases where we get a timeout, also return the last error returned via HTTP
Expand Down
3 changes: 2 additions & 1 deletion pkg/testing/ess/serverless_provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (prov *ServerlessProvision) Provision(ctx context.Context, requests []runne
for _, req := range requests {
client := NewServerlessClient(prov.cfg.Region, "observability", prov.cfg.APIKey, prov.log)
srvReq := ServerlessRequest{Name: req.ID, RegionID: prov.cfg.Region}
_, err := client.DeployStack(ctx, srvReq)
proj, err := client.DeployStack(ctx, srvReq)
if err != nil {
return nil, fmt.Errorf("error deploying stack for request %s: %w", req.ID, err)
}
Expand All @@ -95,6 +95,7 @@ func (prov *ServerlessProvision) Provision(ctx context.Context, requests []runne
Kibana: client.proj.Endpoints.Kibana,
Username: client.proj.Credentials.Username,
Password: client.proj.Credentials.Password,
Internal: map[string]interface{}{"ID": proj.ID},
}
stacks = append(stacks, newStack)
prov.stacksMut.Lock()
Expand Down
15 changes: 12 additions & 3 deletions pkg/testing/fetcher_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
type localFetcher struct {
dir string
snapshotOnly bool
binaryName string
}

type localFetcherOpt func(f *localFetcher)
Expand All @@ -28,10 +29,18 @@ func WithLocalSnapshotOnly() localFetcherOpt {
}
}

// WithCustomBinaryName sets the binary to a custom name, the default is `elastic-agent`
func WithCustomBinaryName(name string) localFetcherOpt {
return func(f *localFetcher) {
f.binaryName = name
}
}

// LocalFetcher returns a fetcher that pulls the binary of the Elastic Agent from a local location.
func LocalFetcher(dir string, opts ...localFetcherOpt) Fetcher {
f := &localFetcher{
dir: dir,
dir: dir,
binaryName: "elastic-agent",
}
for _, o := range opts {
o(f)
Expand All @@ -56,7 +65,7 @@ func (f *localFetcher) Fetch(_ context.Context, operatingSystem string, architec
return nil, fmt.Errorf("invalid version: %q: %w", ver, err)
}

mainBuildfmt := "elastic-agent-%s-%s"
mainBuildfmt := "%s-%s-%s"
if f.snapshotOnly && !ver.IsSnapshot() {
if ver.Prerelease() == "" {
ver = semver.NewParsedSemVer(ver.Major(), ver.Minor(), ver.Patch(), "SNAPSHOT", ver.BuildMetadata())
Expand All @@ -66,7 +75,7 @@ func (f *localFetcher) Fetch(_ context.Context, operatingSystem string, architec

}

mainBuild := fmt.Sprintf(mainBuildfmt, ver, suffix)
mainBuild := fmt.Sprintf(mainBuildfmt, f.binaryName, ver, suffix)
mainBuildPath := filepath.Join(f.dir, mainBuild)
build := mainBuild
buildPath := mainBuildPath
Expand Down
Loading
Loading