Skip to content

Commit

Permalink
feat(metrics): add collector deployment to collect cluster metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
basti1302 committed Sep 5, 2024
1 parent 9f4fa32 commit 4be6df0
Show file tree
Hide file tree
Showing 15 changed files with 426 additions and 127 deletions.
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,6 @@ install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~
.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) --wait=false -f -
sleep 1
$(KUSTOMIZE) build config/crd | $(KUBECTL) patch CustomResourceDefinition dash0monitorings.operator.dash0.com -p '{"metadata":{"finalizers":null}}' --type=merge

.PHONY: deploy-via-helm
deploy-via-helm: ## Deploy the controller via helm to the K8s cluster specified in ~/.kube/config.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,12 @@ rules:
- apiGroups:
- apps
resources:
# Note: apps.daemonsets are also listed further up together with the other workload types in the apps API group, with
# fewer permissions. The declaration here extends that list of permissions to make sure we can also create and delete
# the daemonsets for the OTel collector instances that the Dash0 operator manages.
# Note: apps.daemonsets and app.deployments are also listed further up together with the other workload types in the
# apps API group, with fewer permissions. The declaration here extends that list of permissions to make sure we can
# also create and delete the daemonset and deployment for the OTel collector instance that the Dash0 operator
# manages.
- daemonsets
- deployments
verbs:
- create
- delete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ cluster roles should match snapshot:
- apps
resources:
- daemonsets
- deployments
verbs:
- create
- delete
Expand Down
2 changes: 2 additions & 0 deletions images/collector/src/builder/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ exporters:
receivers:
- gomod: "go.opentelemetry.io/collector/receiver/otlpreceiver v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver v0.106.1"

processors:
Expand All @@ -30,4 +31,5 @@ processors:
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourcedetectionprocessor v0.106.1"
- gomod: "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor v0.106.1"
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,34 @@ var (
daemonSetCollectorConfigurationTemplate = template.Must(
template.New("daemonset-collector-configuration").Parse(daemonSetCollectorConfigurationTemplateSource))

////go:embed deployment.config.yaml.template
//deploymentCollectorConfigurationTemplateSource string
//deploymentCollectorConfigurationTemplate = template.Must(
// template.New("deployment-collector-configuration").Parse(deploymentCollectorConfigurationTemplateSource))
//go:embed deployment.config.yaml.template
deploymentCollectorConfigurationTemplateSource string
deploymentCollectorConfigurationTemplate = template.Must(
template.New("deployment-collector-configuration").Parse(deploymentCollectorConfigurationTemplateSource))

authHeaderValue = fmt.Sprintf("Bearer ${env:%s}", authTokenEnvVarName)
)

func assembleDaemonSetCollectorConfigMap(config *oTelColConfig) (*corev1.ConfigMap, error) {
return assembleCollectorConfigMap(config, daemonSetCollectorConfigurationTemplate)
return assembleCollectorConfigMap(
config,
daemonSetCollectorConfigurationTemplate,
daemonSetCollectorConfigConfigMapName(config.NamePrefix),
)
}

//func assembleDeploymentCollectorConfigMap(config *oTelColConfig) (*corev1.ConfigMap, error) {
// return assembleCollectorConfigMap(config, deploymentCollectorConfigurationTemplate)
//}
func assembleDeploymentCollectorConfigMap(config *oTelColConfig) (*corev1.ConfigMap, error) {
return assembleCollectorConfigMap(
config,
deploymentCollectorConfigurationTemplate,
deploymentCollectorConfigConfigMapName(config.NamePrefix),
)
}

func assembleCollectorConfigMap(
config *oTelColConfig,
template *template.Template,
configMapName string,
) (*corev1.ConfigMap, error) {
exporters, err := ConvertExportSettingsToExporterList(config.Export)
if err != nil {
Expand Down Expand Up @@ -79,7 +88,7 @@ func assembleCollectorConfigMap(
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: collectorConfigConfigMapName(config.NamePrefix),
Name: configMapName,
Namespace: config.Namespace,
Labels: labels(false),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import (
. "github.com/dash0hq/dash0-operator/test/util"
)

type testConfig struct {
assembleConfigMapFunction func(config *oTelColConfig) (*corev1.ConfigMap, error)
pipelineNames []string
}

const (
GrpcEndpointTest = "example.com:4317"
HttpEndpointTest = "https://example.com:4318"
Expand All @@ -29,17 +34,38 @@ var (

var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {

It("should fail if no exporter is configured", func() {
_, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
testConfigs := []TableEntry{
Entry(
"for the DaemonSet",
testConfig{
assembleConfigMapFunction: assembleDaemonSetCollectorConfigMap,
pipelineNames: []string{
"traces/downstream",
"metrics/downstream",
"logs/downstream",
},
}),
Entry(
"for the Deployment",
testConfig{
assembleConfigMapFunction: assembleDeploymentCollectorConfigMap,
pipelineNames: []string{
"metrics/downstream",
},
}),
}

DescribeTable("should fail if no exporter is configured", func(testConfig testConfig) {
_, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{},
})
Expect(err).To(HaveOccurred())
})
}, testConfigs)

It("should fail to render the Dash0 exporter when no endpoint is provided", func() {
_, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should fail to render the Dash0 exporter when no endpoint is provided", func(testConfig testConfig) {
_, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand All @@ -55,10 +81,10 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
ContainSubstring(
"no endpoint provided for the Dash0 exporter, unable to create the OpenTelemetry collector")))

})
}, testConfigs)

It("should render the Dash0 exporter", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render the Dash0 exporter", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -91,11 +117,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers[util.Dash0DatasetHeaderName]).To(BeNil())
Expect(dash0OtlpExporter["encoding"]).To(BeNil())

verifyDownstreamExportersInPipelines(collectorConfig, "otlp/dash0")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlp/dash0")
}, testConfigs)

It("should render the Dash0 exporter with custom dataset", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render the Dash0 exporter with custom dataset", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -129,11 +155,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers[util.Dash0DatasetHeaderName]).To(Equal("custom-dataset"))
Expect(dash0OtlpExporter["encoding"]).To(BeNil())

verifyDownstreamExportersInPipelines(collectorConfig, "otlp/dash0")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlp/dash0")
}, testConfigs)

It("should render a verbose debug exporter in development mode", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render a verbose debug exporter in development mode", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -172,11 +198,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers[util.Dash0DatasetHeaderName]).To(BeNil())
Expect(dash0OtlpExporter["encoding"]).To(BeNil())

verifyDownstreamExportersInPipelines(collectorConfig, "debug", "otlp/dash0")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "debug", "otlp/dash0")
}, testConfigs)

It("should fail to render a gRPC exporter when no endpoint is provided", func() {
_, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should fail to render a gRPC exporter when no endpoint is provided", func(testConfig testConfig) {
_, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand All @@ -193,10 +219,10 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
ContainSubstring(
"no endpoint provided for the gRPC exporter, unable to create the OpenTelemetry collector")))

})
}, testConfigs)

It("should render an arbitrary gRPC exporter", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render an arbitrary gRPC exporter", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -236,11 +262,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers["Key2"]).To(Equal("Value2"))
Expect(otlpGrpcExporter["encoding"]).To(BeNil())

verifyDownstreamExportersInPipelines(collectorConfig, "otlp/grpc")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlp/grpc")
}, testConfigs)

It("should fail to render an HTTP exporter when no endpoint is provided", func() {
_, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should fail to render an HTTP exporter when no endpoint is provided", func(testConfig testConfig) {
_, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand All @@ -257,10 +283,10 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
MatchError(
ContainSubstring(
"no endpoint provided for the HTTP exporter, unable to create the OpenTelemetry collector")))
})
}, testConfigs)

It("should fail to render an HTTP exporter when no encoding is provided", func() {
_, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should fail to render an HTTP exporter when no encoding is provided", func(testConfig testConfig) {
_, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand All @@ -278,10 +304,10 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
ContainSubstring(
"no encoding provided for the HTTP exporter, unable to create the OpenTelemetry collector")))

})
}, testConfigs)

It("should render an arbitrary HTTP exporter", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render an arbitrary HTTP exporter", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -322,11 +348,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers["Key2"]).To(Equal("Value2"))
Expect(otlpHttpExporter["encoding"]).To(Equal("json"))

verifyDownstreamExportersInPipelines(collectorConfig, "otlphttp/json")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlphttp/json")
}, testConfigs)

It("should render the Dash0 exporter together with a gRPC exporter", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render the Dash0 exporter together with a gRPC exporter", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -376,11 +402,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers["Key1"]).To(Equal("Value1"))
Expect(httpExporter["encoding"]).To(BeNil())

verifyDownstreamExportersInPipelines(collectorConfig, "otlp/dash0", "otlp/grpc")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlp/dash0", "otlp/grpc")
}, testConfigs)

It("should render the Dash0 exporter together with an HTTP exporter", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render the Dash0 exporter together with an HTTP exporter", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -431,11 +457,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers["Key1"]).To(Equal("Value1"))
Expect(httpExporter["encoding"]).To(Equal("proto"))

verifyDownstreamExportersInPipelines(collectorConfig, "otlp/dash0", "otlphttp/proto")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlp/dash0", "otlphttp/proto")
}, testConfigs)

It("should render a gRPC exporter together with an HTTP exporter", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render a gRPC exporter together with an HTTP exporter", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -488,11 +514,11 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers["Key2"]).To(Equal("Value2"))
Expect(httpExporter["encoding"]).To(Equal("proto"))

verifyDownstreamExportersInPipelines(collectorConfig, "otlp/grpc", "otlphttp/proto")
})
verifyDownstreamExportersInPipelines(collectorConfig, testConfig, "otlp/grpc", "otlphttp/proto")
}, testConfigs)

It("should render a combination of all three exporter types", func() {
configMap, err := assembleDaemonSetCollectorConfigMap(&oTelColConfig{
DescribeTable("should render a combination of all three exporter types", func(testConfig testConfig) {
configMap, err := testConfig.assembleConfigMapFunction(&oTelColConfig{
Namespace: namespace,
NamePrefix: namePrefix,
Export: dash0v1alpha1.Export{
Expand Down Expand Up @@ -566,8 +592,15 @@ var _ = Describe("The OpenTelemetry Collector ConfigMap conent", func() {
Expect(headers["Key2"]).To(Equal("Value2"))
Expect(httpExporter["encoding"]).To(Equal("json"))

verifyDownstreamExportersInPipelines(collectorConfig, "debug", "otlp/dash0", "otlp/grpc", "otlphttp/json")
})
verifyDownstreamExportersInPipelines(
collectorConfig,
testConfig,
"debug",
"otlp/dash0",
"otlp/grpc",
"otlphttp/json",
)
}, testConfigs)
})

func parseConfigMapContent(configMap *corev1.ConfigMap) map[string]interface{} {
Expand All @@ -578,19 +611,17 @@ func parseConfigMapContent(configMap *corev1.ConfigMap) map[string]interface{} {
return *configMapParsed
}

func verifyDownstreamExportersInPipelines(collectorConfig map[string]interface{}, expectedExporters ...string) {
func verifyDownstreamExportersInPipelines(
collectorConfig map[string]interface{},
testConfig testConfig,
expectedExporters ...string,
) {
pipelines := ((collectorConfig["service"]).(map[string]interface{})["pipelines"]).(map[string]interface{})
Expect(pipelines).ToNot(BeNil())
tracesPipeline := (pipelines["traces/downstream"]).(map[string]interface{})
tracesExporters := (tracesPipeline["exporters"]).([]interface{})
Expect(tracesExporters).To(HaveLen(len(expectedExporters)))
Expect(tracesExporters).To(ContainElements(expectedExporters))
metricsPipeline := (pipelines["metrics/downstream"]).(map[string]interface{})
metricsExporters := (metricsPipeline["exporters"]).([]interface{})
Expect(metricsExporters).To(HaveLen(len(expectedExporters)))
Expect(metricsExporters).To(ContainElements(expectedExporters))
logsPipeline := (pipelines["logs/downstream"]).(map[string]interface{})
logsExporters := (logsPipeline["exporters"]).([]interface{})
Expect(logsExporters).To(ContainElements(expectedExporters))
Expect(logsExporters).To(HaveLen(len(expectedExporters)))
for _, pipelineName := range testConfig.pipelineNames {
pipeline := (pipelines[pipelineName]).(map[string]interface{})
exporters := (pipeline["exporters"]).([]interface{})
Expect(exporters).To(HaveLen(len(expectedExporters)))
Expect(exporters).To(ContainElements(expectedExporters))
}
}
Loading

0 comments on commit 4be6df0

Please sign in to comment.