Skip to content

Commit 8337980

Browse files
mergify[bot]belimawrpkoutsovasilis
authored
[8.18](backport #7995) Enable Filebeat's Journald input in some docker image variants (#8482)
* Enable Filebeat's Journald input in some docker image variants (#7995) Filebeat's Journald input requires `journalctl`, so the systemd package is added to elastic-agent, elastic-agent-complete, elastic-otel-collector variants. --------- Co-authored-by: Craig MacKenzie <[email protected]> (cherry picked from commit fd33d85) # Conflicts: # dev-tools/packaging/settings.go # dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl * Fix merge conflicts Mostly re-doing the addition of systemd packages due to the different base images * Update env var usage * Only install jounralctl in the complete variant * remove basic variant from TestKubernetesJournaldInput * remove TestKubernetesJournaldInputOtel as edot collector variant is not relevant to 8.18 * Update changelog/fragments/1745609163-journalctl-on-all-docker-variants.yaml --------- Co-authored-by: Tiago Queiroz <[email protected]> Co-authored-by: Panos Koutsovasilis <[email protected]>
1 parent e2e3b54 commit 8337980

File tree

6 files changed

+235
-7
lines changed

6 files changed

+235
-7
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Kind can be one of:
2+
# - breaking-change: a change to previously-documented behavior
3+
# - deprecation: functionality that is being removed in a later release
4+
# - bug-fix: fixes a problem in a previous version
5+
# - enhancement: extends functionality but does not break or fix existing behavior
6+
# - feature: new functionality
7+
# - known-issue: problems that we are aware of in a given version
8+
# - security: impacts on the security of a product or a user’s deployment.
9+
# - upgrade: important information for someone upgrading from a prior version
10+
# - other: does not fit into any of the other categories
11+
kind: bug-fix
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: |
15+
Ship journalctl in the elastic-agent-complete, Docker image
16+
to enable reading journald logs. Journalctl is not present on
17+
Wolfi images.
18+
19+
# Long description; in case the summary is not enough to describe the change
20+
# this field accommodate a description without length limits.
21+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
22+
#description:
23+
24+
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
25+
component: elastic-agent
26+
27+
# PR URL; optional; the PR number that added the changeset.
28+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
29+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
30+
# Please provide it if you are adding a fragment for a different PR.
31+
pr: https://github.com/elastic/elastic-agent/pull/7995
32+
33+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
34+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
35+
issue: https://github.com/elastic/beats/issues/44040

dev-tools/packaging/templates/docker/Dockerfile.elastic-agent.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ RUN for iter in {1..10}; do \
257257
$NODE_PATH/node/lib/node_modules/@elastic/synthetics/node_modules/.bin/playwright install-deps chromium && \
258258
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --yes \
259259
fonts-noto \
260-
fonts-noto-cjk && \
260+
fonts-noto-cjk \
261+
systemd && \
261262
exit_code=0 && break || exit_code=$? && echo "apt-get error: retry $iter in 10s" && sleep 10; \
262263
done; \
263264
(exit $exit_code)

magefile.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,16 @@ func (Integration) Kubernetes(ctx context.Context) error {
20832083
return integRunner(ctx, "testing/integration", false, "")
20842084
}
20852085

2086+
// KubernetesSingle runs a single Kubernetes integration test
2087+
func (Integration) KubernetesSingle(ctx context.Context, testName string) error {
2088+
// invoke integration tests
2089+
if err := os.Setenv("TEST_GROUPS", "kubernetes"); err != nil {
2090+
return err
2091+
}
2092+
2093+
return integRunner(ctx, "testing/integration", false, testName)
2094+
}
2095+
20862096
// KubernetesMatrix runs a matrix of kubernetes integration tests
20872097
func (Integration) KubernetesMatrix(ctx context.Context) error {
20882098
// invoke integration tests

testing/integration/journald_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License 2.0;
3+
// you may not use this file except in compliance with the Elastic License 2.0.
4+
5+
//go:build integration
6+
7+
package integration
8+
9+
import (
10+
"context"
11+
"fmt"
12+
"os"
13+
"path/filepath"
14+
"testing"
15+
16+
"github.com/stretchr/testify/require"
17+
corev1 "k8s.io/api/core/v1"
18+
"sigs.k8s.io/e2e-framework/klient/k8s"
19+
20+
"github.com/elastic/elastic-agent-libs/testing/estools"
21+
"github.com/elastic/elastic-agent/pkg/testing/define"
22+
"github.com/elastic/go-elasticsearch/v8"
23+
)
24+
25+
func TestKubernetesJournaldInput(t *testing.T) {
26+
info := define.Require(t, define.Requirements{
27+
Stack: &define.Stack{},
28+
Local: false,
29+
Sudo: false,
30+
OS: []define.OS{
31+
{Type: define.Kubernetes, DockerVariant: "complete"},
32+
},
33+
Group: define.Kubernetes,
34+
})
35+
36+
agentConfigYAML, err := os.ReadFile(filepath.Join("testdata", "journald-input.yml"))
37+
require.NoError(t, err, "failed to read journald input template")
38+
39+
ctx := context.Background()
40+
kCtx := k8sGetContext(t, info)
41+
42+
schedulableNodeCount, err := k8sSchedulableNodeCount(ctx, kCtx)
43+
require.NoError(t, err, "error at getting schedulable node count")
44+
require.NotZero(t, schedulableNodeCount, "no schedulable Kubernetes nodes found")
45+
46+
namespace := kCtx.getNamespace(t)
47+
hostPathType := corev1.HostPathDirectory
48+
49+
steps := []k8sTestStep{
50+
k8sStepCreateNamespace(),
51+
k8sStepDeployKustomize(
52+
agentK8SKustomize,
53+
"elastic-agent-standalone",
54+
k8sKustomizeOverrides{
55+
agentContainerExtraEnv: []corev1.EnvVar{
56+
{
57+
Name: "ELASTICSEARCH_USERNAME",
58+
Value: os.Getenv("ELASTICSEARCH_USERNAME"),
59+
},
60+
{
61+
Name: "ELASTICSEARCH_PASSWORD",
62+
Value: os.Getenv("ELASTICSEARCH_PASSWORD"),
63+
},
64+
{
65+
Name: "EA_POLICY_NAMESPACE",
66+
Value: namespace,
67+
},
68+
},
69+
agentContainerVolumeMounts: []corev1.VolumeMount{
70+
{
71+
Name: "journald-mount",
72+
MountPath: "/opt/journald",
73+
ReadOnly: true,
74+
},
75+
},
76+
agentPodVolumes: []corev1.Volume{
77+
{
78+
Name: "journald-mount",
79+
VolumeSource: corev1.VolumeSource{
80+
HostPath: &corev1.HostPathVolumeSource{
81+
Path: "/run/log/journal",
82+
Type: &hostPathType,
83+
},
84+
},
85+
},
86+
},
87+
},
88+
func(obj k8s.Object) {
89+
// update the configmap to use the journald input
90+
switch objWithType := obj.(type) {
91+
case *corev1.ConfigMap:
92+
_, ok := objWithType.Data["agent.yml"]
93+
if ok {
94+
objWithType.Data["agent.yml"] = string(agentConfigYAML)
95+
}
96+
}
97+
98+
}),
99+
k8sStepCheckAgentStatus(
100+
"app=elastic-agent-standalone",
101+
schedulableNodeCount,
102+
"elastic-agent-standalone",
103+
map[string]bool{
104+
"journald": true,
105+
}),
106+
}
107+
108+
journaldTest(
109+
t,
110+
info.ESClient,
111+
kCtx,
112+
steps,
113+
fmt.Sprintf("logs-generic-%s", namespace),
114+
"input.type",
115+
"journald")
116+
}
117+
118+
func journaldTest(
119+
t *testing.T,
120+
esClient *elasticsearch.Client,
121+
kCtx k8sContext,
122+
steps []k8sTestStep,
123+
index, field, value string) {
124+
t.Helper()
125+
126+
ctx := context.Background()
127+
testNamespace := kCtx.getNamespace(t)
128+
129+
for _, step := range steps {
130+
step(t, ctx, kCtx, testNamespace)
131+
}
132+
133+
// Check if the context was cancelled or timed out
134+
if ctx.Err() != nil {
135+
t.Errorf("context error: %v", ctx.Err())
136+
}
137+
138+
// Query the index and filter by the input type
139+
docs := findESDocs(t, func() (estools.Documents, error) {
140+
return estools.GetLogsForIndexWithContext(
141+
ctx,
142+
esClient,
143+
index,
144+
map[string]any{
145+
field: value,
146+
},
147+
)
148+
})
149+
require.NotEmpty(t, docs, "expected logs to be found in Elasticsearch")
150+
}

testing/integration/kubernetes_agent_standalone_test.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ func getAgentComponentState(status atesting.AgentStatusOutput, componentName str
897897
// k8sDumpPods creates an archive that contains logs of all pods in the given namespace and kube-system to the given target directory
898898
func k8sDumpPods(t *testing.T, ctx context.Context, client klient.Client, testName string, namespace string, targetDir string, testStartTime time.Time) {
899899
// Create the tar file
900-
archivePath := filepath.Join(targetDir, fmt.Sprintf("%s.tar.gz", namespace))
900+
archivePath := filepath.Join(targetDir, fmt.Sprintf("%s.tar", namespace))
901901
tarFile, err := os.Create(archivePath)
902902
if err != nil {
903903
t.Logf("failed to create archive at path %q", archivePath)
@@ -1311,8 +1311,14 @@ type k8sContext struct {
13111311
createdAt time.Time
13121312
}
13131313

1314-
// getNamespace returns a unique namespace for the current test
1314+
// getNamespace returns a unique namespace on every call.
1315+
// If K8S_TESTS_NAMESPACE is set, then its value is returned,
1316+
// otherwise a unique namespace is generated.
13151317
func (k k8sContext) getNamespace(t *testing.T) string {
1318+
if ns := os.Getenv("K8S_TESTS_NAMESPACE"); ns != "" {
1319+
return ns
1320+
}
1321+
13161322
nsUUID, err := uuid.NewV4()
13171323
if err != nil {
13181324
t.Fatalf("error generating namespace UUID: %v", err)
@@ -1379,8 +1385,8 @@ func k8sGetContext(t *testing.T, info *define.Info) k8sContext {
13791385
err = os.MkdirAll(testLogsBasePath, 0o755)
13801386
require.NoError(t, err, "failed to create test logs directory")
13811387

1382-
esHost := os.Getenv("ELASTICSEARCH_HOST")
1383-
require.NotEmpty(t, esHost, "ELASTICSEARCH_HOST must be set")
1388+
esHost, err := getESHost()
1389+
require.NoError(t, err, "cannot parse ELASTICSEARCH_HOST")
13841390

13851391
esAPIKey, err := generateESAPIKey(info.ESClient, info.Namespace)
13861392
require.NoError(t, err, "failed to generate ES API key")
@@ -1440,6 +1446,8 @@ type k8sKustomizeOverrides struct {
14401446
agentContainerExtraEnv []corev1.EnvVar
14411447
agentContainerArgs []string
14421448
agentContainerMemoryLimit string
1449+
agentContainerVolumeMounts []corev1.VolumeMount
1450+
agentPodVolumes []corev1.Volume
14431451
}
14441452

14451453
// k8sStepDeployKustomize renders a kustomize manifest and deploys it. Also, it tries to
@@ -1466,6 +1474,8 @@ func k8sStepDeployKustomize(kustomizePath string, containerName string, override
14661474

14671475
k8sKustomizeAdjustObjects(objects, namespace, containerName,
14681476
func(container *corev1.Container) {
1477+
container.VolumeMounts = append(container.VolumeMounts, overrides.agentContainerVolumeMounts...)
1478+
14691479
// set agent image
14701480
container.Image = kCtx.agentImage
14711481
// set ImagePullPolicy to "Never" to avoid pulling the image
@@ -1509,8 +1519,7 @@ func k8sStepDeployKustomize(kustomizePath string, containerName string, override
15091519
}
15101520

15111521
if overrides.agentContainerArgs != nil {
1512-
// drop arguments overriding default config
1513-
container.Args = []string{}
1522+
container.Args = overrides.agentContainerArgs
15141523
}
15151524
},
15161525
func(pod *corev1.PodSpec) {
@@ -1525,6 +1534,7 @@ func k8sStepDeployKustomize(kustomizePath string, containerName string, override
15251534
}
15261535
}
15271536
}
1537+
pod.Volumes = append(pod.Volumes, overrides.agentPodVolumes...)
15281538
})
15291539

15301540
t.Cleanup(func() {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
outputs:
2+
default:
3+
type: elasticsearch
4+
hosts:
5+
- ${ES_HOST}
6+
username: ${ELASTICSEARCH_USERNAME}
7+
password: ${ELASTICSEARCH_PASSWORD}
8+
9+
agent:
10+
monitoring:
11+
enabled: false
12+
13+
inputs:
14+
- id: journald
15+
log_level: debug
16+
type: journald
17+
data_stream:
18+
namespace: ${env.EA_POLICY_NAMESPACE}
19+
streams:
20+
- id: journald-input-id
21+
paths:
22+
- "/opt/journald/*/*"

0 commit comments

Comments
 (0)