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) }