Skip to content

Commit

Permalink
Add fleet-server bootstrap integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
michel-laterman committed May 22, 2024
1 parent 884c707 commit 0aa1bc4
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 0 deletions.
26 changes: 26 additions & 0 deletions pkg/testing/fixture_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ func (e EnrollOpts) toCmdArgs() []string {
return args
}

type FleetBootstrapOpts struct {
ESHost string // --fleet-server-es
ServiceToken string // --fleet-server-service-token
Policy string // --fleet-server-policy
Port int // --fleet-server-port
}

func (f FleetBootstrapOpts) toCmdArgs() []string {
var args []string
if f.ESHost != "" {
args = append(args, "--fleet-server-es", f.ESHost)
}
if f.ServiceToken != "" {
args = append(args, "--fleet-server-service-token", f.ServiceToken)
}
if f.Policy != "" {
args = append(args, "--fleet-server-policy", f.Policy)
}
if f.Port > 0 {
args = append(args, "--fleet-server-port", fmt.Sprintf("%d", f.Port))
}
return args
}

// InstallOpts specifies the options for the install command
type InstallOpts struct {
BasePath string // --base-path
Expand All @@ -68,6 +92,7 @@ type InstallOpts struct {
Privileged bool // inverse of --unprivileged (as false is the default)

EnrollOpts
FleetBootstrapOpts
}

func (i InstallOpts) toCmdArgs(operatingSystem string) ([]string, error) {
Expand Down Expand Up @@ -95,6 +120,7 @@ func (i InstallOpts) toCmdArgs(operatingSystem string) ([]string, error) {
}

args = append(args, i.EnrollOpts.toCmdArgs()...)
args = append(args, i.FleetBootstrapOpts.toCmdArgs()...)

return args, nil
}
Expand Down
28 changes: 28 additions & 0 deletions pkg/testing/tools/estools/elasticsearch.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,34 @@ func CreateAPIKey(ctx context.Context, client elastictransport.Interface, req AP
return parsed, nil
}

func CreateServiceToken(ctx context.Context, client elastictransport.Interface, service string) (string, error) {
req := esapi.SecurityCreateServiceTokenRequest{
Namespace: "elastic",
Service: service,
}
resp, err := req.Do(ctx, client)
if err != nil {
return "", fmt.Errorf("error creating service token: %w", err)
}
defer resp.Body.Close()
resultBuf, err := handleResponseRaw(resp)
if err != nil {
return "", fmt.Errorf("error handling HTTP response: %w", err)
}

var parsed struct {
Token struct {
Value string `json:"value"`
} `json:"token"`
}
err = json.Unmarshal(resultBuf, &parsed)
if err != nil {
return "", fmt.Errorf("error unmarshaling json response: %w", err)
}
return parsed.Token.Value, nil

}

// FindMatchingLogLines returns any logs with message fields that match the given line
func FindMatchingLogLines(ctx context.Context, client elastictransport.Interface, namespace, line string) (Documents, error) {
return FindMatchingLogLinesWithContext(ctx, client, namespace, line)
Expand Down
18 changes: 18 additions & 0 deletions testing/integration/fleet-server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "fleet_server-1",
"description": "",
"namespace": "",
"package": {
"name": "fleet_server",
"version": "1.5.0"
},
"inputs": {
"fleet_server-fleet-server": {
"enabled": true,
"vars": {
"custom": ""
},
"streams": {}
}
}
}
120 changes: 120 additions & 0 deletions testing/integration/fleetserver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

//go:build integration

package integration

import (
"context"
"os"
"path/filepath"
"runtime"
"testing"
"time"

"github.com/google/uuid"
"github.com/stretchr/testify/require"

"github.com/elastic/elastic-agent-libs/kibana"
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/estools"
"github.com/elastic/elastic-agent/pkg/testing/tools/testcontext"
)

func fleetPolicy() kibana.AgentPolicy {
policyUUID := uuid.New().String()

return kibana.AgentPolicy{
Name: "test-fleet-policy-" + policyUUID,
Namespace: "default",
Description: "Test fleet policy " + policyUUID,
}
}

func TestInstallFleetServerBootstrap(t *testing.T) {
info := define.Require(t, define.Requirements{
Group: FleetBootstrap,
Stack: &define.Stack{},
Sudo: true,
Local: false,
})

ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
defer cancel()

// Get path to Elastic Agent executable
fixture, err := define.NewFixtureFromLocalBuild(t, define.Version())
require.NoError(t, err)
err = fixture.Prepare(ctx)
require.NoError(t, err)

t.Log("Ensure base path is clean")
var defaultBasePath string
switch runtime.GOOS {
case "darwin":
defaultBasePath = `/Library`
case "linux":
defaultBasePath = `/opt`
case "windows":
defaultBasePath = `C:\Program Files`
}

topPath := filepath.Join(defaultBasePath, "Elastic", "Agent")
err = os.RemoveAll(topPath)
require.NoError(t, err, "failed to remove %q. The test requires this path not to exist.")

t.Log("Create fleet-server policy...")
policyResp, err := info.KibanaClient.CreatePolicy(ctx, fleetPolicy())
require.NoError(t, err, "failed creating policy")
policy = policyResp.AgentPolicy
_, err = tools.InstallPackageFromDefaultFile(ctx, info.KibanaClient, "fleet-server", "1.5.0", "fleet-server.json", uuid.New().String, policy.ID)
require.NoError(t, err, "failed creating fleet-server integration")

t.Log("Get fleet-server service token...")
serviceToken, err := estools.CreateServiceToken(ctx, info.ESClient, "fleet-server")
require.NoError(t, err, "failed creating service token")

esHost, ok := os.LookupEnv("ELASTICSEARCH_HOST")
require.True(t, ok, "environment var ELASTICSEARCH_HOST is empty")

// Run `elastic-agent install` with fleet-server bootstrap options.
// We use `--force` to prevent interactive execution.
opts := &atesting.InstallOpts{
Force: true,
Privileged: false,
FleetBootstrapOpts: atesting.FleetBootstrapOpts{
ESHost: esHost,
ServiceToken: serviceToken,
Policy: policy.ID,
Port: 8220,
},
}
out, err := fixture.Install(ctx, &opts)
if err != nil {
t.Logf("Install output: %s", out)
require.NoError(t, err, "unable to install elastic-agent with fleet-server bootstrap options")
}

checkInstallSuccess(t, fixture, topPath, true)
t.Run("check agent package version", testAgentPackageVersion(ctx, fixture, true))

// TODO check fleet-server status

// Make sure uninstall from within the topPath fails on Windows
if runtime.GOOS == "windows" {
cwd, err := os.Getwd()
require.NoErrorf(t, err, "GetWd failed: %s", err)
err = os.Chdir(topPath)
require.NoErrorf(t, err, "Chdir to topPath failed: %s", err)
t.Cleanup(func() {
_ = os.Chdir(cwd)
})
out, err = fixture.Uninstall(ctx, &atesting.UninstallOpts{Force: true})
require.Error(t, err, "uninstall should have failed")
require.Containsf(t, string(out), "uninstall must be run from outside the installed path", "expected error string not found in: %s err: %s", out, err)
}
}
3 changes: 3 additions & 0 deletions testing/integration/groups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const (
// Fleet group of tests. Used for testing Elastic Agent with Fleet.
Fleet = "fleet"

// FleetBootstrap group of tests. Used for testing Elastic Agent when bootstrapping a local fleet-server.
FleetBootstrap = "fleet-bootstrap"

// FleetPrivileged group of tests. Used for testing Elastic Agent with Fleet installed privileged.
FleetPrivileged = "fleet-privileged"

Expand Down

0 comments on commit 0aa1bc4

Please sign in to comment.