Skip to content

Commit 063f3b7

Browse files
rogercollmergify[bot]
authored andcommitted
Set fullnameOverride and validate Otel kube-stack deployment datastreams are being written (metrics, traces) (#7754)
(cherry picked from commit 8ec0229) # Conflicts: # testing/integration/otel_helm_test.go
1 parent 4b72765 commit 063f3b7

File tree

6 files changed

+178
-42
lines changed

6 files changed

+178
-42
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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: feature
12+
13+
# Change summary; a 80ish characters long description of the change.
14+
summary: set collectors fullnameOverride for edot kube-stack values
15+
16+
# Long description; in case the summary is not enough to describe the change
17+
# this field accommodate a description without length limits.
18+
# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
19+
#description:
20+
21+
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
22+
component: elastic-agent
23+
24+
# PR URL; optional; the PR number that added the changeset.
25+
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
26+
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
27+
# Please provide it if you are adding a fragment for a different PR.
28+
pr: https://github.com/elastic/elastic-agent/pull/7754
29+
30+
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
31+
# If not present is automatically filled by the tooling with the issue linked to the PR number.
32+
issue: https://github.com/elastic/elastic-agent/issues/7381

deploy/helm/edot-collector/kube-stack/managed_otlp/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ collectors:
3333
# Cluster is a K8s deployment EDOT collector focused on gathering telemetry
3434
# at the cluster level (Kubernetes Events and cluster metrics).
3535
cluster:
36+
fullnameOverride: "opentelemetry-kube-stack-cluster-stats"
3637
env:
3738
- name: ELASTIC_AGENT_OTEL
3839
value: '"true"'
@@ -184,6 +185,7 @@ collectors:
184185
# node level and exposing an OTLP endpoint for data ingestion.
185186
# Auto-instrumentation SDKs will use this endpoint.
186187
daemon:
188+
fullnameOverride: "opentelemetry-kube-stack-daemon"
187189
env:
188190
# Work around for open /mounts error: https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/35990
189191
- name: HOST_PROC_MOUNTINFO
@@ -525,6 +527,7 @@ collectors:
525527
# Gateway is a K8s deployment EDOT collector focused on processing and
526528
# forwarding telemetry to an Elasticsearch endpoint.
527529
gateway:
530+
fullnameOverride: "opentelemetry-kube-stack-gateway"
528531
suffix: gateway
529532
replicas: 2
530533
autoscaler:

deploy/helm/edot-collector/kube-stack/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ collectors:
3333
# Cluster is a K8s deployment EDOT collector focused on gathering telemetry
3434
# at the cluster level (Kubernetes Events and cluster metrics).
3535
cluster:
36+
fullnameOverride: "opentelemetry-kube-stack-cluster-stats"
3637
env:
3738
- name: ELASTIC_AGENT_OTEL
3839
value: '"true"'
@@ -184,6 +185,7 @@ collectors:
184185
# node level and exposing an OTLP endpoint for data ingestion.
185186
# Auto-instrumentation SDKs will use this endpoint.
186187
daemon:
188+
fullnameOverride: "opentelemetry-kube-stack-daemon"
187189
env:
188190
# Work around for open /mounts error: https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/35990
189191
- name: HOST_PROC_MOUNTINFO
@@ -525,6 +527,7 @@ collectors:
525527
# Gateway is a K8s deployment EDOT collector focused on processing and
526528
# forwarding telemetry to an Elasticsearch endpoint.
527529
gateway:
530+
fullnameOverride: "opentelemetry-kube-stack-gateway"
528531
resources:
529532
limits:
530533
cpu: 1500m

testing/integration/kubernetes_agent_standalone_test.go

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/stretchr/testify/require"
3030

3131
"github.com/elastic/elastic-agent-libs/kibana"
32+
"github.com/elastic/elastic-agent-libs/testing/estools"
3233
"github.com/elastic/go-elasticsearch/v8"
3334

3435
appsv1 "k8s.io/api/apps/v1"
@@ -861,7 +862,8 @@ func k8sCheckAgentStatus(ctx context.Context, client klient.Client, stdout *byte
861862

862863
// k8sGetAgentID returns the agent ID for the given agent pod
863864
func k8sGetAgentID(ctx context.Context, client klient.Client, stdout *bytes.Buffer, stderr *bytes.Buffer,
864-
namespace string, agentPodName string, containerName string) (string, error) {
865+
namespace string, agentPodName string, containerName string,
866+
) (string, error) {
865867
command := []string{"elastic-agent", "status", "--output=json"}
866868

867869
status := atesting.AgentStatusOutput{} // clear status output
@@ -994,7 +996,7 @@ func k8sDumpPods(t *testing.T, ctx context.Context, client klient.Client, testNa
994996
header := &tar.Header{
995997
Name: logFileName,
996998
Size: int64(len(b)),
997-
Mode: 0600,
999+
Mode: 0o600,
9981000
ModTime: time.Now(),
9991001
AccessTime: time.Now(),
10001002
ChangeTime: time.Now(),
@@ -1021,7 +1023,7 @@ func k8sDumpPods(t *testing.T, ctx context.Context, client klient.Client, testNa
10211023
header := &tar.Header{
10221024
Name: statesDumpFile,
10231025
Size: int64(len(b)),
1024-
Mode: 0600,
1026+
Mode: 0o600,
10251027
ModTime: time.Now(),
10261028
AccessTime: time.Now(),
10271029
ChangeTime: time.Now(),
@@ -1099,35 +1101,8 @@ func k8sRenderKustomize(kustomizePath string) ([]byte, error) {
10991101
}
11001102

11011103
// generateESAPIKey generates an API key for the given Elasticsearch.
1102-
func generateESAPIKey(esClient *elasticsearch.Client, keyName string) (string, error) {
1103-
apiKeyReqBody := fmt.Sprintf(`{
1104-
"name": "%s",
1105-
"expiration": "1d"
1106-
}`, keyName)
1107-
1108-
resp, err := esClient.Security.CreateAPIKey(strings.NewReader(apiKeyReqBody))
1109-
if err != nil {
1110-
return "", err
1111-
}
1112-
defer resp.Body.Close()
1113-
1114-
response := make(map[string]interface{})
1115-
err = json.NewDecoder(resp.Body).Decode(&response)
1116-
if err != nil {
1117-
return "", err
1118-
}
1119-
1120-
keyToken := response["api_key"].(string)
1121-
if keyToken == "" {
1122-
return "", fmt.Errorf("key token is empty")
1123-
}
1124-
1125-
keyID := response["id"].(string)
1126-
if keyID == "" {
1127-
return "", fmt.Errorf("key ID is empty")
1128-
}
1129-
1130-
return fmt.Sprintf("%s:%s", keyID, keyToken), nil
1104+
func generateESAPIKey(esClient *elasticsearch.Client, keyName string) (estools.APIKeyResponse, error) {
1105+
return estools.CreateAPIKey(context.Background(), esClient, estools.APIKeyRequest{Name: keyName, Expiration: "1d"})
11311106
}
11321107

11331108
// k8sDeleteOpts contains options for deleting k8s objects
@@ -1327,6 +1302,8 @@ type k8sContext struct {
13271302
esHost string
13281303
// esAPIKey is the API key of the elasticsearch to use in the test
13291304
esAPIKey string
1305+
// esEncodedAPIKey is the encoded API key of the elasticsearch to use in the test
1306+
esEncodedAPIKey string
13301307
// enrollParams contains the information needed to enroll an agent with Fleet in the test
13311308
enrollParams *fleettools.EnrollParams
13321309
// createdAt is the time when the k8sContext was created
@@ -1412,16 +1389,17 @@ func k8sGetContext(t *testing.T, info *define.Info) k8sContext {
14121389
require.NoError(t, err, "failed to create fleet enroll params")
14131390

14141391
return k8sContext{
1415-
client: client,
1416-
clientSet: clientSet,
1417-
agentImage: agentImage,
1418-
agentImageRepo: agentImageRepo,
1419-
agentImageTag: agentImageTag,
1420-
logsBasePath: testLogsBasePath,
1421-
esHost: esHost,
1422-
esAPIKey: esAPIKey,
1423-
enrollParams: enrollParams,
1424-
createdAt: time.Now(),
1392+
client: client,
1393+
clientSet: clientSet,
1394+
agentImage: agentImage,
1395+
agentImageRepo: agentImageRepo,
1396+
agentImageTag: agentImageTag,
1397+
logsBasePath: testLogsBasePath,
1398+
esHost: esHost,
1399+
esAPIKey: esAPIKey.APIKey,
1400+
esEncodedAPIKey: esAPIKey.Encoded,
1401+
enrollParams: enrollParams,
1402+
createdAt: time.Now(),
14251403
}
14261404
}
14271405

testing/integration/otel_helm_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
package integration
88

99
import (
10+
"bufio"
11+
"bytes"
1012
"context"
1113
"fmt"
14+
"os"
15+
"path/filepath"
1216
"testing"
1317
"time"
1418

@@ -20,7 +24,9 @@ import (
2024
corev1 "k8s.io/api/core/v1"
2125
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2226

27+
"github.com/elastic/elastic-agent-libs/testing/estools"
2328
"github.com/elastic/elastic-agent/pkg/testing/define"
29+
testK8s "github.com/elastic/elastic-agent/pkg/testing/kubernetes"
2430
)
2531

2632
var (
@@ -37,6 +43,12 @@ func TestOtelKubeStackHelm(t *testing.T) {
3743
// only test the basic and the wolfi container with otel
3844
{Type: define.Kubernetes, DockerVariant: "basic"},
3945
{Type: define.Kubernetes, DockerVariant: "wolfi"},
46+
<<<<<<< HEAD
47+
=======
48+
// elastic otel collector image
49+
{Type: define.Kubernetes, DockerVariant: "elastic-otel-collector"},
50+
{Type: define.Kubernetes, DockerVariant: "elastic-otel-collector-wolfi"},
51+
>>>>>>> 8ec022980 (Set fullnameOverride and validate Otel kube-stack deployment datastreams are being written (metrics, traces) (#7754))
4052
},
4153
Group: define.Kubernetes,
4254
})
@@ -64,12 +76,26 @@ func TestOtelKubeStackHelm(t *testing.T) {
6476
k8sStepHelmDeployWithValueOptions(chartLocation, "kube-stack-otel",
6577
values.Options{
6678
ValueFiles: []string{"../../deploy/helm/edot-collector/kube-stack/values.yaml"},
79+
<<<<<<< HEAD
6780
Values: []string{fmt.Sprintf("defaultCRConfig.image.repository=%s", kCtx.agentImageRepo), fmt.Sprintf("defaultCRConfig.image.tag=%s", kCtx.agentImageTag)},
81+
=======
82+
Values: []string{
83+
fmt.Sprintf("defaultCRConfig.image.repository=%s", kCtx.agentImageRepo),
84+
fmt.Sprintf("defaultCRConfig.image.tag=%s", kCtx.agentImageTag),
85+
// override cluster wide
86+
// endpoint for tests
87+
"instrumentation.exporter.endpoint=http://opentelemetry-kube-stack-daemon-collector:4318",
88+
},
89+
>>>>>>> 8ec022980 (Set fullnameOverride and validate Otel kube-stack deployment datastreams are being written (metrics, traces) (#7754))
6890

6991
// override secrets reference with env variables
7092
JSONValues: []string{
7193
fmt.Sprintf(`collectors.gateway.env[1]={"name":"ELASTIC_ENDPOINT","value":"%s"}`, kCtx.esHost),
94+
<<<<<<< HEAD
7295
fmt.Sprintf(`collectors.gateway.env[2]={"name":"ELASTIC_API_KEY","value":"%s"}`, kCtx.esAPIKey),
96+
=======
97+
fmt.Sprintf(`collectors.gateway.env[2]={"name":"ELASTIC_API_KEY","value":"%s"}`, kCtx.esEncodedAPIKey),
98+
>>>>>>> 8ec022980 (Set fullnameOverride and validate Otel kube-stack deployment datastreams are being written (metrics, traces) (#7754))
7399
},
74100
},
75101
),
@@ -83,6 +109,18 @@ func TestOtelKubeStackHelm(t *testing.T) {
83109
// - Two Gateway pods to collect, aggregate and forward
84110
// telemetry.
85111
k8sStepCheckRunningPods("app.kubernetes.io/managed-by=opentelemetry-operator", 4, "otc-container"),
112+
<<<<<<< HEAD
113+
=======
114+
// validate kubeletstats metrics are being
115+
// pushed
116+
k8sStepCheckDatastreamsHits(info, "metrics", "kubeletstatsreceiver.otel", "default"),
117+
// validates auto-instrumentation and traces
118+
// datastream generation
119+
func(t *testing.T, ctx context.Context, kCtx k8sContext, namespace string) {
120+
k8sStepDeployJavaApp()(t, ctx, kCtx, namespace)
121+
k8sStepCheckDatastreamsHits(info, "traces", "generic.otel", "default")(t, ctx, kCtx, namespace)
122+
},
123+
>>>>>>> 8ec022980 (Set fullnameOverride and validate Otel kube-stack deployment datastreams are being written (metrics, traces) (#7754))
86124
},
87125
},
88126
{
@@ -175,3 +213,61 @@ func k8sStepCheckRunningPods(podLabelSelector string, expectedPodNumber int, con
175213
}, 5*time.Minute, 10*time.Second, fmt.Sprintf("at least %d agent containers should be checked", expectedPodNumber))
176214
}
177215
}
216+
217+
func k8sStepDeployJavaApp() k8sTestStep {
218+
return func(t *testing.T, ctx context.Context, kCtx k8sContext, namespace string) {
219+
javaApp, err := os.ReadFile(filepath.Join("testdata", "java_app.yaml"))
220+
require.NoError(t, err)
221+
222+
objects, err := testK8s.LoadFromYAML(bufio.NewReader(bytes.NewReader(javaApp)))
223+
require.NoError(t, err, "failed to parse rendered kustomize")
224+
225+
err = k8sCreateObjects(ctx, kCtx.client, k8sCreateOpts{wait: true, namespace: namespace}, objects...)
226+
require.NoError(t, err, "failed to create objects")
227+
}
228+
}
229+
230+
// k8sStepCheckDatastreams checks the corresponding Elasticsearch datastreams
231+
// are created and documents being written
232+
func k8sStepCheckDatastreamsHits(info *define.Info, dsType, dataset, datastreamNamespace string) k8sTestStep {
233+
return func(t *testing.T, ctx context.Context, kCtx k8sContext, namespace string) {
234+
require.Eventually(t, func() bool {
235+
query := queryK8sNamespaceDataStream(dsType, dataset, datastreamNamespace, namespace)
236+
docs, err := estools.PerformQueryForRawQuery(ctx, query, fmt.Sprintf(".ds-%s*", dsType), info.ESClient)
237+
require.NoError(t, err, "failed to get %s datastream documents", fmt.Sprintf("%s-%s-%s", dsType, dataset, datastreamNamespace))
238+
return docs.Hits.Total.Value > 0
239+
}, 5*time.Minute, 10*time.Second, fmt.Sprintf("at least one document should be available for %s datastream", fmt.Sprintf("%s-%s-%s", dsType, dataset, datastreamNamespace)))
240+
}
241+
}
242+
243+
func queryK8sNamespaceDataStream(dsType, dataset, datastreamNamespace, k8snamespace string) map[string]any {
244+
return map[string]any{
245+
"_source": []string{"message"},
246+
"query": map[string]any{
247+
"bool": map[string]any{
248+
"filter": []any{
249+
map[string]any{
250+
"term": map[string]any{
251+
"data_stream.dataset": dataset,
252+
},
253+
},
254+
map[string]any{
255+
"term": map[string]any{
256+
"data_stream.namespace": datastreamNamespace,
257+
},
258+
},
259+
map[string]any{
260+
"term": map[string]any{
261+
"data_stream.type": dsType,
262+
},
263+
},
264+
map[string]any{
265+
"term": map[string]any{
266+
"resource.attributes.k8s.namespace.name": k8snamespace,
267+
},
268+
},
269+
},
270+
},
271+
},
272+
}
273+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
labels:
5+
app: java-app
6+
name: java-app
7+
spec:
8+
replicas: 1
9+
selector:
10+
matchLabels:
11+
app: java-app
12+
template:
13+
metadata:
14+
labels:
15+
app: java-app
16+
annotations:
17+
instrumentation.opentelemetry.io/inject-java: "true"
18+
spec:
19+
containers:
20+
- name: java-app
21+
image: docker.elastic.co/demos/apm/k8s-webhook-test
22+
env:
23+
- name: OTEL_INSTRUMENTATION_METHODS_INCLUDE
24+
value: "test.Testing[methodB]"

0 commit comments

Comments
 (0)