From c683ee18ce0cf98bbee3db04ac2ab42d29bc5f41 Mon Sep 17 00:00:00 2001 From: Ankit152 Date: Mon, 28 Oct 2024 19:38:07 +0530 Subject: [PATCH 1/4] feat: create service for extensions Signed-off-by: Ankit152 --- apis/v1beta1/config.go | 7 +++++- internal/components/extensions/helpers.go | 3 +++ internal/manifests/collector/service.go | 28 +++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apis/v1beta1/config.go b/apis/v1beta1/config.go index 82fd9a1325..f8fe348562 100644 --- a/apis/v1beta1/config.go +++ b/apis/v1beta1/config.go @@ -206,7 +206,8 @@ func (c *Config) getPortsForComponentKinds(logger logr.Logger, componentKinds .. case KindProcessor: continue case KindExtension: - continue + retriever = extensions.ParserFor + cfg = *c.Extensions } for componentName := range enabledComponents[componentKind] { // TODO: Clean up the naming here and make it simpler to use a retriever. @@ -318,6 +319,10 @@ func (c *Config) GetExporterPorts(logger logr.Logger) ([]corev1.ServicePort, err return c.getPortsForComponentKinds(logger, KindExporter) } +func (c *Config) GetExtensionPorts(logger logr.Logger) ([]corev1.ServicePort, error) { + return c.getPortsForComponentKinds(logger, KindExtension) +} + func (c *Config) GetAllPorts(logger logr.Logger) ([]corev1.ServicePort, error) { return c.getPortsForComponentKinds(logger, KindReceiver, KindExporter) } diff --git a/internal/components/extensions/helpers.go b/internal/components/extensions/helpers.go index d05a04f3d9..87708a60e1 100644 --- a/internal/components/extensions/helpers.go +++ b/internal/components/extensions/helpers.go @@ -55,6 +55,9 @@ var ( return components.ParseSingleEndpointSilent(logger, name, defaultPort, &config.SingleEndpointConfig) }). MustBuild(), + components.NewSinglePortParserBuilder("jaeger_query", 16686). + WithTargetPort(16686). + MustBuild(), } ) diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index a7b8813f94..1782335ac5 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -108,6 +108,34 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { }, nil } +func ExtensionService(params manifests.Params) (*corev1.Service, error) { + name := naming.Service(params.OtelCol.Name) + labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + + annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) + if err != nil { + return nil, err + } + + ports, err := params.OtelCol.Spec.Config.GetExtensionPorts(params.Log) + if err != nil { + return nil, err + } + + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.OtelCol.Namespace, + Labels: labels, + Annotations: annotations, + }, + Spec: corev1.ServiceSpec{ + Ports: ports, + Selector: manifestutils.SelectorLabels(params.OtelCol.ObjectMeta, ComponentOpenTelemetryCollector), + }, + }, nil +} + func Service(params manifests.Params) (*corev1.Service, error) { name := naming.Service(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) From 8f92a9b9ba2b929e71064dd6507f4d4e63e4d655 Mon Sep 17 00:00:00 2001 From: Ankit152 Date: Tue, 29 Oct 2024 20:58:34 +0530 Subject: [PATCH 2/4] chore: added extension service in manifest factories Signed-off-by: Ankit152 --- internal/manifests/collector/collector.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/manifests/collector/collector.go b/internal/manifests/collector/collector.go index df294d4d47..0e4cc414d5 100644 --- a/internal/manifests/collector/collector.go +++ b/internal/manifests/collector/collector.go @@ -53,6 +53,7 @@ func Build(params manifests.Params) ([]client.Object, error) { manifests.Factory(Service), manifests.Factory(HeadlessService), manifests.Factory(MonitoringService), + manifests.Factory(ExtensionService), manifests.Factory(Ingress), }...) From 765562ddc34d52e411c9fb0888b8c09690d2fcdd Mon Sep 17 00:00:00 2001 From: Ankit152 Date: Fri, 1 Nov 2024 23:51:17 +0530 Subject: [PATCH 3/4] chore: added unit test for extension service function Signed-off-by: Ankit152 --- apis/v1beta1/config.go | 6 +- internal/manifests/collector/service.go | 10 +- internal/manifests/collector/service_test.go | 155 +++++++++++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) diff --git a/apis/v1beta1/config.go b/apis/v1beta1/config.go index f8fe348562..d38e6be70a 100644 --- a/apis/v1beta1/config.go +++ b/apis/v1beta1/config.go @@ -207,7 +207,11 @@ func (c *Config) getPortsForComponentKinds(logger logr.Logger, componentKinds .. continue case KindExtension: retriever = extensions.ParserFor - cfg = *c.Extensions + if c.Extensions == nil { + cfg = AnyConfig{} + } else { + cfg = *c.Extensions + } } for componentName := range enabledComponents[componentKind] { // TODO: Clean up the naming here and make it simpler to use a retriever. diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index 1782335ac5..19559d0c09 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -32,6 +32,7 @@ import ( const ( headlessLabel = "operator.opentelemetry.io/collector-headless-service" monitoringLabel = "operator.opentelemetry.io/collector-monitoring-service" + extensionService = "operator.opentelemetry.io/collector-extension-service" serviceTypeLabel = "operator.opentelemetry.io/collector-service-type" valueExists = "Exists" ) @@ -42,10 +43,11 @@ const ( BaseServiceType ServiceType = iota HeadlessServiceType MonitoringServiceType + ExtensionServiceType ) func (s ServiceType) String() string { - return [...]string{"base", "headless", "monitoring"}[s] + return [...]string{"base", "headless", "monitoring", "extension"}[s] } func HeadlessService(params manifests.Params) (*corev1.Service, error) { @@ -111,6 +113,8 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { func ExtensionService(params manifests.Params) (*corev1.Service, error) { name := naming.Service(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) + labels[extensionService] = valueExists + labels[serviceTypeLabel] = ExtensionServiceType.String() annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) if err != nil { @@ -122,6 +126,10 @@ func ExtensionService(params manifests.Params) (*corev1.Service, error) { return nil, err } + if len(ports) == 0 { + return nil, nil + } + return &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: name, diff --git a/internal/manifests/collector/service_test.go b/internal/manifests/collector/service_test.go index 11ac981585..d9483c5afb 100644 --- a/internal/manifests/collector/service_test.go +++ b/internal/manifests/collector/service_test.go @@ -321,6 +321,161 @@ func TestMonitoringService(t *testing.T) { }) } +func TestExtensionService(t *testing.T) { + t.Run("when the extension has http endpoint", func(t *testing.T) { + params := manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{ + "http": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, + }, + }, + }, + }, + }, + }, + } + + actual, err := ExtensionService(params) + assert.NotNil(t, actual) + assert.NoError(t, err) + }) + + t.Run("when the extension has grpc endpoint", func(t *testing.T) { + params := manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{ + "grpc": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, + }, + }, + }, + }, + }, + }, + } + + actual, err := ExtensionService(params) + assert.NotNil(t, actual) + assert.NoError(t, err) + }) + + t.Run("when the extension has both http and grpc endpoint", func(t *testing.T) { + params := manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{ + "http": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, + "grpc": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, + }, + }, + }, + }, + }, + }, + } + + actual, err := ExtensionService(params) + assert.NotNil(t, actual) + assert.NoError(t, err) + }) + + t.Run("when the extension has no extensions defined", func(t *testing.T) { + params := manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{}, + }, + }, + }, + }, + } + + actual, err := ExtensionService(params) + assert.Nil(t, actual) + assert.NoError(t, err) + }) + + t.Run("when the extension has no endpoint defined", func(t *testing.T) { + params := manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{}, + }, + }, + }, + }, + }, + } + + actual, err := ExtensionService(params) + assert.NotNil(t, actual) + assert.NoError(t, err) + }) +} + func service(name string, ports []v1beta1.PortsSpec) v1.Service { return serviceWithInternalTrafficPolicy(name, ports, v1.ServiceInternalTrafficPolicyCluster) } From c3ebb64e5fb7e6fb0baacce191a1107799b0721a Mon Sep 17 00:00:00 2001 From: Ankit152 Date: Sun, 10 Nov 2024 14:16:40 +0530 Subject: [PATCH 4/4] chore: added e2e tests for extensions Signed-off-by: Ankit152 --- .chloggen/service-extension.yaml | 16 ++ apis/v1beta1/config.go | 6 +- internal/manifests/collector/service.go | 6 +- internal/manifests/collector/service_test.go | 282 +++++++++++-------- internal/naming/main.go | 5 + tests/e2e/extension/00-assert.yaml | 140 +++++++++ tests/e2e/extension/00-install.yaml | 30 ++ tests/e2e/extension/chainsaw-test.yaml | 14 + 8 files changed, 376 insertions(+), 123 deletions(-) create mode 100755 .chloggen/service-extension.yaml create mode 100644 tests/e2e/extension/00-assert.yaml create mode 100644 tests/e2e/extension/00-install.yaml create mode 100644 tests/e2e/extension/chainsaw-test.yaml diff --git a/.chloggen/service-extension.yaml b/.chloggen/service-extension.yaml new file mode 100755 index 0000000000..d182754f46 --- /dev/null +++ b/.chloggen/service-extension.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action) +component: collector + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: support for creating a service for extensions when ports are specified. + +# One or more tracking issues related to the change +issues: [3460] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/apis/v1beta1/config.go b/apis/v1beta1/config.go index d38e6be70a..5cb9150513 100644 --- a/apis/v1beta1/config.go +++ b/apis/v1beta1/config.go @@ -327,10 +327,14 @@ func (c *Config) GetExtensionPorts(logger logr.Logger) ([]corev1.ServicePort, er return c.getPortsForComponentKinds(logger, KindExtension) } -func (c *Config) GetAllPorts(logger logr.Logger) ([]corev1.ServicePort, error) { +func (c *Config) GetReceiverAndExporterPorts(logger logr.Logger) ([]corev1.ServicePort, error) { return c.getPortsForComponentKinds(logger, KindReceiver, KindExporter) } +func (c *Config) GetAllPorts(logger logr.Logger) ([]corev1.ServicePort, error) { + return c.getPortsForComponentKinds(logger, KindReceiver, KindExporter, KindExtension) +} + func (c *Config) GetEnvironmentVariables(logger logr.Logger) ([]corev1.EnvVar, error) { return c.getEnvironmentVariablesForComponentKinds(logger, KindReceiver) } diff --git a/internal/manifests/collector/service.go b/internal/manifests/collector/service.go index 19559d0c09..7e27eb752c 100644 --- a/internal/manifests/collector/service.go +++ b/internal/manifests/collector/service.go @@ -32,7 +32,6 @@ import ( const ( headlessLabel = "operator.opentelemetry.io/collector-headless-service" monitoringLabel = "operator.opentelemetry.io/collector-monitoring-service" - extensionService = "operator.opentelemetry.io/collector-extension-service" serviceTypeLabel = "operator.opentelemetry.io/collector-service-type" valueExists = "Exists" ) @@ -111,9 +110,8 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) { } func ExtensionService(params manifests.Params) (*corev1.Service, error) { - name := naming.Service(params.OtelCol.Name) + name := naming.ExtensionService(params.OtelCol.Name) labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{}) - labels[extensionService] = valueExists labels[serviceTypeLabel] = ExtensionServiceType.String() annotations, err := manifestutils.Annotations(params.OtelCol, params.Config.AnnotationsFilter()) @@ -154,7 +152,7 @@ func Service(params manifests.Params) (*corev1.Service, error) { return nil, err } - ports, err := params.OtelCol.Spec.Config.GetAllPorts(params.Log) + ports, err := params.OtelCol.Spec.Config.GetReceiverAndExporterPorts(params.Log) if err != nil { return nil, err } diff --git a/internal/manifests/collector/service_test.go b/internal/manifests/collector/service_test.go index d9483c5afb..7a9695e594 100644 --- a/internal/manifests/collector/service_test.go +++ b/internal/manifests/collector/service_test.go @@ -26,6 +26,7 @@ import ( "github.com/open-telemetry/opentelemetry-operator/internal/config" "github.com/open-telemetry/opentelemetry-operator/internal/manifests" "github.com/open-telemetry/opentelemetry-operator/internal/manifests/manifestutils" + "github.com/open-telemetry/opentelemetry-operator/internal/naming" ) func TestExtractPortNumbersAndNames(t *testing.T) { @@ -322,24 +323,31 @@ func TestMonitoringService(t *testing.T) { } func TestExtensionService(t *testing.T) { - t.Run("when the extension has http endpoint", func(t *testing.T) { - params := manifests.Params{ - Config: config.Config{}, - Log: logger, - OtelCol: v1beta1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: v1beta1.OpenTelemetryCollectorSpec{ - Config: v1beta1.Config{ - Service: v1beta1.Service{ - Extensions: []string{"jaeger_query"}, - }, - Extensions: &v1beta1.AnyConfig{ - Object: map[string]interface{}{ - "jaeger_query": map[string]interface{}{ - "http": map[string]interface{}{ - "endpoint": "0.0.0.0:16686", + testCases := []struct { + name string + params manifests.Params + expectedPorts []v1.ServicePort + }{ + { + name: "when the extension has http endpoint", + params: manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{ + "http": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, }, }, }, @@ -347,31 +355,36 @@ func TestExtensionService(t *testing.T) { }, }, }, - } - - actual, err := ExtensionService(params) - assert.NotNil(t, actual) - assert.NoError(t, err) - }) - - t.Run("when the extension has grpc endpoint", func(t *testing.T) { - params := manifests.Params{ - Config: config.Config{}, - Log: logger, - OtelCol: v1beta1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", + expectedPorts: []v1.ServicePort{ + { + Name: "jaeger-query", + Port: 16686, + TargetPort: intstr.IntOrString{ + IntVal: 16686, + }, }, - Spec: v1beta1.OpenTelemetryCollectorSpec{ - Config: v1beta1.Config{ - Service: v1beta1.Service{ - Extensions: []string{"jaeger_query"}, - }, - Extensions: &v1beta1.AnyConfig{ - Object: map[string]interface{}{ - "jaeger_query": map[string]interface{}{ - "grpc": map[string]interface{}{ - "endpoint": "0.0.0.0:16686", + }, + }, + { + name: "when the extension has grpc endpoint", + params: manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{ + "http": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, }, }, }, @@ -379,34 +392,39 @@ func TestExtensionService(t *testing.T) { }, }, }, - } - - actual, err := ExtensionService(params) - assert.NotNil(t, actual) - assert.NoError(t, err) - }) - - t.Run("when the extension has both http and grpc endpoint", func(t *testing.T) { - params := manifests.Params{ - Config: config.Config{}, - Log: logger, - OtelCol: v1beta1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", + expectedPorts: []v1.ServicePort{ + { + Name: "jaeger-query", + Port: 16686, + TargetPort: intstr.IntOrString{ + IntVal: 16686, + }, }, - Spec: v1beta1.OpenTelemetryCollectorSpec{ - Config: v1beta1.Config{ - Service: v1beta1.Service{ - Extensions: []string{"jaeger_query"}, - }, - Extensions: &v1beta1.AnyConfig{ - Object: map[string]interface{}{ - "jaeger_query": map[string]interface{}{ - "http": map[string]interface{}{ - "endpoint": "0.0.0.0:16686", - }, - "grpc": map[string]interface{}{ - "endpoint": "0.0.0.0:16686", + }, + }, + { + name: "when the extension has both http and grpc endpoint", + params: manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{ + "http": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, + "grpc": map[string]interface{}{ + "endpoint": "0.0.0.0:16686", + }, }, }, }, @@ -414,66 +432,94 @@ func TestExtensionService(t *testing.T) { }, }, }, - } - - actual, err := ExtensionService(params) - assert.NotNil(t, actual) - assert.NoError(t, err) - }) - - t.Run("when the extension has no extensions defined", func(t *testing.T) { - params := manifests.Params{ - Config: config.Config{}, - Log: logger, - OtelCol: v1beta1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", + expectedPorts: []v1.ServicePort{ + { + Name: "jaeger-query", + Port: 16686, + TargetPort: intstr.IntOrString{ + IntVal: 16686, + }, }, - Spec: v1beta1.OpenTelemetryCollectorSpec{ - Config: v1beta1.Config{ - Service: v1beta1.Service{ - Extensions: []string{"jaeger_query"}, - }, - Extensions: &v1beta1.AnyConfig{ - Object: map[string]interface{}{}, + }, + }, + { + name: "when the extension has no extensions defined", + params: manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{}, + }, }, }, }, }, - } - - actual, err := ExtensionService(params) - assert.Nil(t, actual) - assert.NoError(t, err) - }) - - t.Run("when the extension has no endpoint defined", func(t *testing.T) { - params := manifests.Params{ - Config: config.Config{}, - Log: logger, - OtelCol: v1beta1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: v1beta1.OpenTelemetryCollectorSpec{ - Config: v1beta1.Config{ - Service: v1beta1.Service{ - Extensions: []string{"jaeger_query"}, - }, - Extensions: &v1beta1.AnyConfig{ - Object: map[string]interface{}{ - "jaeger_query": map[string]interface{}{}, + expectedPorts: []v1.ServicePort{}, + }, + { + name: "when the extension has no endpoint defined", + params: manifests.Params{ + Config: config.Config{}, + Log: logger, + OtelCol: v1beta1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: v1beta1.OpenTelemetryCollectorSpec{ + Config: v1beta1.Config{ + Service: v1beta1.Service{ + Extensions: []string{"jaeger_query"}, + }, + Extensions: &v1beta1.AnyConfig{ + Object: map[string]interface{}{ + "jaeger_query": map[string]interface{}{}, + }, }, }, }, }, }, - } + expectedPorts: []v1.ServicePort{ + { + Name: "jaeger-query", + Port: 16686, + TargetPort: intstr.IntOrString{ + IntVal: 16686, + }, + }, + }, + }, + } - actual, err := ExtensionService(params) - assert.NotNil(t, actual) - assert.NoError(t, err) - }) + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + actual, err := ExtensionService(tc.params) + assert.NoError(t, err) + + if len(tc.expectedPorts) > 0 { + assert.NotNil(t, actual) + assert.Equal(t, actual.Name, naming.ExtensionService(tc.params.OtelCol.Name)) + // ports assertion + assert.Equal(t, len(tc.expectedPorts), len(actual.Spec.Ports)) + assert.Equal(t, tc.expectedPorts[0].Name, actual.Spec.Ports[0].Name) + assert.Equal(t, tc.expectedPorts[0].Port, actual.Spec.Ports[0].Port) + assert.Equal(t, tc.expectedPorts[0].TargetPort.IntVal, actual.Spec.Ports[0].TargetPort.IntVal) + } else { + // no ports, no service + assert.Nil(t, actual) + } + }) + } } func service(name string, ports []v1beta1.PortsSpec) v1.Service { diff --git a/internal/naming/main.go b/internal/naming/main.go index 8642f618c3..149a9f9d5a 100644 --- a/internal/naming/main.go +++ b/internal/naming/main.go @@ -116,6 +116,11 @@ func MonitoringService(otelcol string) string { return DNSName(Truncate("%s-monitoring", 63, Service(otelcol))) } +// ExtensionService builds the name for the extension service based on the instance. +func ExtensionService(otelcol string) string { + return DNSName(Truncate("%s-extension", 63, Service(otelcol))) +} + // Service builds the service name based on the instance. func Service(otelcol string) string { return DNSName(Truncate("%s-collector", 63, otelcol)) diff --git a/tests/e2e/extension/00-assert.yaml b/tests/e2e/extension/00-assert.yaml new file mode 100644 index 0000000000..c62406a1f3 --- /dev/null +++ b/tests/e2e/extension/00-assert.yaml @@ -0,0 +1,140 @@ +apiVersion: v1 +items: +- apiVersion: apps/v1 + kind: Deployment + metadata: + name: jaeger-inmemory-collector + spec: + template: + spec: + containers: + - ports: + - containerPort: 16686 + name: jaeger-query + protocol: TCP + - containerPort: 8888 + name: metrics + protocol: TCP + - containerPort: 4317 + name: otlp-grpc + protocol: TCP + - containerPort: 4318 + name: otlp-http + protocol: TCP +kind: List +metadata: + resourceVersion: "" +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger-inmemory-collector +spec: + ports: + - appProtocol: grpc + name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: 4317 + - appProtocol: http + name: otlp-http + port: 4318 + protocol: TCP + targetPort: 4318 +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + service.beta.openshift.io/serving-cert-secret-name: jaeger-inmemory-collector-headless-tls + labels: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/name: jaeger-inmemory-collector + app.kubernetes.io/part-of: opentelemetry + app.kubernetes.io/version: latest + operator.opentelemetry.io/collector-headless-service: Exists + operator.opentelemetry.io/collector-service-type: headless + name: jaeger-inmemory-collector-headless + ownerReferences: + - apiVersion: opentelemetry.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: OpenTelemetryCollector + name: jaeger-inmemory +spec: + clusterIP: None + clusterIPs: + - None + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - appProtocol: grpc + name: otlp-grpc + port: 4317 + protocol: TCP + targetPort: 4317 + - appProtocol: http + name: otlp-http + port: 4318 + protocol: TCP + targetPort: 4318 + selector: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/part-of: opentelemetry + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/name: jaeger-inmemory-collector-monitoring + app.kubernetes.io/part-of: opentelemetry + app.kubernetes.io/version: latest + operator.opentelemetry.io/collector-monitoring-service: Exists + operator.opentelemetry.io/collector-service-type: monitoring + name: jaeger-inmemory-collector-monitoring +spec: + ports: + - name: monitoring + port: 8888 + protocol: TCP + targetPort: 8888 + selector: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/part-of: opentelemetry + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger-inmemory-collector-extension + labels: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/part-of: opentelemetry + app.kubernetes.io/version: latest + operator.opentelemetry.io/collector-service-type: extension +spec: + selector: + app.kubernetes.io/component: opentelemetry-collector + app.kubernetes.io/managed-by: opentelemetry-operator + app.kubernetes.io/part-of: opentelemetry + ports: + - name: jaeger-query + port: 16686 + targetPort: 16686 +status: + loadBalancer: {} diff --git a/tests/e2e/extension/00-install.yaml b/tests/e2e/extension/00-install.yaml new file mode 100644 index 0000000000..43e27fa9b2 --- /dev/null +++ b/tests/e2e/extension/00-install.yaml @@ -0,0 +1,30 @@ +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: jaeger-inmemory +spec: + image: jaegertracing/jaeger:latest + config: + service: + extensions: [jaeger_storage, jaeger_query] + pipelines: + traces: + receivers: [otlp] + exporters: [jaeger_storage_exporter] + extensions: + jaeger_query: + storage: + traces: memstore + jaeger_storage: + backends: + memstore: + memory: + max_traces: 100000 + receivers: + otlp: + protocols: + grpc: + http: + exporters: + jaeger_storage_exporter: + trace_storage: memstore diff --git a/tests/e2e/extension/chainsaw-test.yaml b/tests/e2e/extension/chainsaw-test.yaml new file mode 100644 index 0000000000..488a76359b --- /dev/null +++ b/tests/e2e/extension/chainsaw-test.yaml @@ -0,0 +1,14 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + creationTimestamp: null + name: extension-test +spec: + steps: + - name: step-00 + try: + - apply: + file: 00-install.yaml + - assert: + file: 00-assert.yaml