Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 config/recipes/elastic-agent/README.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Deploys Elastic Agent as a DaemonSet in Fleet mode with System and Kubernetes in

===== System and Kubernetes integrations running as non-root - `fleet-kubernetes-integration-nonroot.yaml`

The provided example is functionally identical to the previous section but runs the Elastic Agent processes (both the Elastic Agent running as the Fleet server and the Elastic Agent connected to Fleet) as a non-root user by utilizing a DaemonSet to ensure directory and file permissions. *Note* The DaemonSet itself must run as root to set up permissions and ECK >= 2.10.0 is required.
The provided example is functionally identical to the previous section but runs the Elastic Agent processes (both the Elastic Agent running as the Fleet server and the Elastic Agent connected to Fleet) as a non-root user by utilizing a DaemonSet to ensure directory and file permissions. *Note* This is only required when Elastic Agent is < 8.16.0. Also the DaemonSet itself must run as root to set up permissions and ECK >= 2.10.0 is required.

===== Custom logs integration with autodiscover - `fleet-custom-logs-integration.yaml`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
---
# This example only applies to Elastic Agent versions < v8.16.0.
# Since Elastic Agent v8.16.0, the `runAsUser: 0` is not needed
# as Agent changes the ownership of the volumes mounts to the container user id.
apiVersion: apps/v1
kind: DaemonSet
metadata:
Expand Down
12 changes: 8 additions & 4 deletions config/recipes/elastic-agent/fleet-kubernetes-integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ spec:
spec:
serviceAccountName: fleet-server
automountServiceAccountToken: true
securityContext:
runAsUser: 0
# Since Elastic Agent v8.16.0, the runAsUser: 0 is not needed
# as Agent changes ownership of the data directory to the container user id.
# securityContext:
# runAsUser: 0
---
apiVersion: agent.k8s.elastic.co/v1alpha1
kind: Agent
Expand Down Expand Up @@ -114,8 +116,10 @@ spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
automountServiceAccountToken: true
securityContext:
runAsUser: 0
# Since Elastic Agent v8.16.0, the runAsUser: 0 is not needed
# as Agent changes ownership of the data directory to the container user id.
# securityContext:
# runAsUser: 0
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
Expand Down
63 changes: 0 additions & 63 deletions test/e2e/agent/recipes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,69 +124,6 @@ func TestFleetKubernetesIntegrationRecipe(t *testing.T) {
runAgentRecipe(t, "fleet-kubernetes-integration.yaml", customize)
}

func TestFleetKubernetesNonRootIntegrationRecipe(t *testing.T) {
v := version.MustParse(test.Ctx().ElasticStackVersion)

if (v.GE(version.MinFor(7, 17, 28)) && v.LT(version.MinFor(8, 0, 0))) ||
(v.GE(version.MinFor(8, 1, 3)) && v.LT(version.MinFor(8, 2, 0))) {
t.Skipf("Skipped as version %s is affected by https://github.com/elastic/kibana/pull/236788", v)
}

// https://github.com/elastic/cloud-on-k8s/issues/6331
if v.LT(version.MinFor(8, 7, 0)) && v.GE(version.MinFor(8, 6, 0)) {
t.SkipNow()
}

if (v.GE(version.MinFor(9, 0, 1)) && v.LE(version.MinFor(9, 0, 4))) ||
(v.EQ(version.From(9, 1, 0))) ||
(v.EQ(version.MustParse("9.3.0-SNAPSHOT"))) { // TODO remove once https://github.com/elastic/kibana/pull/230211 is backported to 9.3.x
t.Skipf("Skipped as version %s is affected by https://github.com/elastic/kibana/pull/230211", v)
}

// Do not test between 9.1.0 and 9.1.5 due to broken ssl settings in Kibana, see https://github.com/elastic/cloud-on-k8s/issues/8820
if v.GE(version.From(9, 1, 0)) && v.LT(version.From(9, 1, 5)) {
t.Skipf("Skipped as version %s is affected by https://github.com/elastic/kibana/issues/233780", v)
}

// The recipe does not work fully within an openshift cluster without modifications.
if test.Ctx().OcpCluster {
t.SkipNow()
}

customize := func(builder agent.Builder) agent.Builder {
if !builder.Agent.Spec.FleetServerEnabled {
return builder
}

return builder.
WithFleetAgentDataStreamsValidation().
// TODO API server should generate event in time but on kind we see repeatedly no metrics being reported in time
// see https://github.com/elastic/cloud-on-k8s/issues/4092
// WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.apiserver", "k8s")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.container", "default")).
// Might not generate an event in time for this check to succeed in all environments
// WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.event", "k8s")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.node", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.pod", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.proxy", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.system", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "kubernetes.volume", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.cpu", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.diskio", "default")).
// to be reinstated once https://github.com/elastic/beats/issues/30590 is addressed
// WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.fsstat", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.load", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.memory", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.network", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.process", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.process.summary", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.socket_summary", "default")).
WithDefaultESValidation(agent.HasWorkingDataStream(agent.MetricsType, "system.uptime", "default"))
}

runAgentRecipe(t, "fleet-kubernetes-integration-nonroot.yaml", customize)
}

func TestFleetCustomLogsIntegrationRecipe(t *testing.T) {
v := version.MustParse(test.Ctx().ElasticStackVersion)

Expand Down
72 changes: 1 addition & 71 deletions test/e2e/test/helper/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,12 +359,8 @@ func transformToE2E(namespace, fullTestName, suffix string, transformers []Build
decodedObj.Namespace = namespace
decodedObj.Name = decodedObj.Name + "-" + suffix
case *appsv1.DaemonSet:
name := decodedObj.Name + "-" + suffix
decodedObj.Namespace = namespace
decodedObj.Name = name
decodedObj.Spec.Selector.MatchLabels["app.kubernetes.io/instance"] = name
decodedObj.Spec.Template.ObjectMeta.Labels["app.kubernetes.io/instance"] = name
maybeMutateForAgentNonRootTests(decodedObj, namespace, suffix)
decodedObj.Name = decodedObj.Name + "-" + suffix
}

if builder != nil {
Expand All @@ -389,30 +385,6 @@ func transformToE2E(namespace, fullTestName, suffix string, transformers []Build
return builders, otherObjects
}

// maybeMutateForAgentNonRootTests will possibly mutate the given daemonset when
// running tests for Elastic Agent running as non-root. This is required as the
// directories depend on both the namespace and the random suffix of the e2e tests.
func maybeMutateForAgentNonRootTests(ds *appsv1.DaemonSet, namespace, suffix string) {
for i, init := range ds.Spec.Template.Spec.InitContainers {
if init.Name == "manage-agent-hostpath-permissions" {
for j, cmd := range ds.Spec.Template.Spec.InitContainers[i].Command {
updatedCmd := strings.Replace(
cmd,
"/var/lib/elastic-agent/default/elastic-agent/state",
fmt.Sprintf("/var/lib/elastic-agent/%s/elastic-agent-%s/state", namespace, suffix),
1,
)
ds.Spec.Template.Spec.InitContainers[i].Command[j] = strings.Replace(
updatedCmd,
"/var/lib/elastic-agent/default/fleet-server/state",
fmt.Sprintf("/var/lib/elastic-agent/%s/fleet-server-%s/state", namespace, suffix),
1,
)
}
}
}
}

// sortBuilders mutates the given builder slice to sort them by test priority:
// Elasticsearch > Kibana > APMServer > Enterprise Search > Beats
// The underlying goal is, for example, to ensure Elasticsearch is available before we start testing Beats.
Expand Down Expand Up @@ -498,48 +470,6 @@ func tweakConfigLiterals(config *commonv1.Config, suffix string, namespace strin
}
}

fleetOutputsKey := "xpack.fleet.outputs"

// This is only used when testing Agent+Fleet running as non-root. (config/recipes/elastic-agent/fleet-kubernetes-integration-nonroot.yaml)
//
// Adjust the Kibana's spec.config.xpack.fleet.outputs section to both
// 1. Point to the valid Elasticsearch instance with suffix + namespace being random
// 2. Point to the valid mounted Elasticsearch CA with a random suffix + namespace in the mount path.
if untypedOutputs, ok := data[fleetOutputsKey]; ok { //nolint:nestif
if untypedXpackOutputsSlice, ok := untypedOutputs.([]interface{}); ok {
for _, untypedOutputMap := range untypedXpackOutputsSlice {
if outputMap, ok := untypedOutputMap.(map[string]interface{}); ok {
if outputMap["id"] == "eck-fleet-agent-output-elasticsearch" {
if outputSlice, ok := outputMap["hosts"].([]interface{}); ok {
for j, untypedHost := range outputSlice {
if host, ok := untypedHost.(string); ok {
outputSlice[j] = strings.ReplaceAll(
host,
"elasticsearch-es-http.default",
fmt.Sprintf("elasticsearch-%s-es-http.%s", suffix, namespace),
)
}
}
}
if untypedSSL, ok := outputMap["ssl"].(map[string]interface{}); ok {
if untypedCAs, ok := untypedSSL["certificate_authorities"].([]interface{}); ok {
for k, untypedCA := range untypedCAs {
if ca, ok := untypedCA.(string); ok {
untypedCAs[k] = strings.ReplaceAll(
ca,
"elasticsearch-association/default/elasticsearch/",
fmt.Sprintf("elasticsearch-association/%s/elasticsearch-%s/", namespace, suffix),
)
}
}
}
}
}
}
}
}
}

return data
}

Expand Down