diff --git a/apis/otel/v1alpha1/defaults.go b/apis/otel/v1alpha1/defaults.go index edb0f9b0..b0627d2d 100644 --- a/apis/otel/v1alpha1/defaults.go +++ b/apis/otel/v1alpha1/defaults.go @@ -397,7 +397,181 @@ service: defaultGatewayCPU = "4" defaultGatewayMemory = "8Gi" - + defaultGatewayConfig = ` + exporters: + sapm: + access_token: ${SPLUNK_ACCESS_TOKEN} + endpoint: https://ingest.${SPLUNK_REALM}.signalfx.com/v2/trace + signalfx: + access_token: ${SPLUNK_ACCESS_TOKEN} + api_url: https://api.${SPLUNK_REALM}.signalfx.com + ingest_url: https://ingest.${SPLUNK_REALM}.signalfx.com + extensions: + health_check: null + http_forwarder: + egress: + endpoint: https://api.${SPLUNK_REALM}.signalfx.com + memory_ballast: + size_mib: ${SPLUNK_BALLAST_SIZE_MIB} + zpages: null + processors: + batch: null + filter/logs: + logs: + exclude: + match_type: strict + resource_attributes: + - key: splunk.com/exclude + value: "true" + k8sattributes: + extract: + annotations: + - from: pod + key: splunk.com/sourcetype + - from: namespace + key: splunk.com/exclude + tag_name: splunk.com/exclude + - from: pod + key: splunk.com/exclude + tag_name: splunk.com/exclude + - from: namespace + key: splunk.com/index + tag_name: com.splunk.index + - from: pod + key: splunk.com/index + tag_name: com.splunk.index + labels: + - key: app + metadata: + - k8s.namespace.name + - k8s.node.name + - k8s.pod.name + - k8s.pod.uid + pod_association: + - from: resource_attribute + name: k8s.pod.uid + - from: resource_attribute + name: k8s.pod.ip + - from: resource_attribute + name: ip + - from: connection + - from: resource_attribute + name: host.name + memory_limiter: + check_interval: 2s + limit_mib: ${SPLUNK_MEMORY_LIMIT_MIB} + resource/add_cluster_name: + attributes: + - action: upsert + key: k8s.cluster.name + value: ${MY_CLUSTER_NAME} + resource/add_collector_k8s: + attributes: + - action: insert + key: k8s.node.name + value: ${K8S_NODE_NAME} + - action: insert + key: k8s.pod.name + value: ${K8S_POD_NAME} + - action: insert + key: k8s.pod.uid + value: ${K8S_POD_UID} + - action: insert + key: k8s.namespace.name + value: ${K8S_NAMESPACE} + resource/logs: + attributes: + - action: upsert + from_attribute: k8s.pod.annotations.splunk.com/sourcetype + key: com.splunk.sourcetype + - action: delete + key: k8s.pod.annotations.splunk.com/sourcetype + - action: delete + key: splunk.com/exclude + resourcedetection: + detectors: + - env + - system + override: true + timeout: 10s + receivers: + jaeger: + protocols: + grpc: + endpoint: 0.0.0.0:14250 + thrift_http: + endpoint: 0.0.0.0:14268 + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + prometheus/collector: + config: + scrape_configs: + - job_name: otel-collector + scrape_interval: 10s + static_configs: + - targets: + - ${K8S_POD_IP}:8889 + signalfx: + access_token_passthrough: true + endpoint: 0.0.0.0:9943 + zipkin: + endpoint: 0.0.0.0:9411 + service: + extensions: + - health_check + - memory_ballast + - zpages + - http_forwarder + pipelines: + logs/signalfx-events: + exporters: + - signalfx + processors: + - memory_limiter + - batch + receivers: + - signalfx + metrics: + exporters: + - signalfx + processors: + - memory_limiter + - batch + - resource/add_cluster_name + receivers: + - otlp + - signalfx + metrics/collector: + exporters: + - signalfx + processors: + - memory_limiter + - batch + - resource/add_collector_k8s + - resourcedetection + - resource/add_cluster_name + receivers: + - prometheus/collector + traces: + exporters: + - sapm + processors: + - memory_limiter + - batch + - k8sattributes + - resource/add_cluster_name + receivers: + - otlp + - jaeger + - zipkin + telemetry: + metrics: + address: 0.0.0.0:8889 +` // the javaagent version is managed by the update-javaagent-version.sh script. defaultJavaAgentVersion = "v1.14.1" defaultJavaAgentImage = "quay.io/signalfx/splunk-otel-instrumentation-java:" + defaultJavaAgentVersion diff --git a/apis/otel/v1alpha1/splunkotelagent_types.go b/apis/otel/v1alpha1/splunkotelagent_types.go index 6e74b6de..43ba2d9c 100644 --- a/apis/otel/v1alpha1/splunkotelagent_types.go +++ b/apis/otel/v1alpha1/splunkotelagent_types.go @@ -156,7 +156,7 @@ type AgentSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec ClusterReceiver CollectorSpec `json:"clusterReceiver,omitempty"` - // ClusterReceiver is a Splunk OpenTelemetry Collector deployment used to export data to Splunk APM. + // Gatway is a Splunk OpenTelemetry Collector deployment used to export data to Splunk APM. // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec Gateway CollectorSpec `json:"gateway,omitempty"` diff --git a/apis/otel/v1alpha1/splunkotelagent_webhook.go b/apis/otel/v1alpha1/splunkotelagent_webhook.go index 0918d3d4..fead22c3 100644 --- a/apis/otel/v1alpha1/splunkotelagent_webhook.go +++ b/apis/otel/v1alpha1/splunkotelagent_webhook.go @@ -119,7 +119,7 @@ func (r *Agent) validateCRDAgentSpec() error { spec := r.Spec.Agent if spec.Replicas != nil { - return fmt.Errorf("`replicas` is not supported by clusterReceiver") + return fmt.Errorf("`replicas` is not supported by the agent") } return nil @@ -129,11 +129,11 @@ func (r *Agent) validateCRDClusterReceiverSpec() error { spec := r.Spec.ClusterReceiver if spec.Replicas != nil { - return fmt.Errorf("`replicas` is not supported by clusterReceiver") + return fmt.Errorf("`replicas` is not supported by the clusterReceiver") } if spec.HostNetwork { - return fmt.Errorf("`hostNetwork` cannot be true for clusterReceiver") + return fmt.Errorf("`hostNetwork` cannot be true for the clusterReceiver") } return nil @@ -142,10 +142,6 @@ func (r *Agent) validateCRDClusterReceiverSpec() error { func (r *Agent) validateCRDGatewaySpec() error { spec := r.Spec.Gateway - if r.Spec.Gateway.Enabled != nil && *r.Spec.Gateway.Enabled { - return fmt.Errorf("gateway is not supported at the moment") - } - if spec.HostNetwork { return fmt.Errorf("`hostNetwork` cannot be true for clusterReceiver") } @@ -249,8 +245,6 @@ func (r *Agent) defaultClusterReceiver() { func (r *Agent) defaultGateway() { spec := &r.Spec.Gateway - // TODO(splunk): forcibly disable gateway until we add support for it. - spec.Enabled = &[]bool{false}[0] spec.HostNetwork = false // The gateway is not enabled by default @@ -259,8 +253,115 @@ func (r *Agent) defaultGateway() { spec.Enabled = &s } + if spec.Replicas == nil { + s := int32(3) + spec.Replicas = &s + } + + if spec.Ports == nil { + spec.Ports = []v1.ServicePort{ + { + Name: "otlp", + Protocol: "TCP", + Port: 4317, + }, + { + Name: "otlp-http", + Protocol: "TCP", + Port: 4318, + }, + { + Protocol: "TCP", + Port: 55681, + }, + { + Name: "jaeger-thrift", + Protocol: "TCP", + Port: 14268, + }, + { + Name: "jaeger-grpc", + Protocol: "TCP", + Port: 14250, + }, + { + Name: "zipkin", + Protocol: "TCP", + Port: 9411, + }, + { + Name: "signalfx", + Protocol: "TCP", + Port: 9943, + }, + { + Name: "http-forwarder", + Protocol: "TCP", + Port: 6060, + }, + } + } + + if spec.Enabled == nil { + s := false + spec.Enabled = &s + } + + if spec.Replicas == nil { + s := int32(3) + spec.Replicas = &s + } + + if spec.Ports == nil { + spec.Ports = []v1.ServicePort{ + { + Name: "otlp", + Protocol: "TCP", + Port: 4317, + }, + { + Name: "otlp-http", + Protocol: "TCP", + Port: 4318, + }, + { + Protocol: "TCP", + Port: 55681, + }, + { + Name: "jaeger-thrift", + Protocol: "TCP", + Port: 14268, + }, + { + Name: "jaeger-grpc", + Protocol: "TCP", + Port: 14250, + }, + { + Name: "zipkin", + Protocol: "TCP", + Port: 9411, + }, + { + Name: "signalfx", + Protocol: "TCP", + Port: 9943, + }, + { + Name: "http-forwarder", + Protocol: "TCP", + Port: 6060, + }, + } + } + setDefaultResources(spec, defaultGatewayCPU, defaultGatewayMemory) setDefaultEnvVars(spec, r.Spec.Realm, r.Spec.ClusterName) + + if spec.Config == "" { + spec.Config = defaultGatewayConfig + } } func setDefaultResources(spec *CollectorSpec, defaultCPU string, diff --git a/bundle/manifests/otel.splunk.com_agents.yaml b/bundle/manifests/otel.splunk.com_agents.yaml index 21ae3381..ffa318ee 100644 --- a/bundle/manifests/otel.splunk.com_agents.yaml +++ b/bundle/manifests/otel.splunk.com_agents.yaml @@ -4222,7 +4222,7 @@ spec: x-kubernetes-list-type: atomic type: object gateway: - description: ClusterReceiver is a Splunk OpenTelemetry Collector deployment + description: Gatway is a Splunk OpenTelemetry Collector deployment used to export data to Splunk APM. properties: args: diff --git a/bundle/manifests/splunk-otel-collector-operator.clusterserviceversion.yaml b/bundle/manifests/splunk-otel-collector-operator.clusterserviceversion.yaml index ee708af5..664960ff 100644 --- a/bundle/manifests/splunk-otel-collector-operator.clusterserviceversion.yaml +++ b/bundle/manifests/splunk-otel-collector-operator.clusterserviceversion.yaml @@ -167,8 +167,8 @@ spec: deployment(s). displayName: Volumes path: clusterReceiver.volumes - - description: ClusterReceiver is a Splunk OpenTelemetry Collector deployment - used to export data to Splunk APM. + - description: Gatway is a Splunk OpenTelemetry Collector deployment used to + export data to Splunk APM. displayName: Gateway path: gateway - description: Args is the set of arguments to pass to the OpenTelemetry Collector diff --git a/config/crd/bases/otel.splunk.com_agents.yaml b/config/crd/bases/otel.splunk.com_agents.yaml index 94ed533a..a0deb7be 100644 --- a/config/crd/bases/otel.splunk.com_agents.yaml +++ b/config/crd/bases/otel.splunk.com_agents.yaml @@ -4212,7 +4212,7 @@ spec: x-kubernetes-list-type: atomic type: object gateway: - description: ClusterReceiver is a Splunk OpenTelemetry Collector deployment + description: Gatway is a Splunk OpenTelemetry Collector deployment used to export data to Splunk APM. properties: args: diff --git a/config/manifests/bases/splunk-otel-collector-operator.clusterserviceversion.yaml b/config/manifests/bases/splunk-otel-collector-operator.clusterserviceversion.yaml index c838a2b3..cc220809 100644 --- a/config/manifests/bases/splunk-otel-collector-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/splunk-otel-collector-operator.clusterserviceversion.yaml @@ -155,8 +155,8 @@ spec: deployment(s). displayName: Volumes path: clusterReceiver.volumes - - description: ClusterReceiver is a Splunk OpenTelemetry Collector deployment - used to export data to Splunk APM. + - description: Gatway is a Splunk OpenTelemetry Collector deployment used to + export data to Splunk APM. displayName: Gateway path: gateway - description: Args is the set of arguments to pass to the OpenTelemetry Collector diff --git a/controllers/otel/agent_controller.go b/controllers/otel/agent_controller.go index 50e867fc..c4932b93 100644 --- a/controllers/otel/agent_controller.go +++ b/controllers/otel/agent_controller.go @@ -85,13 +85,11 @@ func NewReconciler(logger logr.Logger, client client.Client, scheme *runtime.Sch reconcile.Agents, true, }, - /* - { - "gateway", - reconcile.Gateway, - true, - }, - */ + { + "gateway", + reconcile.Gateways, + true, + }, { "splunk opentelemetry", reconcile.Self, diff --git a/controllers/otel/agent_controller_test.go b/controllers/otel/agent_controller_test.go index 31eaca12..873bc640 100644 --- a/controllers/otel/agent_controller_test.go +++ b/controllers/otel/agent_controller_test.go @@ -47,7 +47,11 @@ func TestNewObjectsOnReconciliation(t *testing.T) { Name: nsn.Name, Namespace: nsn.Namespace, }, - Spec: v1alpha1.AgentSpec{}, + Spec: v1alpha1.AgentSpec{ + Gateway: v1alpha1.CollectorSpec{ + Enabled: &[]bool{true}[0], + }, + }, } err := k8sClient.Create(context.Background(), created) require.NoError(t, err) @@ -84,13 +88,12 @@ func TestNewObjectsOnReconciliation(t *testing.T) { assert.NoError(t, err) assert.NotEmpty(t, list.Items) } - // TODO(splunk): forcibly disable this test until we add gateway support - //{ - // list := &corev1.ServiceList{} - // err = k8sClient.List(context.Background(), list, opts...) - // assert.NoError(t, err) - // assert.NotEmpty(t, list.Items) - //} + { + list := &corev1.ServiceList{} + err = k8sClient.List(context.Background(), list, opts...) + assert.NoError(t, err) + assert.NotEmpty(t, list.Items) + } { list := &appsv1.DeploymentList{} err = k8sClient.List(context.Background(), list, opts...) diff --git a/internal/collector/agent.go b/internal/collector/agent.go index c98584e6..9d25bbb0 100644 --- a/internal/collector/agent.go +++ b/internal/collector/agent.go @@ -25,7 +25,7 @@ import ( "github.com/signalfx/splunk-otel-collector-operator/internal/naming" ) -// Agent builds the deployment for the given instance. +// Agent builds the Splunk Otel Collector Agent daemonset for the given instance. func Agent(logger logr.Logger, otelcol v1alpha1.Agent) appsv1.DaemonSet { labels := Labels(otelcol) labels["app.kubernetes.io/name"] = naming.Agent(otelcol) diff --git a/internal/collector/clusterreceiver.go b/internal/collector/clusterreceiver.go index 8e1798cc..d107e1cf 100644 --- a/internal/collector/clusterreceiver.go +++ b/internal/collector/clusterreceiver.go @@ -25,7 +25,7 @@ import ( "github.com/signalfx/splunk-otel-collector-operator/internal/naming" ) -// ClusterReceiver builds the Splunk Cluster Receiver instance (deployment) for the given instance. +// ClusterReceiver builds the Splunk Otel Collector ClusterReceiver deployment for the given instance. func ClusterReceiver(logger logr.Logger, otelcol v1alpha1.Agent) appsv1.Deployment { labels := Labels(otelcol) labels["app.kubernetes.io/name"] = naming.ClusterReceiver(otelcol) diff --git a/internal/collector/gateway.go b/internal/collector/gateway.go new file mode 100644 index 00000000..c5e9d88d --- /dev/null +++ b/internal/collector/gateway.go @@ -0,0 +1,61 @@ +// Copyright The OpenTelemetry Authors +// Copyright Splunk Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package collector + +import ( + "github.com/go-logr/logr" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/signalfx/splunk-otel-collector-operator/apis/otel/v1alpha1" + "github.com/signalfx/splunk-otel-collector-operator/internal/naming" +) + +// Gateway builds the Splunk Otel Collector Gateway deployment for the given instance. +func Gateway(logger logr.Logger, otelcol v1alpha1.Agent) appsv1.Deployment { + labels := Labels(otelcol) + labels["app.kubernetes.io/name"] = naming.Gateway(otelcol) + + annotations := Annotations(otelcol) + + return appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: naming.Gateway(otelcol), + Namespace: otelcol.Namespace, + Labels: labels, + Annotations: annotations, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: otelcol.Spec.Gateway.Replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + Annotations: otelcol.Annotations, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: ServiceAccountName(otelcol), + Containers: []corev1.Container{Container(logger, otelcol.Spec.Gateway)}, + Volumes: Volumes(otelcol.Spec.Gateway, naming.ConfigMap(otelcol, "gateway")), + Tolerations: otelcol.Spec.Gateway.Tolerations, + }, + }, + }, + } +} diff --git a/internal/collector/reconcile/agent.go b/internal/collector/reconcile/agent.go index 10f87d35..9fbec208 100644 --- a/internal/collector/reconcile/agent.go +++ b/internal/collector/reconcile/agent.go @@ -26,6 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "github.com/signalfx/splunk-otel-collector-operator/internal/collector" + "github.com/signalfx/splunk-otel-collector-operator/internal/naming" ) // +kubebuilder:rbac:groups="apps",resources=daemonsets,verbs=get;list;watch;create;update;patch;delete @@ -119,6 +120,7 @@ func deleteAgents(ctx context.Context, params Params, expected []appsv1.DaemonSe client.MatchingLabels(map[string]string{ "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), "app.kubernetes.io/managed-by": "splunk-otel-collector-operator", + "app.kubernetes.io/name": naming.Agent(params.Instance), }), } list := &appsv1.DaemonSetList{} diff --git a/internal/collector/reconcile/agent_test.go b/internal/collector/reconcile/agent_test.go index be0e4b60..d48456fa 100644 --- a/internal/collector/reconcile/agent_test.go +++ b/internal/collector/reconcile/agent_test.go @@ -60,6 +60,7 @@ func TestExpectedDaemonsets(t *testing.T) { labels := map[string]string{ "app.kubernetes.io/instance": "default.test", "app.kubernetes.io/managed-by": "splunk-otel-collector-operator", + "app.kubernetes.io/name": "test-agent", } ds := v1.DaemonSet{} ds.Name = "dummy" diff --git a/internal/collector/reconcile/gateway.go b/internal/collector/reconcile/gateway.go new file mode 100644 index 00000000..bf4cba80 --- /dev/null +++ b/internal/collector/reconcile/gateway.go @@ -0,0 +1,139 @@ +// Copyright The OpenTelemetry Authors +// Copyright Splunk Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package reconcile + +import ( + "context" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/signalfx/splunk-otel-collector-operator/internal/collector" + "github.com/signalfx/splunk-otel-collector-operator/internal/naming" +) + +// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;list;watch;create;update;patch;delete + +// Gateway reconciles the Splunk Otel Gateway required for the instance in the current context. +func Gateways(ctx context.Context, params Params) error { + desired := []appsv1.Deployment{} + if params.Instance.Spec.Gateway.Enabled != nil && *params.Instance.Spec.Gateway.Enabled { + // TODO(splunk): pass params.Instance.Spec.Gateway instead of params.Instance + desired = append(desired, collector.Gateway(params.Log, params.Instance)) + } + + // first, handle the create/update parts + if err := expectedGateways(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the expected deployments: %w", err) + } + + // then, delete the extra objects + if err := deleteGateways(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the deployments to be deleted: %w", err) + } + + return nil +} + +func expectedGateways(ctx context.Context, params Params, expected []appsv1.Deployment) error { + for _, obj := range expected { + desired := obj + + if err := controllerutil.SetControllerReference(¶ms.Instance, &desired, params.Scheme); err != nil { + return fmt.Errorf("failed to set controller reference: %w", err) + } + + existing := &appsv1.Deployment{} + nns := types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name} + err := params.Client.Get(ctx, nns, existing) + if err != nil && k8serrors.IsNotFound(err) { + if err = params.Client.Create(ctx, &desired); err != nil { + return fmt.Errorf("failed to create: %w", err) + } + params.Log.V(2).Info("created", "deployment.name", desired.Name, "deployment.namespace", desired.Namespace) + continue + } else if err != nil { + return fmt.Errorf("failed to get: %w", err) + } + + // it exists already, merge the two if the end result isn't identical to the existing one + updated := existing.DeepCopy() + if updated.Annotations == nil { + updated.Annotations = map[string]string{} + } + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + updated.Spec = desired.Spec + updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences + + for k, v := range desired.ObjectMeta.Annotations { + updated.ObjectMeta.Annotations[k] = v + } + for k, v := range desired.ObjectMeta.Labels { + updated.ObjectMeta.Labels[k] = v + } + + patch := client.MergeFrom(existing) + + if err := params.Client.Patch(ctx, updated, patch); err != nil { + return fmt.Errorf("failed to apply changes: %w", err) + } + + params.Log.V(2).Info("applied", "deployment.name", desired.Name, "deployment.namespace", desired.Namespace) + } + + return nil +} + +func deleteGateways(ctx context.Context, params Params, expected []appsv1.Deployment) error { + opts := []client.ListOption{ + client.InNamespace(params.Instance.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), + "app.kubernetes.io/managed-by": "splunk-otel-collector-operator", + "app.kubernetes.io/name": naming.Gateway(params.Instance), + }), + } + list := &appsv1.DeploymentList{} + if err := params.Client.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for i := range list.Items { + existing := list.Items[i] + del := true + for _, keep := range expected { + if keep.Name == existing.Name && keep.Namespace == existing.Namespace { + del = false + } + } + + if del { + if err := params.Client.Delete(ctx, &existing); err != nil { + return fmt.Errorf("failed to delete: %w", err) + } + params.Log.V(2).Info("deleted", "deployment.name", existing.Name, "deployment.namespace", existing.Namespace) + } + } + + return nil +} diff --git a/internal/collector/reconcile/service.go b/internal/collector/reconcile/service.go index c4649f89..b7e85f44 100644 --- a/internal/collector/reconcile/service.go +++ b/internal/collector/reconcile/service.go @@ -38,7 +38,7 @@ import ( func Services(ctx context.Context, params Params) error { desired := []corev1.Service{} - if params.Instance.Spec.Gateway.Enabled != nil && !*params.Instance.Spec.Gateway.Enabled { + if params.Instance.Spec.Gateway.Enabled != nil && *params.Instance.Spec.Gateway.Enabled { type builder func(context.Context, Params) *corev1.Service for _, builder := range []builder{desiredService, headless, monitoringService} { // TODO(splunk): pass in params.Instance.Spec.Gateway instead of params diff --git a/tests/e2e/config-injection/01-install.yaml b/tests/e2e/config-injection/01-install.yaml index af018901..ee3f1950 100644 --- a/tests/e2e/config-injection/01-install.yaml +++ b/tests/e2e/config-injection/01-install.yaml @@ -4,4 +4,10 @@ metadata: name: test-conf-injection spec: clusterName: test-cluster - realm: my-splunk-realm \ No newline at end of file + realm: my-splunk-realm + agent: + enabled: true + clusterReceiver: + enabled: false + gateway: + enabled: false \ No newline at end of file diff --git a/tests/e2e/gateway/00-install.yaml b/tests/e2e/gateway/00-install.yaml new file mode 100644 index 00000000..7670ed1f --- /dev/null +++ b/tests/e2e/gateway/00-install.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Secret +metadata: + name: splunk-access-token +type: Opaque +stringData: + access-token: 0123456789--1234567-12 \ No newline at end of file diff --git a/tests/e2e/gateway/01-assert.yaml b/tests/e2e/gateway/01-assert.yaml new file mode 100644 index 00000000..55b67fcd --- /dev/null +++ b/tests/e2e/gateway/01-assert.yaml @@ -0,0 +1,319 @@ +apiVersion: otel.splunk.com/v1alpha1 +kind: Agent +metadata: + labels: + app.kubernetes.io/managed-by: splunk-otel-collector-operator +spec: + clusterName: test-cluster-gateway-only + realm: my-splunk-realm +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test-gateway-only-gateway + labels: + app.kubernetes.io/managed-by: splunk-otel-collector-operator +data: + collector.yaml: |2 + + exporters: + sapm: + access_token: ${SPLUNK_ACCESS_TOKEN} + endpoint: https://ingest.${SPLUNK_REALM}.signalfx.com/v2/trace + signalfx: + access_token: ${SPLUNK_ACCESS_TOKEN} + api_url: https://api.${SPLUNK_REALM}.signalfx.com + ingest_url: https://ingest.${SPLUNK_REALM}.signalfx.com + extensions: + health_check: null + http_forwarder: + egress: + endpoint: https://api.${SPLUNK_REALM}.signalfx.com + memory_ballast: + size_mib: ${SPLUNK_BALLAST_SIZE_MIB} + zpages: null + processors: + batch: null + filter/logs: + logs: + exclude: + match_type: strict + resource_attributes: + - key: splunk.com/exclude + value: "true" + k8sattributes: + extract: + annotations: + - from: pod + key: splunk.com/sourcetype + - from: namespace + key: splunk.com/exclude + tag_name: splunk.com/exclude + - from: pod + key: splunk.com/exclude + tag_name: splunk.com/exclude + - from: namespace + key: splunk.com/index + tag_name: com.splunk.index + - from: pod + key: splunk.com/index + tag_name: com.splunk.index + labels: + - key: app + metadata: + - k8s.namespace.name + - k8s.node.name + - k8s.pod.name + - k8s.pod.uid + pod_association: + - from: resource_attribute + name: k8s.pod.uid + - from: resource_attribute + name: k8s.pod.ip + - from: resource_attribute + name: ip + - from: connection + - from: resource_attribute + name: host.name + memory_limiter: + check_interval: 2s + limit_mib: ${SPLUNK_MEMORY_LIMIT_MIB} + resource/add_cluster_name: + attributes: + - action: upsert + key: k8s.cluster.name + value: ${MY_CLUSTER_NAME} + resource/add_collector_k8s: + attributes: + - action: insert + key: k8s.node.name + value: ${K8S_NODE_NAME} + - action: insert + key: k8s.pod.name + value: ${K8S_POD_NAME} + - action: insert + key: k8s.pod.uid + value: ${K8S_POD_UID} + - action: insert + key: k8s.namespace.name + value: ${K8S_NAMESPACE} + resource/logs: + attributes: + - action: upsert + from_attribute: k8s.pod.annotations.splunk.com/sourcetype + key: com.splunk.sourcetype + - action: delete + key: k8s.pod.annotations.splunk.com/sourcetype + - action: delete + key: splunk.com/exclude + resourcedetection: + detectors: + - env + - system + override: true + timeout: 10s + receivers: + jaeger: + protocols: + grpc: + endpoint: 0.0.0.0:14250 + thrift_http: + endpoint: 0.0.0.0:14268 + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + prometheus/collector: + config: + scrape_configs: + - job_name: otel-collector + scrape_interval: 10s + static_configs: + - targets: + - ${K8S_POD_IP}:8889 + signalfx: + access_token_passthrough: true + endpoint: 0.0.0.0:9943 + zipkin: + endpoint: 0.0.0.0:9411 + service: + extensions: + - health_check + - memory_ballast + - zpages + - http_forwarder + pipelines: + logs/signalfx-events: + exporters: + - signalfx + processors: + - memory_limiter + - batch + receivers: + - signalfx + metrics: + exporters: + - signalfx + processors: + - memory_limiter + - batch + - resource/add_cluster_name + receivers: + - otlp + - signalfx + metrics/collector: + exporters: + - signalfx + processors: + - memory_limiter + - batch + - resource/add_collector_k8s + - resourcedetection + - resource/add_cluster_name + receivers: + - prometheus/collector + traces: + exporters: + - sapm + processors: + - memory_limiter + - batch + - k8sattributes + - resource/add_cluster_name + receivers: + - otlp + - jaeger + - zipkin + telemetry: + metrics: + address: 0.0.0.0:8889 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + prometheus.io/path: /metrics + prometheus.io/port: "8888" + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/component: splunk-otel-collector + app.kubernetes.io/managed-by: splunk-otel-collector-operator + app.kubernetes.io/name: test-gateway-only-gateway + app.kubernetes.io/part-of: opentelemetry + name: test-gateway-only-gateway +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app.kubernetes.io/component: splunk-otel-collector + app.kubernetes.io/managed-by: splunk-otel-collector-operator + app.kubernetes.io/name: test-gateway-only-gateway + app.kubernetes.io/part-of: opentelemetry + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app.kubernetes.io/component: splunk-otel-collector + app.kubernetes.io/managed-by: splunk-otel-collector-operator + app.kubernetes.io/name: test-gateway-only-gateway + app.kubernetes.io/part-of: opentelemetry + spec: + containers: + - args: + - --config=/conf/collector.yaml + env: + - name: SPLUNK_ACCESS_TOKEN + valueFrom: + secretKeyRef: + key: access-token + name: splunk-access-token + - name: SPLUNK_REALM + value: my-splunk-realm + - name: MY_CLUSTER_NAME + value: test-cluster-gateway-only + - name: HOST_PROC + value: /hostfs/proc + - name: HOST_SYS + value: /hostfs/sys + - name: HOST_ETC + value: /hostfs/etc + - name: HOST_VAR + value: /hostfs/var + - name: HOST_RUN + value: /hostfs/run + - name: HOST_DEV + value: /hostfs/dev + - name: MY_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: MY_NODE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: MY_POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: MY_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: MY_POD_UID + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.uid + - name: MY_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: SPLUNK_MEMORY_TOTAL_MIB + value: "200" + image: quay.io/signalfx/splunk-otel-collector:0.58.0 + imagePullPolicy: IfNotPresent + name: otc-container + resources: + limits: + cpu: 200m + memory: 200Mi + requests: + cpu: 100m + memory: 100Mi + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /conf + name: otc-internal + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: { } + serviceAccount: splunk-otel-operator-acccount + serviceAccountName: splunk-otel-operator-acccount + terminationGracePeriodSeconds: 30 + volumes: + - configMap: + defaultMode: 420 + items: + - key: collector.yaml + path: collector.yaml + name: test-gateway-only-gateway + name: otc-internal +status: + availableReplicas: 1 + readyReplicas: 1 + replicas: 1 diff --git a/tests/e2e/gateway/01-install.yaml b/tests/e2e/gateway/01-install.yaml new file mode 100644 index 00000000..754ce5b3 --- /dev/null +++ b/tests/e2e/gateway/01-install.yaml @@ -0,0 +1,22 @@ +apiVersion: otel.splunk.com/v1alpha1 +kind: Agent +metadata: + name: test-gateway-only +spec: + clusterName: test-cluster-gateway-only + realm: my-splunk-realm + agent: + enabled: false + clusterReceiver: + enabled: false + gateway: + enabled: true + resources: + limits: + cpu: 200m + memory: 200Mi + requests: + memory: 100Mi + cpu: 100m + replicas: + 1 \ No newline at end of file