Skip to content

Commit 139ce53

Browse files
authored
systemtest: use Fleet Server (#5085)
* systemtest: use Fleet Server * systemtest: fix bulk unenrolment
1 parent d580619 commit 139ce53

File tree

4 files changed

+91
-35
lines changed

4 files changed

+91
-35
lines changed

systemtest/apmservertest/config.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ func defaultOutputConfig() OutputConfig {
453453
Enabled: true,
454454
Hosts: []string{net.JoinHostPort(
455455
getenvDefault("ES_HOST", defaultElasticsearchHost),
456-
getenvDefault("ES_PORT", defaultElasticsearchPort),
456+
ElasticsearchPort(),
457457
)},
458458
Username: getenvDefault("ES_USER", defaultElasticsearchUser),
459459
Password: getenvDefault("ES_PASS", defaultElasticsearchPass),
@@ -470,6 +470,13 @@ func KibanaPort() string {
470470
return getenvDefault("KIBANA_PORT", defaultKibanaPort)
471471
}
472472

473+
// ElasticsearchPort returns the Elasticsearch REST API port,
474+
// configured using ES_PORT, or otherwise returning the default
475+
// of 9200.
476+
func ElasticsearchPort() string {
477+
return getenvDefault("ES_PORT", defaultElasticsearchPort)
478+
}
479+
473480
func getenvDefault(k, defaultv string) string {
474481
v := os.Getenv(k)
475482
if v == "" {

systemtest/containers.go

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ import (
4343
"github.com/elastic/go-elasticsearch/v7"
4444
)
4545

46-
const startContainersTimeout = 5 * time.Minute
46+
const (
47+
startContainersTimeout = 5 * time.Minute
48+
49+
defaultFleetServerPort = "8220"
50+
)
4751

4852
// StartStackContainers starts Docker containers for Elasticsearch and Kibana.
4953
//
@@ -91,9 +95,7 @@ func NewUnstartedElasticsearchContainer() (*ElasticsearchContainer, error) {
9195
Image: container.Image,
9296
AutoRemove: true,
9397
}
94-
waitFor := wait.ForHTTP("/")
95-
waitFor.Port = "9200/tcp"
96-
req.WaitingFor = waitFor
98+
req.WaitingFor = wait.ForHTTP("/").WithPort("9200/tcp")
9799

98100
for port := range containerDetails.Config.ExposedPorts {
99101
req.ExposedPorts = append(req.ExposedPorts, string(port))
@@ -252,30 +254,30 @@ func NewUnstartedElasticAgentContainer() (*ElasticAgentContainer, error) {
252254
}
253255
defer docker.Close()
254256

255-
kibanaContainer, err := stackContainerInfo(context.Background(), docker, "kibana")
257+
esContainer, err := stackContainerInfo(context.Background(), docker, "elasticsearch")
256258
if err != nil {
257259
return nil, err
258260
}
259-
kibanaContainerDetails, err := docker.ContainerInspect(context.Background(), kibanaContainer.ID)
261+
esContainerDetails, err := docker.ContainerInspect(context.Background(), esContainer.ID)
260262
if err != nil {
261263
return nil, err
262264
}
263265

264-
var kibanaIPAddress string
266+
var esIPAddress string
265267
var networks []string
266-
for network, settings := range kibanaContainerDetails.NetworkSettings.Networks {
268+
for network, settings := range esContainerDetails.NetworkSettings.Networks {
267269
networks = append(networks, network)
268-
if kibanaIPAddress == "" && settings.IPAddress != "" {
269-
kibanaIPAddress = settings.IPAddress
270+
if esIPAddress == "" && settings.IPAddress != "" {
271+
esIPAddress = settings.IPAddress
270272
}
271273
}
272-
kibanaURL := &url.URL{
274+
esURL := &url.URL{
273275
Scheme: "http",
274-
Host: net.JoinHostPort(kibanaIPAddress, apmservertest.KibanaPort()),
276+
Host: net.JoinHostPort(esIPAddress, apmservertest.ElasticsearchPort()),
275277
}
276278

277-
// Use the same stack version as used for Kibana.
278-
agentImageVersion := kibanaContainer.Image[strings.LastIndex(kibanaContainer.Image, ":")+1:]
279+
// Use the same stack version as used for Elasticsearch.
280+
agentImageVersion := esContainer.Image[strings.LastIndex(esContainer.Image, ":")+1:]
279281
agentImage := "docker.elastic.co/beats/elastic-agent:" + agentImageVersion
280282
if err := pullDockerImage(context.Background(), docker, agentImage); err != nil {
281283
return nil, err
@@ -293,11 +295,6 @@ func NewUnstartedElasticAgentContainer() (*ElasticAgentContainer, error) {
293295
AutoRemove: true,
294296
Networks: networks,
295297
Env: map[string]string{
296-
"KIBANA_HOST": kibanaURL.String(),
297-
298-
// TODO(axw) remove once https://github.com/elastic/elastic-agent-client/issues/20 is fixed
299-
"GODEBUG": "x509ignoreCN=0",
300-
301298
// NOTE(axw) because we bind-mount the apm-server artifacts in, they end up owned by the
302299
// current user rather than root. Disable Beats's strict permission checks to avoid resulting
303300
// complaints, as they're irrelevant to these system tests.
@@ -307,15 +304,17 @@ func NewUnstartedElasticAgentContainer() (*ElasticAgentContainer, error) {
307304
return &ElasticAgentContainer{
308305
request: req,
309306
installDir: agentInstallDir,
307+
elasticsearchURL: esURL.String(),
310308
StackVersion: agentImageVersion,
311309
BindMountInstall: make(map[string]string),
312310
}, nil
313311
}
314312

315313
// ElasticAgentContainer represents an ephemeral Elastic Agent container.
316314
type ElasticAgentContainer struct {
317-
container testcontainers.Container
318-
request testcontainers.ContainerRequest
315+
container testcontainers.Container
316+
request testcontainers.ContainerRequest
317+
elasticsearchURL string // used by Fleet Server only
319318

320319
// installDir holds the location of the "install" directory inside
321320
// the Elastic Agent container.
@@ -325,6 +324,10 @@ type ElasticAgentContainer struct {
325324
// can be bind-mounted.
326325
installDir string
327326

327+
// FleetServer controls whether this Elastic Agent bootstraps
328+
// Fleet Server.
329+
FleetServer bool
330+
328331
// StackVersion holds the stack version of the container image,
329332
// e.g. 8.0.0-SNAPSHOT.
330333
StackVersion string
@@ -335,6 +338,12 @@ type ElasticAgentContainer struct {
335338
// WaitingFor holds an optional wait strategy.
336339
WaitingFor wait.Strategy
337340

341+
// FleetServerURL holds the Fleet Server URL to enroll into.
342+
//
343+
// This will be populated by Start if FleetServer is true, using
344+
// one of the container's network aliases.
345+
FleetServerURL string
346+
338347
// Addrs holds the "host:port" address for each exposed port.
339348
// This will be populated by Start.
340349
Addrs []string
@@ -361,14 +370,27 @@ func (c *ElasticAgentContainer) Start() error {
361370
defer cancel()
362371

363372
// Update request from user-definable fields.
364-
if c.FleetEnrollmentToken != "" {
373+
if c.FleetServer {
374+
c.request.Env["FLEET_SERVER_ENABLE"] = "1"
375+
c.request.Env["FLEET_SERVER_HOST"] = "0.0.0.0"
376+
c.request.Env["FLEET_SERVER_PORT"] = defaultFleetServerPort
377+
c.request.Env["FLEET_SERVER_INSECURE_HTTP"] = "1" // expose Fleet Server over HTTP
378+
c.request.Env["FLEET_SERVER_ELASTICSEARCH_HOST"] = c.elasticsearchURL
379+
c.request.Env["FLEET_SERVER_ELASTICSEARCH_USERNAME"] = adminElasticsearchUser
380+
c.request.Env["FLEET_SERVER_ELASTICSEARCH_PASSWORD"] = adminElasticsearchPass
381+
382+
c.request.WaitingFor = wait.ForHTTP("/api/status").WithPort(defaultFleetServerPort + "/tcp")
383+
c.request.ExposedPorts = []string{defaultFleetServerPort}
384+
} else if c.FleetEnrollmentToken != "" {
365385
c.request.Env["FLEET_ENROLL"] = "1"
366386
c.request.Env["FLEET_ENROLLMENT_TOKEN"] = c.FleetEnrollmentToken
367387
c.request.Env["FLEET_INSECURE"] = "1"
368-
c.request.Env["FLEET_URL"] = "http://kibana:5601"
388+
c.request.Env["FLEET_URL"] = c.FleetServerURL
389+
}
390+
c.request.ExposedPorts = append(c.request.ExposedPorts, c.ExposedPorts...)
391+
if c.WaitingFor != nil {
392+
c.request.WaitingFor = c.WaitingFor
369393
}
370-
c.request.ExposedPorts = c.ExposedPorts
371-
c.request.WaitingFor = c.WaitingFor
372394
c.request.BindMounts = map[string]string{}
373395
for source, target := range c.BindMountInstall {
374396
c.request.BindMounts[source] = path.Join(c.installDir, target)
@@ -390,15 +412,33 @@ func (c *ElasticAgentContainer) Start() error {
390412
return err
391413
}
392414
if len(ports) > 0 {
393-
ip, err := container.Host(ctx)
415+
hostIP, err := container.Host(ctx)
394416
if err != nil {
395417
return err
396418
}
397419
for _, portbindings := range ports {
398420
for _, pb := range portbindings {
399-
c.Addrs = append(c.Addrs, net.JoinHostPort(ip, pb.HostPort))
421+
c.Addrs = append(c.Addrs, net.JoinHostPort(hostIP, pb.HostPort))
422+
}
423+
}
424+
}
425+
if c.FleetServer {
426+
networkAliases, err := container.NetworkAliases(ctx)
427+
if err != nil {
428+
return err
429+
}
430+
var networkAlias string
431+
for _, networkAliases := range networkAliases {
432+
if len(networkAliases) > 0 {
433+
networkAlias = networkAliases[0]
434+
break
400435
}
401436
}
437+
if networkAlias == "" {
438+
return errors.New("no network alias found")
439+
}
440+
fleetServerURL := &url.URL{Scheme: "http", Host: net.JoinHostPort(networkAlias, defaultFleetServerPort)}
441+
c.FleetServerURL = fleetServerURL.String()
402442
}
403443

404444
c.container = container

systemtest/fleet_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"path/filepath"
2929
"runtime"
3030
"testing"
31+
"time"
3132

3233
"github.com/stretchr/testify/assert"
3334
"github.com/stretchr/testify/require"
@@ -62,9 +63,19 @@ func TestFleetIntegration(t *testing.T) {
6263
err = fleet.CreatePackagePolicy(packagePolicy)
6364
require.NoError(t, err)
6465

66+
// Bootstrap fleet-server.
67+
fleetServer, err := systemtest.NewUnstartedElasticAgentContainer()
68+
require.NoError(t, err)
69+
fleetServer.FleetServer = true
70+
defer fleetServer.Close()
71+
err = fleetServer.Start()
72+
require.NoError(t, err)
73+
74+
// Enroll another elastic-agent to run the APM integration.
6575
agent, err := systemtest.NewUnstartedElasticAgentContainer()
6676
require.NoError(t, err)
6777
agent.FleetEnrollmentToken = enrollmentAPIKey.APIKey
78+
agent.FleetServerURL = fleetServer.FleetServerURL
6879
defer agent.Close()
6980

7081
defer func() {
@@ -101,9 +112,7 @@ func TestFleetIntegration(t *testing.T) {
101112
// Start elastic-agent with port 8200 exposed, and wait for the server to service
102113
// healthcheck requests to port 8200.
103114
agent.ExposedPorts = []string{"8200"}
104-
waitFor := wait.ForHTTP("/")
105-
waitFor.Port = "8200/tcp"
106-
agent.WaitingFor = waitFor
115+
agent.WaitingFor = wait.ForHTTP("/").WithPort("8200/tcp").WithStartupTimeout(5 * time.Minute)
107116
err = agent.Start()
108117
require.NoError(t, err)
109118

@@ -214,7 +223,7 @@ func cleanupFleet(t testing.TB, fleet *fleettest.Client) {
214223
err = fleet.DeleteAgentPolicy(p.ID)
215224
var fleetError *fleettest.Error
216225
if errors.As(err, &fleetError) {
217-
assert.Equal(t, http.StatusNotFound, fleetError.StatusCode)
226+
assert.Equal(t, http.StatusNotFound, fleetError.StatusCode, fleetError.Message)
218227
}
219228
}
220229
}

systemtest/fleettest/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ func (c *Client) Agents() ([]Agent, error) {
7070
}
7171

7272
// BulkUnenrollAgents bulk-unenrolls agents.
73-
func (c *Client) BulkUnenrollAgents(force bool, agentIDs ...string) error {
73+
func (c *Client) BulkUnenrollAgents(revoke bool, agentIDs ...string) error {
7474
var body bytes.Buffer
7575
type bulkUnenroll struct {
7676
Agents []string `json:"agents"`
77-
Force bool `json:"force"`
77+
Revoke bool `json:"revoke"`
7878
}
79-
if err := json.NewEncoder(&body).Encode(bulkUnenroll{agentIDs, force}); err != nil {
79+
if err := json.NewEncoder(&body).Encode(bulkUnenroll{agentIDs, revoke}); err != nil {
8080
return err
8181
}
8282
req := c.newFleetRequest("POST", "/agents/bulk_unenroll", &body)

0 commit comments

Comments
 (0)