From edb2a72a0a91de074e0ddadcf77dc168dcdec3fd Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Fri, 15 Dec 2023 19:00:56 +0100
Subject: [PATCH 01/36] Support monolithic deployment mode
Signed-off-by: Andreas Gerstmayr
---
.gitignore | 1 +
PROJECT | 13 +
apis/tempo/v1alpha1/tempomonolithic_types.go | 265 ++
.../tempo/v1alpha1/tempomonolithic_webhook.go | 77 +
apis/tempo/v1alpha1/zz_generated.deepcopy.go | 424 +++
.../tempo-operator.clusterserviceversion.yaml | 87 +-
.../tempo.grafana.com_tempomonolithics.yaml | 228 ++
.../tempo-operator.clusterserviceversion.yaml | 87 +-
.../tempo.grafana.com_tempomonolithics.yaml | 228 ++
cmd/start/main.go | 22 +-
.../tempo.grafana.com_tempomonolithics.yaml | 219 ++
config/crd/kustomization.yaml | 1 +
.../cainjection_in_tempomonolithics.yaml | 7 +
.../patches/webhook_in_tempomonolithics.yaml | 16 +
.../tempo-operator.clusterserviceversion.yaml | 5 +
.../tempo-operator.clusterserviceversion.yaml | 5 +
config/rbac/role.yaml | 26 +
config/samples/community/kustomization.yaml | 1 +
.../tempo_v1alpha1_tempomonolithic.yaml | 8 +
config/samples/openshift/kustomization.yaml | 1 +
.../tempo_v1alpha1_tempomonolithic.yaml | 8 +
config/webhook/manifests.yaml | 40 +
controllers/tempo/common.go | 68 +
.../tempo/tempomonolithic_controller.go | 78 +
controllers/tempo/tempostack_controller.go | 2 +-
.../tempo/tempostack_create_or_update.go | 10 -
docs/operator/api.md | 2551 +++++++++++++----
docs/spec/tempomonolithic.yaml | 39 +
internal/manifests/manifestutils/constants.go | 15 +
internal/manifests/monolithic/build.go | 28 +
internal/manifests/monolithic/config.go | 162 ++
internal/manifests/monolithic/labels.go | 19 +
internal/manifests/monolithic/options.go | 13 +
internal/manifests/monolithic/service.go | 126 +
internal/manifests/monolithic/statefulset.go | 252 ++
internal/manifests/mutate.go | 42 +-
.../manifests/queryfrontend/query_frontend.go | 45 +-
.../queryfrontend/query_frontend_test.go | 34 +-
38 files changed, 4668 insertions(+), 585 deletions(-)
create mode 100644 apis/tempo/v1alpha1/tempomonolithic_types.go
create mode 100644 apis/tempo/v1alpha1/tempomonolithic_webhook.go
create mode 100644 bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
create mode 100644 bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
create mode 100644 config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
create mode 100644 config/crd/patches/cainjection_in_tempomonolithics.yaml
create mode 100644 config/crd/patches/webhook_in_tempomonolithics.yaml
create mode 100644 config/samples/community/tempo_v1alpha1_tempomonolithic.yaml
create mode 100644 config/samples/openshift/tempo_v1alpha1_tempomonolithic.yaml
create mode 100644 controllers/tempo/common.go
create mode 100644 controllers/tempo/tempomonolithic_controller.go
create mode 100644 docs/spec/tempomonolithic.yaml
create mode 100644 internal/manifests/monolithic/build.go
create mode 100644 internal/manifests/monolithic/config.go
create mode 100644 internal/manifests/monolithic/labels.go
create mode 100644 internal/manifests/monolithic/options.go
create mode 100644 internal/manifests/monolithic/service.go
create mode 100644 internal/manifests/monolithic/statefulset.go
diff --git a/.gitignore b/.gitignore
index f591b5792..4eff0bac3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,4 @@ docs/prologue/contributing.md
#IDE
.idea
+.vscode
diff --git a/PROJECT b/PROJECT
index 37a0e69b5..cf3097871 100644
--- a/PROJECT
+++ b/PROJECT
@@ -21,4 +21,17 @@ resources:
defaulting: true
validation: true
webhookVersion: v1
+- api:
+ crdVersion: v1
+ namespaced: true
+ controller: true
+ domain: grafana.com
+ group: tempo
+ kind: TempoMonolithic
+ path: github.com/grafana/tempo-operator/api/v1alpha1
+ version: v1alpha1
+ webhooks:
+ defaulting: true
+ validation: true
+ webhookVersion: v1
version: "3"
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
new file mode 100644
index 000000000..ee535f8df
--- /dev/null
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -0,0 +1,265 @@
+package v1alpha1
+
+import (
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "k8s.io/apimachinery/pkg/api/resource"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// TempoMonolithicSpec defines the desired state of TempoMonolithic.
+type TempoMonolithicSpec struct {
+ // Storage defines the backend storage configuration
+ //
+ // +kubebuilder:validation:Optional
+ Storage MonolithicStorageSpec `json:"storage"`
+
+ // Ingestion defines the trace ingestion configuration
+ //
+ // +kubebuilder:validation:Optional
+ Ingestion *MonolithicIngestionSpec `json:"ingestion,omitempty"`
+
+ // JaegerUI defines the Jaeger UI configuration
+ //
+ // +kubebuilder:validation:Optional
+ JaegerUI *MonolithicJaegerUISpec `json:"jaegerui,omitempty"`
+
+ // ManagementState defines whether this instance is managed by the operator or self-managed
+ //
+ // +kubebuilder:validation:Required
+ Management ManagementStateType `json:"management,omitempty"`
+
+ // Observability defines observability configuration for the Tempo deployment
+ //
+ // +kubebuilder:validation:Optional
+ Observability *MonolithicObservabilitySpec `json:"observability,omitempty"`
+
+ // ExtraConfig defines any extra (overlay) configuration for components
+ //
+ // +kubebuilder:validation:Optional
+ ExtraConfig *MonolithicExtraConfigSpec `json:"extraConfig,omitempty"`
+}
+
+// MonolithicStorageSpec defines the storage for the Tempo deployment.
+type MonolithicStorageSpec struct {
+ // Traces defines the backend storage configuration for traces
+ //
+ // +kubebuilder:validation:Required
+ Traces MonolithicTracesStorageSpec `json:"traces"`
+}
+
+// MonolithicTracesStorageSpec defines the traces storage for the Tempo deployment.
+type MonolithicTracesStorageSpec struct {
+ // Backend defines the backend for storing traces
+ //
+ // +kubebuilder:validation:Required
+ Backend MonolithicTracesStorageBackend `json:"backend"`
+
+ // WAL defines the write-ahead logging (WAL) configuration
+ //
+ // +kubebuilder:validation:Required
+ WAL *MonolithicTracesStorageWALSpec `json:"wal"`
+
+ // PV defines the Persistent Volume configuration
+ //
+ // +kubebuilder:validation:Required
+ PV *MonolithicTracesStoragePersistentVolumeSpec `json:"pv"`
+}
+
+// MonolithicTracesStorageBackend defines the backend storage for traces.
+//
+// +kubebuilder:validation:Enum=memory;pv
+type MonolithicTracesStorageBackend string
+
+const (
+ // MonolithicTracesStorageBackendMemory specifies a in-memory storage backend.
+ MonolithicTracesStorageBackendMemory MonolithicTracesStorageBackend = "memory"
+ // MonolithicTracesStorageBackendPersistentVolume specifies a Persistent Volume storage backend.
+ MonolithicTracesStorageBackendPersistentVolume MonolithicTracesStorageBackend = "pv"
+)
+
+// MonolithicTracesStorageWALSpec defines the write-ahead logging (WAL) configuration.
+type MonolithicTracesStorageWALSpec struct {
+ // Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
+ //
+ // +kubebuilder:validation:Required
+ Size resource.Quantity `json:"size"`
+}
+
+// MonolithicTracesStoragePersistentVolumeSpec defines the Persistent Volume configuration.
+type MonolithicTracesStoragePersistentVolumeSpec struct {
+ // Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
+ //
+ // +kubebuilder:validation:Required
+ Size resource.Quantity `json:"size"`
+}
+
+// MonolithicIngestionSpec defines the ingestion settings.
+type MonolithicIngestionSpec struct {
+ // OTLP defines the ingestion configuration for OTLP
+ //
+ // +kubebuilder:validation:Optional
+ OTLP *MonolithicIngestionOTLPSpec `json:"otlp,omitempty"`
+
+ // TLS defines the TLS configuration for ingestion
+ //
+ // +kubebuilder:validation:Optional
+ TLS *MonolithicIngestionTLSSpec `json:"tls,omitempty"`
+}
+
+// MonolithicIngestionOTLPSpec defines the settings for OTLP ingestion.
+type MonolithicIngestionOTLPSpec struct {
+ // GRPC defines the OTLP/gRPC configuration
+ //
+ // +kubebuilder:validation:Optional
+ GRPC *MonolithicIngestionOTLPProtocolsGRPCSpec `json:"grpc,omitempty"`
+
+ // HTTP defines the OTLP/HTTP configuration
+ //
+ // +kubebuilder:validation:Optional
+ HTTP *MonolithicIngestionOTLPProtocolsHTTPSpec `json:"http,omitempty"`
+}
+
+// MonolithicIngestionOTLPProtocolsGRPCSpec defines the settings for OTLP ingestion over GRPC.
+type MonolithicIngestionOTLPProtocolsGRPCSpec struct {
+ // Enabled defines if OTLP over gRPC is enabled
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+}
+
+// MonolithicIngestionOTLPProtocolsHTTPSpec defines the settings for OTLP ingestion over HTTP.
+type MonolithicIngestionOTLPProtocolsHTTPSpec struct {
+ // Enabled defines if OTLP over HTTP is enabled
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+}
+
+// MonolithicIngestionTLSSpec defines the TLS settings for ingestion.
+type MonolithicIngestionTLSSpec struct {
+ // Enabled defines if TLS is enabled for ingestion
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+
+ // CA defines the name of a secret containing the CA certificate
+ //
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:MinLength=1
+ CA string `json:"ca"`
+
+ // Cert defines the name of a secret containing the TLS certificate and private key
+ //
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:MinLength=1
+ Cert string `json:"cert"`
+}
+
+// MonolithicJaegerUISpec defines the settings for the Jaeger UI.
+type MonolithicJaegerUISpec struct {
+ // Enabled defines if the Jaeger UI should be enabled
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+
+ // Ingress defines the ingress configuration for Jaeger UI
+ //
+ // +kubebuilder:validation:Optional
+ Ingress *MonolithicJaegerUIIngressSpec `json:"ingress,omitempty"`
+
+ // Route defines the route configuration for Jaeger UI
+ //
+ // +kubebuilder:validation:Optional
+ Route *MonolithicJaegerUIRouteSpec `json:"route,omitempty"`
+}
+
+// MonolithicJaegerUIIngressSpec defines the settings for the Jaeger UI ingress.
+type MonolithicJaegerUIIngressSpec struct {
+ // Enabled defines if an Ingress object should be created for Jaeger UI
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+}
+
+// MonolithicJaegerUIRouteSpec defines the settings for the Jaeger UI route.
+type MonolithicJaegerUIRouteSpec struct {
+ // Enabled defines if a Route object should be created for Jaeger UI
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+}
+
+// MonolithicObservabilitySpec defines the observability settings of the Tempo deployment.
+type MonolithicObservabilitySpec struct {
+ // Metrics defines the metrics configuration of the Tempo deployment
+ //
+ // +kubebuilder:validation:Optional
+ Metrics *MonolithicObservabilityMetricsSpec `json:"metrics,omitempty"`
+}
+
+// MonolithicObservabilityMetricsSpec defines the metrics settings of the Tempo deployment.
+type MonolithicObservabilityMetricsSpec struct {
+ // ServiceMonitors defines the ServiceMonitor configuration
+ //
+ // +kubebuilder:validation:Optional
+ ServiceMonitors *MonolithicObservabilityMetricsServiceMonitorsSpec `json:"serviceMonitors,omitempty"`
+
+ // ServiceMonitors defines the PrometheusRule configuration
+ //
+ // +kubebuilder:validation:Optional
+ PrometheusRules *MonolithicObservabilityMetricsPrometheusRulesSpec `json:"prometheusRules,omitempty"`
+}
+
+// MonolithicObservabilityMetricsServiceMonitorsSpec defines the ServiceMonitor settings.
+type MonolithicObservabilityMetricsServiceMonitorsSpec struct {
+ // Enabled defines if the operator should create ServiceMonitors for this Tempo deployment
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+}
+
+// MonolithicObservabilityMetricsPrometheusRulesSpec defines the PrometheusRules settings.
+type MonolithicObservabilityMetricsPrometheusRulesSpec struct {
+ // Enabled defines if the operator should create PrometheusRules for this Tempo deployment
+ //
+ // +kubebuilder:validation:Required
+ Enabled bool `json:"enabled"`
+}
+
+// MonolithicExtraConfigSpec defines extra configuration for this deployment.
+type MonolithicExtraConfigSpec struct {
+ // Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
+ // +kubebuilder:validation:Optional
+ Tempo apiextensionsv1.JSON `json:"tempo,omitempty"`
+}
+
+// TempoMonolithicStatus defines the observed state of TempoMonolithic.
+type TempoMonolithicStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+
+// TempoMonolithic is the Schema for the tempomonolithics API.
+type TempoMonolithic struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec TempoMonolithicSpec `json:"spec,omitempty"`
+ Status TempoMonolithicStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// TempoMonolithicList contains a list of TempoMonolithic.
+type TempoMonolithicList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []TempoMonolithic `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&TempoMonolithic{}, &TempoMonolithicList{})
+}
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
new file mode 100644
index 000000000..ff7d71b5d
--- /dev/null
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -0,0 +1,77 @@
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// SetupWebhookWithManager will setup the manager to manage the webhooks.
+func (r *TempoMonolithic) SetupWebhookWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewWebhookManagedBy(mgr).
+ For(r).
+ Complete()
+}
+
+//+kubebuilder:webhook:path=/mutate-tempo-grafana-com-v1alpha1-tempomonolithic,mutating=true,failurePolicy=fail,sideEffects=None,groups=tempo.grafana.com,resources=tempomonolithics,verbs=create;update,versions=v1alpha1,name=mtempomonolithic.kb.io,admissionReviewVersions=v1
+
+var _ webhook.Defaulter = &TempoMonolithic{}
+
+// Default implements webhook.Defaulter so a webhook will be registered for the type.
+func (r *TempoMonolithic) Default() {
+ log := ctrl.Log.WithName("tempomonolithic-webhook")
+ log.V(1).Info("running defaulter webhook", "name", r.Name)
+
+ if r.Spec.Storage.Traces.Backend == "" {
+ r.Spec.Storage.Traces.Backend = MonolithicTracesStorageBackendMemory
+ }
+
+ if r.Spec.Storage.Traces.Backend != MonolithicTracesStorageBackendMemory && r.Spec.Storage.Traces.WAL == nil {
+ r.Spec.Storage.Traces.WAL = &MonolithicTracesStorageWALSpec{
+ Size: tenGBQuantity,
+ }
+ }
+
+ if r.Spec.Storage.Traces.Backend == MonolithicTracesStorageBackendPersistentVolume && r.Spec.Storage.Traces.PV == nil {
+ r.Spec.Storage.Traces.PV = &MonolithicTracesStoragePersistentVolumeSpec{
+ Size: tenGBQuantity,
+ }
+ }
+
+ if r.Spec.Ingestion == nil {
+ r.Spec.Ingestion = &MonolithicIngestionSpec{
+ OTLP: &MonolithicIngestionOTLPSpec{
+ GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ }
+ }
+}
+
+//+kubebuilder:webhook:path=/validate-tempo-grafana-com-v1alpha1-tempomonolithic,mutating=false,failurePolicy=fail,sideEffects=None,groups=tempo.grafana.com,resources=tempomonolithics,verbs=create;update,versions=v1alpha1,name=vtempomonolithic.kb.io,admissionReviewVersions=v1
+
+var _ webhook.Validator = &TempoMonolithic{}
+
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
+func (r *TempoMonolithic) ValidateCreate() (admission.Warnings, error) {
+ return r.validate()
+}
+
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
+func (r *TempoMonolithic) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ return r.validate()
+}
+
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
+func (r *TempoMonolithic) ValidateDelete() (admission.Warnings, error) {
+ // TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
+ return r.validate()
+}
+
+func (r *TempoMonolithic) validate() (admission.Warnings, error) {
+ log := ctrl.Log.WithName("tempomonolithic-webhook")
+ log.V(1).Info("running validating webhook", "name", r.Name)
+ return nil, nil
+}
diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
index c6870d8e1..7829eda3a 100644
--- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -366,6 +366,320 @@ func (in *MetricsConfigSpec) DeepCopy() *MetricsConfigSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicExtraConfigSpec) DeepCopyInto(out *MonolithicExtraConfigSpec) {
+ *out = *in
+ in.Tempo.DeepCopyInto(&out.Tempo)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicExtraConfigSpec.
+func (in *MonolithicExtraConfigSpec) DeepCopy() *MonolithicExtraConfigSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicExtraConfigSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicIngestionOTLPProtocolsGRPCSpec) DeepCopyInto(out *MonolithicIngestionOTLPProtocolsGRPCSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionOTLPProtocolsGRPCSpec.
+func (in *MonolithicIngestionOTLPProtocolsGRPCSpec) DeepCopy() *MonolithicIngestionOTLPProtocolsGRPCSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicIngestionOTLPProtocolsGRPCSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicIngestionOTLPProtocolsHTTPSpec) DeepCopyInto(out *MonolithicIngestionOTLPProtocolsHTTPSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionOTLPProtocolsHTTPSpec.
+func (in *MonolithicIngestionOTLPProtocolsHTTPSpec) DeepCopy() *MonolithicIngestionOTLPProtocolsHTTPSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicIngestionOTLPProtocolsHTTPSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicIngestionOTLPSpec) DeepCopyInto(out *MonolithicIngestionOTLPSpec) {
+ *out = *in
+ if in.GRPC != nil {
+ in, out := &in.GRPC, &out.GRPC
+ *out = new(MonolithicIngestionOTLPProtocolsGRPCSpec)
+ **out = **in
+ }
+ if in.HTTP != nil {
+ in, out := &in.HTTP, &out.HTTP
+ *out = new(MonolithicIngestionOTLPProtocolsHTTPSpec)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionOTLPSpec.
+func (in *MonolithicIngestionOTLPSpec) DeepCopy() *MonolithicIngestionOTLPSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicIngestionOTLPSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicIngestionSpec) DeepCopyInto(out *MonolithicIngestionSpec) {
+ *out = *in
+ if in.OTLP != nil {
+ in, out := &in.OTLP, &out.OTLP
+ *out = new(MonolithicIngestionOTLPSpec)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.TLS != nil {
+ in, out := &in.TLS, &out.TLS
+ *out = new(MonolithicIngestionTLSSpec)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionSpec.
+func (in *MonolithicIngestionSpec) DeepCopy() *MonolithicIngestionSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicIngestionSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicIngestionTLSSpec) DeepCopyInto(out *MonolithicIngestionTLSSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionTLSSpec.
+func (in *MonolithicIngestionTLSSpec) DeepCopy() *MonolithicIngestionTLSSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicIngestionTLSSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicJaegerUIIngressSpec) DeepCopyInto(out *MonolithicJaegerUIIngressSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicJaegerUIIngressSpec.
+func (in *MonolithicJaegerUIIngressSpec) DeepCopy() *MonolithicJaegerUIIngressSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicJaegerUIIngressSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicJaegerUIRouteSpec) DeepCopyInto(out *MonolithicJaegerUIRouteSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicJaegerUIRouteSpec.
+func (in *MonolithicJaegerUIRouteSpec) DeepCopy() *MonolithicJaegerUIRouteSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicJaegerUIRouteSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicJaegerUISpec) DeepCopyInto(out *MonolithicJaegerUISpec) {
+ *out = *in
+ if in.Ingress != nil {
+ in, out := &in.Ingress, &out.Ingress
+ *out = new(MonolithicJaegerUIIngressSpec)
+ **out = **in
+ }
+ if in.Route != nil {
+ in, out := &in.Route, &out.Route
+ *out = new(MonolithicJaegerUIRouteSpec)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicJaegerUISpec.
+func (in *MonolithicJaegerUISpec) DeepCopy() *MonolithicJaegerUISpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicJaegerUISpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicObservabilityMetricsPrometheusRulesSpec) DeepCopyInto(out *MonolithicObservabilityMetricsPrometheusRulesSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicObservabilityMetricsPrometheusRulesSpec.
+func (in *MonolithicObservabilityMetricsPrometheusRulesSpec) DeepCopy() *MonolithicObservabilityMetricsPrometheusRulesSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicObservabilityMetricsPrometheusRulesSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicObservabilityMetricsServiceMonitorsSpec) DeepCopyInto(out *MonolithicObservabilityMetricsServiceMonitorsSpec) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicObservabilityMetricsServiceMonitorsSpec.
+func (in *MonolithicObservabilityMetricsServiceMonitorsSpec) DeepCopy() *MonolithicObservabilityMetricsServiceMonitorsSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicObservabilityMetricsServiceMonitorsSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicObservabilityMetricsSpec) DeepCopyInto(out *MonolithicObservabilityMetricsSpec) {
+ *out = *in
+ if in.ServiceMonitors != nil {
+ in, out := &in.ServiceMonitors, &out.ServiceMonitors
+ *out = new(MonolithicObservabilityMetricsServiceMonitorsSpec)
+ **out = **in
+ }
+ if in.PrometheusRules != nil {
+ in, out := &in.PrometheusRules, &out.PrometheusRules
+ *out = new(MonolithicObservabilityMetricsPrometheusRulesSpec)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicObservabilityMetricsSpec.
+func (in *MonolithicObservabilityMetricsSpec) DeepCopy() *MonolithicObservabilityMetricsSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicObservabilityMetricsSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicObservabilitySpec) DeepCopyInto(out *MonolithicObservabilitySpec) {
+ *out = *in
+ if in.Metrics != nil {
+ in, out := &in.Metrics, &out.Metrics
+ *out = new(MonolithicObservabilityMetricsSpec)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicObservabilitySpec.
+func (in *MonolithicObservabilitySpec) DeepCopy() *MonolithicObservabilitySpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicObservabilitySpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicStorageSpec) DeepCopyInto(out *MonolithicStorageSpec) {
+ *out = *in
+ in.Traces.DeepCopyInto(&out.Traces)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicStorageSpec.
+func (in *MonolithicStorageSpec) DeepCopy() *MonolithicStorageSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicStorageSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicTracesStoragePersistentVolumeSpec) DeepCopyInto(out *MonolithicTracesStoragePersistentVolumeSpec) {
+ *out = *in
+ out.Size = in.Size.DeepCopy()
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicTracesStoragePersistentVolumeSpec.
+func (in *MonolithicTracesStoragePersistentVolumeSpec) DeepCopy() *MonolithicTracesStoragePersistentVolumeSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicTracesStoragePersistentVolumeSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicTracesStorageSpec) DeepCopyInto(out *MonolithicTracesStorageSpec) {
+ *out = *in
+ if in.WAL != nil {
+ in, out := &in.WAL, &out.WAL
+ *out = new(MonolithicTracesStorageWALSpec)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.PV != nil {
+ in, out := &in.PV, &out.PV
+ *out = new(MonolithicTracesStoragePersistentVolumeSpec)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicTracesStorageSpec.
+func (in *MonolithicTracesStorageSpec) DeepCopy() *MonolithicTracesStorageSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicTracesStorageSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MonolithicTracesStorageWALSpec) DeepCopyInto(out *MonolithicTracesStorageWALSpec) {
+ *out = *in
+ out.Size = in.Size.DeepCopy()
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicTracesStorageWALSpec.
+func (in *MonolithicTracesStorageWALSpec) DeepCopy() *MonolithicTracesStorageWALSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MonolithicTracesStorageWALSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCSpec) DeepCopyInto(out *OIDCSpec) {
*out = *in
@@ -771,6 +1085,116 @@ func (in *TempoGatewaySpec) DeepCopy() *TempoGatewaySpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TempoMonolithic) DeepCopyInto(out *TempoMonolithic) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TempoMonolithic.
+func (in *TempoMonolithic) DeepCopy() *TempoMonolithic {
+ if in == nil {
+ return nil
+ }
+ out := new(TempoMonolithic)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *TempoMonolithic) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TempoMonolithicList) DeepCopyInto(out *TempoMonolithicList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]TempoMonolithic, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TempoMonolithicList.
+func (in *TempoMonolithicList) DeepCopy() *TempoMonolithicList {
+ if in == nil {
+ return nil
+ }
+ out := new(TempoMonolithicList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *TempoMonolithicList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TempoMonolithicSpec) DeepCopyInto(out *TempoMonolithicSpec) {
+ *out = *in
+ in.Storage.DeepCopyInto(&out.Storage)
+ if in.Ingestion != nil {
+ in, out := &in.Ingestion, &out.Ingestion
+ *out = new(MonolithicIngestionSpec)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.JaegerUI != nil {
+ in, out := &in.JaegerUI, &out.JaegerUI
+ *out = new(MonolithicJaegerUISpec)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Observability != nil {
+ in, out := &in.Observability, &out.Observability
+ *out = new(MonolithicObservabilitySpec)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.ExtraConfig != nil {
+ in, out := &in.ExtraConfig, &out.ExtraConfig
+ *out = new(MonolithicExtraConfigSpec)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TempoMonolithicSpec.
+func (in *TempoMonolithicSpec) DeepCopy() *TempoMonolithicSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(TempoMonolithicSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TempoMonolithicStatus) DeepCopyInto(out *TempoMonolithicStatus) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TempoMonolithicStatus.
+func (in *TempoMonolithicStatus) DeepCopy() *TempoMonolithicStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(TempoMonolithicStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TempoQueryFrontendSpec) DeepCopyInto(out *TempoQueryFrontendSpec) {
*out = *in
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index bd9ff4e0c..26fcd0a89 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -4,6 +4,20 @@ metadata:
annotations:
alm-examples: |-
[
+ {
+ "apiVersion": "tempo.grafana.com/v1alpha1",
+ "kind": "TempoMonolithic",
+ "metadata": {
+ "name": "sample"
+ },
+ "spec": {
+ "storage": {
+ "traces": {
+ "backend": "memory"
+ }
+ }
+ }
+ },
{
"apiVersion": "tempo.grafana.com/v1alpha1",
"kind": "TempoStack",
@@ -42,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2023-12-13T18:24:45Z"
+ createdAt: "2023-12-21T12:56:45Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -57,6 +71,11 @@ spec:
apiservicedefinitions: {}
customresourcedefinitions:
owned:
+ - description: TempoMonolithic is the Schema for the tempomonolithics API.
+ displayName: Tempo Monolithic
+ kind: TempoMonolithic
+ name: tempomonolithics.tempo.grafana.com
+ version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
kind: TempoStack
@@ -739,6 +758,32 @@ spec:
- list
- update
- watch
+ - apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+ - apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics/finalizers
+ verbs:
+ - update
+ - apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics/status
+ verbs:
+ - get
+ - patch
+ - update
- apiGroups:
- tempo.grafana.com
resources:
@@ -965,6 +1010,26 @@ spec:
name: tempo-gateway-opa
version: 0.6.0
webhookdefinitions:
+ - admissionReviewVersions:
+ - v1
+ containerPort: 443
+ deploymentName: tempo-operator-controller
+ failurePolicy: Fail
+ generateName: mtempomonolithic.kb.io
+ rules:
+ - apiGroups:
+ - tempo.grafana.com
+ apiVersions:
+ - v1alpha1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - tempomonolithics
+ sideEffects: None
+ targetPort: 9443
+ type: MutatingAdmissionWebhook
+ webhookPath: /mutate-tempo-grafana-com-v1alpha1-tempomonolithic
- admissionReviewVersions:
- v1
containerPort: 443
@@ -985,6 +1050,26 @@ spec:
targetPort: 9443
type: MutatingAdmissionWebhook
webhookPath: /mutate-tempo-grafana-com-v1alpha1-tempostack
+ - admissionReviewVersions:
+ - v1
+ containerPort: 443
+ deploymentName: tempo-operator-controller
+ failurePolicy: Fail
+ generateName: vtempomonolithic.kb.io
+ rules:
+ - apiGroups:
+ - tempo.grafana.com
+ apiVersions:
+ - v1alpha1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - tempomonolithics
+ sideEffects: None
+ targetPort: 9443
+ type: ValidatingAdmissionWebhook
+ webhookPath: /validate-tempo-grafana-com-v1alpha1-tempomonolithic
- admissionReviewVersions:
- v1
containerPort: 443
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
new file mode 100644
index 000000000..04502402a
--- /dev/null
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -0,0 +1,228 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ labels:
+ app.kubernetes.io/managed-by: operator-lifecycle-manager
+ app.kubernetes.io/name: tempo-operator
+ app.kubernetes.io/part-of: tempo-operator
+ name: tempomonolithics.tempo.grafana.com
+spec:
+ group: tempo.grafana.com
+ names:
+ kind: TempoMonolithic
+ listKind: TempoMonolithicList
+ plural: tempomonolithics
+ singular: tempomonolithic
+ scope: Namespaced
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: TempoMonolithic is the Schema for the tempomonolithics API.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: TempoMonolithicSpec defines the desired state of TempoMonolithic.
+ properties:
+ extraConfig:
+ description: ExtraConfig defines any extra (overlay) configuration
+ for components
+ properties:
+ tempo:
+ description: Tempo defines any extra Tempo configuration, which
+ will be merged with the operator's generated Tempo configuration
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ ingestion:
+ description: Ingestion defines the trace ingestion configuration
+ properties:
+ otlp:
+ description: OTLP defines the ingestion configuration for OTLP
+ properties:
+ grpc:
+ description: GRPC defines the OTLP/gRPC configuration
+ properties:
+ enabled:
+ description: Enabled defines if OTLP over gRPC is enabled
+ type: boolean
+ required:
+ - enabled
+ type: object
+ http:
+ description: HTTP defines the OTLP/HTTP configuration
+ properties:
+ enabled:
+ description: Enabled defines if OTLP over HTTP is enabled
+ type: boolean
+ required:
+ - enabled
+ type: object
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for ingestion
+ properties:
+ ca:
+ description: CA defines the name of a secret containing the
+ CA certificate
+ minLength: 1
+ type: string
+ cert:
+ description: Cert defines the name of a secret containing
+ the TLS certificate and private key
+ minLength: 1
+ type: string
+ enabled:
+ description: Enabled defines if TLS is enabled for ingestion
+ type: boolean
+ required:
+ - ca
+ - cert
+ - enabled
+ type: object
+ type: object
+ jaegerui:
+ description: JaegerUI defines the Jaeger UI configuration
+ properties:
+ enabled:
+ description: Enabled defines if the Jaeger UI should be enabled
+ type: boolean
+ ingress:
+ description: Ingress defines the ingress configuration for Jaeger
+ UI
+ properties:
+ enabled:
+ description: Enabled defines if an Ingress object should be
+ created for Jaeger UI
+ type: boolean
+ required:
+ - enabled
+ type: object
+ route:
+ description: Route defines the route configuration for Jaeger
+ UI
+ properties:
+ enabled:
+ description: Enabled defines if a Route object should be created
+ for Jaeger UI
+ type: boolean
+ required:
+ - enabled
+ type: object
+ required:
+ - enabled
+ type: object
+ management:
+ description: ManagementState defines whether this instance is managed
+ by the operator or self-managed
+ enum:
+ - Managed
+ - Unmanaged
+ type: string
+ observability:
+ description: Observability defines observability configuration for
+ the Tempo deployment
+ properties:
+ metrics:
+ description: Metrics defines the metrics configuration of the
+ Tempo deployment
+ properties:
+ prometheusRules:
+ description: ServiceMonitors defines the PrometheusRule configuration
+ properties:
+ enabled:
+ description: Enabled defines if the operator should create
+ PrometheusRules for this Tempo deployment
+ type: boolean
+ required:
+ - enabled
+ type: object
+ serviceMonitors:
+ description: ServiceMonitors defines the ServiceMonitor configuration
+ properties:
+ enabled:
+ description: Enabled defines if the operator should create
+ ServiceMonitors for this Tempo deployment
+ type: boolean
+ required:
+ - enabled
+ type: object
+ type: object
+ type: object
+ storage:
+ description: Storage defines the backend storage configuration
+ properties:
+ traces:
+ description: Traces defines the backend storage configuration
+ for traces
+ properties:
+ backend:
+ description: Backend defines the backend for storing traces
+ enum:
+ - memory
+ - pv
+ type: string
+ pv:
+ description: PV defines the Persistent Volume configuration
+ properties:
+ size:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Size defines the size of the Persistent Volume
+ for storing the traces. Defaults to 10Gi.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - size
+ type: object
+ wal:
+ description: WAL defines the write-ahead logging (WAL) configuration
+ properties:
+ size:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Size defines the size of the Persistent Volume
+ for storing the WAL. Defaults to 10Gi.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - size
+ type: object
+ required:
+ - backend
+ - pv
+ - wal
+ type: object
+ required:
+ - traces
+ type: object
+ type: object
+ status:
+ description: TempoMonolithicStatus defines the observed state of TempoMonolithic.
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: null
+ storedVersions: null
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index 697f9809a..8951a1ee8 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -4,6 +4,20 @@ metadata:
annotations:
alm-examples: |-
[
+ {
+ "apiVersion": "tempo.grafana.com/v1alpha1",
+ "kind": "TempoMonolithic",
+ "metadata": {
+ "name": "sample"
+ },
+ "spec": {
+ "storage": {
+ "traces": {
+ "backend": "memory"
+ }
+ }
+ }
+ },
{
"apiVersion": "tempo.grafana.com/v1alpha1",
"kind": "TempoStack",
@@ -42,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2023-12-13T18:24:44Z"
+ createdAt: "2023-12-21T12:56:44Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -57,6 +71,11 @@ spec:
apiservicedefinitions: {}
customresourcedefinitions:
owned:
+ - description: TempoMonolithic is the Schema for the tempomonolithics API.
+ displayName: Tempo Monolithic
+ kind: TempoMonolithic
+ name: tempomonolithics.tempo.grafana.com
+ version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
kind: TempoStack
@@ -739,6 +758,32 @@ spec:
- list
- update
- watch
+ - apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+ - apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics/finalizers
+ verbs:
+ - update
+ - apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics/status
+ verbs:
+ - get
+ - patch
+ - update
- apiGroups:
- tempo.grafana.com
resources:
@@ -976,6 +1021,26 @@ spec:
name: tempo-gateway-opa
version: 0.6.0
webhookdefinitions:
+ - admissionReviewVersions:
+ - v1
+ containerPort: 443
+ deploymentName: tempo-operator-controller
+ failurePolicy: Fail
+ generateName: mtempomonolithic.kb.io
+ rules:
+ - apiGroups:
+ - tempo.grafana.com
+ apiVersions:
+ - v1alpha1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - tempomonolithics
+ sideEffects: None
+ targetPort: 9443
+ type: MutatingAdmissionWebhook
+ webhookPath: /mutate-tempo-grafana-com-v1alpha1-tempomonolithic
- admissionReviewVersions:
- v1
containerPort: 443
@@ -996,6 +1061,26 @@ spec:
targetPort: 9443
type: MutatingAdmissionWebhook
webhookPath: /mutate-tempo-grafana-com-v1alpha1-tempostack
+ - admissionReviewVersions:
+ - v1
+ containerPort: 443
+ deploymentName: tempo-operator-controller
+ failurePolicy: Fail
+ generateName: vtempomonolithic.kb.io
+ rules:
+ - apiGroups:
+ - tempo.grafana.com
+ apiVersions:
+ - v1alpha1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - tempomonolithics
+ sideEffects: None
+ targetPort: 9443
+ type: ValidatingAdmissionWebhook
+ webhookPath: /validate-tempo-grafana-com-v1alpha1-tempomonolithic
- admissionReviewVersions:
- v1
containerPort: 443
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
new file mode 100644
index 000000000..04502402a
--- /dev/null
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -0,0 +1,228 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ labels:
+ app.kubernetes.io/managed-by: operator-lifecycle-manager
+ app.kubernetes.io/name: tempo-operator
+ app.kubernetes.io/part-of: tempo-operator
+ name: tempomonolithics.tempo.grafana.com
+spec:
+ group: tempo.grafana.com
+ names:
+ kind: TempoMonolithic
+ listKind: TempoMonolithicList
+ plural: tempomonolithics
+ singular: tempomonolithic
+ scope: Namespaced
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: TempoMonolithic is the Schema for the tempomonolithics API.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: TempoMonolithicSpec defines the desired state of TempoMonolithic.
+ properties:
+ extraConfig:
+ description: ExtraConfig defines any extra (overlay) configuration
+ for components
+ properties:
+ tempo:
+ description: Tempo defines any extra Tempo configuration, which
+ will be merged with the operator's generated Tempo configuration
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ ingestion:
+ description: Ingestion defines the trace ingestion configuration
+ properties:
+ otlp:
+ description: OTLP defines the ingestion configuration for OTLP
+ properties:
+ grpc:
+ description: GRPC defines the OTLP/gRPC configuration
+ properties:
+ enabled:
+ description: Enabled defines if OTLP over gRPC is enabled
+ type: boolean
+ required:
+ - enabled
+ type: object
+ http:
+ description: HTTP defines the OTLP/HTTP configuration
+ properties:
+ enabled:
+ description: Enabled defines if OTLP over HTTP is enabled
+ type: boolean
+ required:
+ - enabled
+ type: object
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for ingestion
+ properties:
+ ca:
+ description: CA defines the name of a secret containing the
+ CA certificate
+ minLength: 1
+ type: string
+ cert:
+ description: Cert defines the name of a secret containing
+ the TLS certificate and private key
+ minLength: 1
+ type: string
+ enabled:
+ description: Enabled defines if TLS is enabled for ingestion
+ type: boolean
+ required:
+ - ca
+ - cert
+ - enabled
+ type: object
+ type: object
+ jaegerui:
+ description: JaegerUI defines the Jaeger UI configuration
+ properties:
+ enabled:
+ description: Enabled defines if the Jaeger UI should be enabled
+ type: boolean
+ ingress:
+ description: Ingress defines the ingress configuration for Jaeger
+ UI
+ properties:
+ enabled:
+ description: Enabled defines if an Ingress object should be
+ created for Jaeger UI
+ type: boolean
+ required:
+ - enabled
+ type: object
+ route:
+ description: Route defines the route configuration for Jaeger
+ UI
+ properties:
+ enabled:
+ description: Enabled defines if a Route object should be created
+ for Jaeger UI
+ type: boolean
+ required:
+ - enabled
+ type: object
+ required:
+ - enabled
+ type: object
+ management:
+ description: ManagementState defines whether this instance is managed
+ by the operator or self-managed
+ enum:
+ - Managed
+ - Unmanaged
+ type: string
+ observability:
+ description: Observability defines observability configuration for
+ the Tempo deployment
+ properties:
+ metrics:
+ description: Metrics defines the metrics configuration of the
+ Tempo deployment
+ properties:
+ prometheusRules:
+ description: ServiceMonitors defines the PrometheusRule configuration
+ properties:
+ enabled:
+ description: Enabled defines if the operator should create
+ PrometheusRules for this Tempo deployment
+ type: boolean
+ required:
+ - enabled
+ type: object
+ serviceMonitors:
+ description: ServiceMonitors defines the ServiceMonitor configuration
+ properties:
+ enabled:
+ description: Enabled defines if the operator should create
+ ServiceMonitors for this Tempo deployment
+ type: boolean
+ required:
+ - enabled
+ type: object
+ type: object
+ type: object
+ storage:
+ description: Storage defines the backend storage configuration
+ properties:
+ traces:
+ description: Traces defines the backend storage configuration
+ for traces
+ properties:
+ backend:
+ description: Backend defines the backend for storing traces
+ enum:
+ - memory
+ - pv
+ type: string
+ pv:
+ description: PV defines the Persistent Volume configuration
+ properties:
+ size:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Size defines the size of the Persistent Volume
+ for storing the traces. Defaults to 10Gi.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - size
+ type: object
+ wal:
+ description: WAL defines the write-ahead logging (WAL) configuration
+ properties:
+ size:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Size defines the size of the Persistent Volume
+ for storing the WAL. Defaults to 10Gi.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - size
+ type: object
+ required:
+ - backend
+ - pv
+ - wal
+ type: object
+ required:
+ - traces
+ type: object
+ type: object
+ status:
+ description: TempoMonolithicStatus defines the observed state of TempoMonolithic.
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: null
+ storedVersions: null
diff --git a/cmd/start/main.go b/cmd/start/main.go
index 6613dde64..d9bb5b119 100644
--- a/cmd/start/main.go
+++ b/cmd/start/main.go
@@ -67,12 +67,25 @@ func start(c *cobra.Command, args []string) {
os.Exit(1)
}
+ if err = (&controllers.TempoMonolithicReconciler{
+ Client: mgr.GetClient(),
+ Scheme: mgr.GetScheme(),
+ CtrlConfig: ctrlConfig,
+ }).SetupWithManager(mgr); err != nil {
+ setupLog.Error(err, "unable to create controller", "controller", "TempoMonolithic")
+ os.Exit(1)
+ }
+
enableWebhooks := os.Getenv("ENABLE_WEBHOOKS") != "false"
if enableWebhooks {
if err = (&tempov1alpha1.TempoStack{}).SetupWebhookWithManager(mgr, ctrlConfig); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "TempoStack")
os.Exit(1)
}
+ if err = (&tempov1alpha1.TempoMonolithic{}).SetupWebhookWithManager(mgr); err != nil {
+ setupLog.Error(err, "unable to create webhook", "webhook", "TempoMonolithic")
+ os.Exit(1)
+ }
}
//+kubebuilder:scaffold:builder
@@ -130,7 +143,14 @@ func addDependencies(mgr ctrl.Manager, ctrlConfig configv1alpha1.ProjectConfig,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}
- return reconciler.Reconcile(ctx, ctrlConfig)
+
+ // log error but do not fail operator startup if operator reconcile fails
+ // operator reconcile is only used for creating ServiceMonitor and PrometheusRules of the operator itself
+ err := reconciler.Reconcile(ctx, ctrlConfig)
+ if err != nil {
+ ctrl.LoggerFrom(ctx).WithName("operator-reconcile").Error(err, "cannot reconcile operator")
+ }
+ return nil
}))
if err != nil {
return fmt.Errorf("failed to setup operator reconciler: %w", err)
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
new file mode 100644
index 000000000..857af2d41
--- /dev/null
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -0,0 +1,219 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.9.2
+ creationTimestamp: null
+ name: tempomonolithics.tempo.grafana.com
+spec:
+ group: tempo.grafana.com
+ names:
+ kind: TempoMonolithic
+ listKind: TempoMonolithicList
+ plural: tempomonolithics
+ singular: tempomonolithic
+ scope: Namespaced
+ versions:
+ - name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: TempoMonolithic is the Schema for the tempomonolithics API.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: TempoMonolithicSpec defines the desired state of TempoMonolithic.
+ properties:
+ extraConfig:
+ description: ExtraConfig defines any extra (overlay) configuration
+ for components
+ properties:
+ tempo:
+ description: Tempo defines any extra Tempo configuration, which
+ will be merged with the operator's generated Tempo configuration
+ x-kubernetes-preserve-unknown-fields: true
+ type: object
+ ingestion:
+ description: Ingestion defines the trace ingestion configuration
+ properties:
+ otlp:
+ description: OTLP defines the ingestion configuration for OTLP
+ properties:
+ grpc:
+ description: GRPC defines the OTLP/gRPC configuration
+ properties:
+ enabled:
+ description: Enabled defines if OTLP over gRPC is enabled
+ type: boolean
+ required:
+ - enabled
+ type: object
+ http:
+ description: HTTP defines the OTLP/HTTP configuration
+ properties:
+ enabled:
+ description: Enabled defines if OTLP over HTTP is enabled
+ type: boolean
+ required:
+ - enabled
+ type: object
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for ingestion
+ properties:
+ ca:
+ description: CA defines the name of a secret containing the
+ CA certificate
+ minLength: 1
+ type: string
+ cert:
+ description: Cert defines the name of a secret containing
+ the TLS certificate and private key
+ minLength: 1
+ type: string
+ enabled:
+ description: Enabled defines if TLS is enabled for ingestion
+ type: boolean
+ required:
+ - ca
+ - cert
+ - enabled
+ type: object
+ type: object
+ jaegerui:
+ description: JaegerUI defines the Jaeger UI configuration
+ properties:
+ enabled:
+ description: Enabled defines if the Jaeger UI should be enabled
+ type: boolean
+ ingress:
+ description: Ingress defines the ingress configuration for Jaeger
+ UI
+ properties:
+ enabled:
+ description: Enabled defines if an Ingress object should be
+ created for Jaeger UI
+ type: boolean
+ required:
+ - enabled
+ type: object
+ route:
+ description: Route defines the route configuration for Jaeger
+ UI
+ properties:
+ enabled:
+ description: Enabled defines if a Route object should be created
+ for Jaeger UI
+ type: boolean
+ required:
+ - enabled
+ type: object
+ required:
+ - enabled
+ type: object
+ management:
+ description: ManagementState defines whether this instance is managed
+ by the operator or self-managed
+ enum:
+ - Managed
+ - Unmanaged
+ type: string
+ observability:
+ description: Observability defines observability configuration for
+ the Tempo deployment
+ properties:
+ metrics:
+ description: Metrics defines the metrics configuration of the
+ Tempo deployment
+ properties:
+ prometheusRules:
+ description: ServiceMonitors defines the PrometheusRule configuration
+ properties:
+ enabled:
+ description: Enabled defines if the operator should create
+ PrometheusRules for this Tempo deployment
+ type: boolean
+ required:
+ - enabled
+ type: object
+ serviceMonitors:
+ description: ServiceMonitors defines the ServiceMonitor configuration
+ properties:
+ enabled:
+ description: Enabled defines if the operator should create
+ ServiceMonitors for this Tempo deployment
+ type: boolean
+ required:
+ - enabled
+ type: object
+ type: object
+ type: object
+ storage:
+ description: Storage defines the backend storage configuration
+ properties:
+ traces:
+ description: Traces defines the backend storage configuration
+ for traces
+ properties:
+ backend:
+ description: Backend defines the backend for storing traces
+ enum:
+ - memory
+ - pv
+ type: string
+ pv:
+ description: PV defines the Persistent Volume configuration
+ properties:
+ size:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Size defines the size of the Persistent Volume
+ for storing the traces. Defaults to 10Gi.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - size
+ type: object
+ wal:
+ description: WAL defines the write-ahead logging (WAL) configuration
+ properties:
+ size:
+ anyOf:
+ - type: integer
+ - type: string
+ description: Size defines the size of the Persistent Volume
+ for storing the WAL. Defaults to 10Gi.
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ required:
+ - size
+ type: object
+ required:
+ - backend
+ - pv
+ - wal
+ type: object
+ required:
+ - traces
+ type: object
+ type: object
+ status:
+ description: TempoMonolithicStatus defines the observed state of TempoMonolithic.
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 04bf60698..2eee3e92c 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -3,6 +3,7 @@
# It should be run by config/default
resources:
- bases/tempo.grafana.com_tempostacks.yaml
+- bases/tempo.grafana.com_tempomonolithics.yaml
#- bases/config.tempo.grafana.com_projectconfigs.yaml
#+kubebuilder:scaffold:crdkustomizeresource
diff --git a/config/crd/patches/cainjection_in_tempomonolithics.yaml b/config/crd/patches/cainjection_in_tempomonolithics.yaml
new file mode 100644
index 000000000..689bf4436
--- /dev/null
+++ b/config/crd/patches/cainjection_in_tempomonolithics.yaml
@@ -0,0 +1,7 @@
+# The following patch adds a directive for certmanager to inject CA into the CRD
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
+ name: tempomonolithics.tempo.grafana.com
diff --git a/config/crd/patches/webhook_in_tempomonolithics.yaml b/config/crd/patches/webhook_in_tempomonolithics.yaml
new file mode 100644
index 000000000..87d5b6053
--- /dev/null
+++ b/config/crd/patches/webhook_in_tempomonolithics.yaml
@@ -0,0 +1,16 @@
+# The following patch enables a conversion webhook for the CRD
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: tempomonolithics.tempo.grafana.com
+spec:
+ conversion:
+ strategy: Webhook
+ webhook:
+ clientConfig:
+ service:
+ namespace: system
+ name: webhook-service
+ path: /convert
+ conversionReviewVersions:
+ - v1
diff --git a/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml b/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
index 9e51e750b..ab2ca3e9d 100644
--- a/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
+++ b/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
@@ -18,6 +18,11 @@ spec:
apiservicedefinitions: {}
customresourcedefinitions:
owned:
+ - description: TempoMonolithic is the Schema for the tempomonolithics API.
+ displayName: Tempo Monolithic
+ kind: TempoMonolithic
+ name: tempomonolithics.tempo.grafana.com
+ version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
kind: TempoStack
diff --git a/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml b/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
index 9e51e750b..ab2ca3e9d 100644
--- a/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
+++ b/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
@@ -18,6 +18,11 @@ spec:
apiservicedefinitions: {}
customresourcedefinitions:
owned:
+ - description: TempoMonolithic is the Schema for the tempomonolithics API.
+ displayName: Tempo Monolithic
+ kind: TempoMonolithic
+ name: tempomonolithics.tempo.grafana.com
+ version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
kind: TempoStack
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index e4ebc88bd..7c433e504 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -118,6 +118,32 @@ rules:
- list
- update
- watch
+- apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics/finalizers
+ verbs:
+ - update
+- apiGroups:
+ - tempo.grafana.com
+ resources:
+ - tempomonolithics/status
+ verbs:
+ - get
+ - patch
+ - update
- apiGroups:
- tempo.grafana.com
resources:
diff --git a/config/samples/community/kustomization.yaml b/config/samples/community/kustomization.yaml
index c7b35e7c5..71b5852c7 100644
--- a/config/samples/community/kustomization.yaml
+++ b/config/samples/community/kustomization.yaml
@@ -1,4 +1,5 @@
## Append samples you want in your CSV to this file as resources ##
resources:
- tempo_v1alpha1_tempostack.yaml
+- tempo_v1alpha1_tempomonolithic.yaml
#+kubebuilder:scaffold:manifestskustomizesamples
diff --git a/config/samples/community/tempo_v1alpha1_tempomonolithic.yaml b/config/samples/community/tempo_v1alpha1_tempomonolithic.yaml
new file mode 100644
index 000000000..7530f6a54
--- /dev/null
+++ b/config/samples/community/tempo_v1alpha1_tempomonolithic.yaml
@@ -0,0 +1,8 @@
+apiVersion: tempo.grafana.com/v1alpha1
+kind: TempoMonolithic
+metadata:
+ name: sample
+spec:
+ storage:
+ traces:
+ backend: memory
diff --git a/config/samples/openshift/kustomization.yaml b/config/samples/openshift/kustomization.yaml
index c7b35e7c5..71b5852c7 100644
--- a/config/samples/openshift/kustomization.yaml
+++ b/config/samples/openshift/kustomization.yaml
@@ -1,4 +1,5 @@
## Append samples you want in your CSV to this file as resources ##
resources:
- tempo_v1alpha1_tempostack.yaml
+- tempo_v1alpha1_tempomonolithic.yaml
#+kubebuilder:scaffold:manifestskustomizesamples
diff --git a/config/samples/openshift/tempo_v1alpha1_tempomonolithic.yaml b/config/samples/openshift/tempo_v1alpha1_tempomonolithic.yaml
new file mode 100644
index 000000000..7530f6a54
--- /dev/null
+++ b/config/samples/openshift/tempo_v1alpha1_tempomonolithic.yaml
@@ -0,0 +1,8 @@
+apiVersion: tempo.grafana.com/v1alpha1
+kind: TempoMonolithic
+metadata:
+ name: sample
+spec:
+ storage:
+ traces:
+ backend: memory
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
index ac8ff9096..5ec8c2305 100644
--- a/config/webhook/manifests.yaml
+++ b/config/webhook/manifests.yaml
@@ -5,6 +5,26 @@ metadata:
creationTimestamp: null
name: mutating-webhook-configuration
webhooks:
+- admissionReviewVersions:
+ - v1
+ clientConfig:
+ service:
+ name: webhook-service
+ namespace: system
+ path: /mutate-tempo-grafana-com-v1alpha1-tempomonolithic
+ failurePolicy: Fail
+ name: mtempomonolithic.kb.io
+ rules:
+ - apiGroups:
+ - tempo.grafana.com
+ apiVersions:
+ - v1alpha1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - tempomonolithics
+ sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
@@ -32,6 +52,26 @@ metadata:
creationTimestamp: null
name: validating-webhook-configuration
webhooks:
+- admissionReviewVersions:
+ - v1
+ clientConfig:
+ service:
+ name: webhook-service
+ namespace: system
+ path: /validate-tempo-grafana-com-v1alpha1-tempomonolithic
+ failurePolicy: Fail
+ name: vtempomonolithic.kb.io
+ rules:
+ - apiGroups:
+ - tempo.grafana.com
+ apiVersions:
+ - v1alpha1
+ operations:
+ - CREATE
+ - UPDATE
+ resources:
+ - tempomonolithics
+ sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
diff --git a/controllers/tempo/common.go b/controllers/tempo/common.go
new file mode 100644
index 000000000..d0ce86fa8
--- /dev/null
+++ b/controllers/tempo/common.go
@@ -0,0 +1,68 @@
+package controllers
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "github.com/go-logr/logr"
+ rbacv1 "k8s.io/api/rbac/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ "github.com/grafana/tempo-operator/internal/manifests"
+)
+
+func isNamespaceScoped(obj client.Object) bool {
+ switch obj.(type) {
+ case *rbacv1.ClusterRole, *rbacv1.ClusterRoleBinding:
+ return false
+ default:
+ return true
+ }
+}
+
+// reconcileManagedObjects creates or updates all managed objects.
+// If immutable fields are changed, the object will be deleted and re-created.
+func reconcileManagedObjects(ctx context.Context, log logr.Logger, k8sclient client.Client, owner metav1.Object, scheme *runtime.Scheme, managedObjects []client.Object) error {
+ errs := []error{}
+ for _, obj := range managedObjects {
+ l := log.WithValues(
+ "objectName", obj.GetName(),
+ "objectKind", obj.GetObjectKind().GroupVersionKind(),
+ )
+
+ if isNamespaceScoped(obj) {
+ if err := ctrl.SetControllerReference(owner, obj, scheme); err != nil {
+ l.Error(err, "failed to set controller owner reference to resource")
+ errs = append(errs, err)
+ continue
+ }
+ }
+
+ desired := obj.DeepCopyObject().(client.Object)
+ mutateFn := manifests.MutateFuncFor(obj, desired)
+
+ op, err := ctrl.CreateOrUpdate(ctx, k8sclient, obj, mutateFn)
+
+ var immutableErr *manifests.ImmutableErr
+ if err != nil && errors.As(err, &immutableErr) {
+ l.Error(err, "detected a change in an immutable field. The object will be deleted, and re-created on next reconcile", "obj", obj.GetName())
+ err = k8sclient.Delete(ctx, desired)
+ }
+ if err != nil {
+ l.Error(err, "failed to configure resource")
+ errs = append(errs, err)
+ continue
+ }
+
+ l.V(1).Info(fmt.Sprintf("resource has been %s", op))
+ }
+
+ if len(errs) > 0 {
+ return fmt.Errorf("failed to create objects for %s: %w", owner.GetName(), errors.Join(errs...))
+ }
+ return nil
+}
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
new file mode 100644
index 000000000..dde031b05
--- /dev/null
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -0,0 +1,78 @@
+package controllers
+
+import (
+ "context"
+ "fmt"
+
+ appsv1 "k8s.io/api/apps/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/grafana/tempo-operator/internal/manifests/monolithic"
+)
+
+// TempoMonolithicReconciler reconciles a TempoMonolithic object.
+type TempoMonolithicReconciler struct {
+ client.Client
+ Scheme *runtime.Scheme
+ CtrlConfig configv1alpha1.ProjectConfig
+}
+
+//+kubebuilder:rbac:groups=tempo.grafana.com,resources=tempomonolithics,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=tempo.grafana.com,resources=tempomonolithics/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=tempo.grafana.com,resources=tempomonolithics/finalizers,verbs=update
+
+// Reconcile is part of the main kubernetes reconciliation loop which aims to
+// move the current state of the cluster closer to the desired state.
+func (r *TempoMonolithicReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ log := log.FromContext(ctx).WithName("tempomonolithic-reconcile")
+
+ log.V(1).Info("starting reconcile loop")
+ defer log.V(1).Info("finished reconcile loop")
+
+ tempo := v1alpha1.TempoMonolithic{}
+ if err := r.Get(ctx, req.NamespacedName, &tempo); err != nil {
+ if !apierrors.IsNotFound(err) {
+ log.Error(err, "unable to fetch TempoMonolithic")
+ return ctrl.Result{}, fmt.Errorf("could not fetch tempo: %w", err)
+ }
+
+ // we'll ignore not-found errors, since they can't be fixed by an immediate
+ // requeue (we'll need to wait for a new notification), and we can get them
+ // on deleted requests.
+ return ctrl.Result{}, nil
+ }
+
+ if tempo.Spec.Management == v1alpha1.ManagementStateUnmanaged {
+ log.Info("Skipping reconciliation for unmanaged TempoMonolithic resource", "name", req.String())
+ return ctrl.Result{}, nil
+ }
+
+ managedObjects, err := monolithic.BuildAll(monolithic.Options{
+ CtrlConfig: r.CtrlConfig,
+ Tempo: tempo,
+ })
+ if err != nil {
+ return ctrl.Result{}, fmt.Errorf("error building manifests: %w", err)
+ }
+
+ err = reconcileManagedObjects(ctx, log, r.Client, &tempo, r.Scheme, managedObjects)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ return ctrl.Result{}, nil
+}
+
+// SetupWithManager sets up the controller with the Manager.
+func (r *TempoMonolithicReconciler) SetupWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewControllerManagedBy(mgr).
+ For(&v1alpha1.TempoMonolithic{}).
+ Owns(&appsv1.StatefulSet{}).
+ Complete(r)
+}
diff --git a/controllers/tempo/tempostack_controller.go b/controllers/tempo/tempostack_controller.go
index 3c3dd53df..4a2bb396f 100644
--- a/controllers/tempo/tempostack_controller.go
+++ b/controllers/tempo/tempostack_controller.go
@@ -72,7 +72,7 @@ func (r *TempoStackReconciler) Reconcile(ctx context.Context, req ctrl.Request)
tempo := v1alpha1.TempoStack{}
if err := r.Get(ctx, req.NamespacedName, &tempo); err != nil {
if !apierrors.IsNotFound(err) {
- log.Error(err, "unable to fetch TempoTempoStack")
+ log.Error(err, "unable to fetch TempoStack")
return ctrl.Result{}, fmt.Errorf("could not fetch tempo: %w", err)
}
diff --git a/controllers/tempo/tempostack_create_or_update.go b/controllers/tempo/tempostack_create_or_update.go
index 8b4799786..0d9ebdece 100644
--- a/controllers/tempo/tempostack_create_or_update.go
+++ b/controllers/tempo/tempostack_create_or_update.go
@@ -12,7 +12,6 @@ import (
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
- rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -75,15 +74,6 @@ func (r *TempoStackReconciler) getStorageConfig(ctx context.Context, tempo v1alp
return params, nil
}
-func isNamespaceScoped(obj client.Object) bool {
- switch obj.(type) {
- case *rbacv1.ClusterRole, *rbacv1.ClusterRoleBinding:
- return false
- default:
- return true
- }
-}
-
func (r *TempoStackReconciler) createOrUpdate(ctx context.Context, log logr.Logger, req ctrl.Request, tempo v1alpha1.TempoStack) error {
storageConfig, err := r.getStorageConfig(ctx, tempo)
if err != nil {
diff --git a/docs/operator/api.md b/docs/operator/api.md
index 89151191c..cab1608b2 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -1331,7 +1331,7 @@ RateLimitSpec
-(Appears on:TempoStackSpec)
+(Appears on:TempoMonolithicSpec, TempoStackSpec)
@@ -1550,17 +1550,17 @@ using an in-process OpenPolicyAgent Rego authorizer.
-## OIDCSpec { #tempo-grafana-com-v1alpha1-OIDCSpec }
+## MonolithicExtraConfigSpec { #tempo-grafana-com-v1alpha1-MonolithicExtraConfigSpec }
-(Appears on:AuthenticationSpec)
+(Appears on:TempoMonolithicSpec)
-
OIDCSpec defines the oidc configuration spec for Tempo Gateway component.
+
MonolithicExtraConfigSpec defines extra configuration for this deployment.
@@ -1584,13 +1584,13 @@ using an in-process OpenPolicyAgent Rego authorizer.
-secret
+tempo
-
+
-TenantSecretSpec
+k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON
@@ -1600,45 +1600,53 @@ TenantSecretSpec
-(Optional)
-
- Secret defines the spec for the clientID, clientSecret and issuerCAPath for tenant’s authentication.
+Tempo defines any extra Tempo configuration, which will be merged with the operator’s generated Tempo configuration
|
-
+
+
-
+## MonolithicIngestionOTLPProtocolsGRPCSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionOTLPProtocolsGRPCSpec }
-issuerURL
+
-
+(Appears on:MonolithicIngestionOTLPSpec)
-string
+
-
+
- |
+MonolithicIngestionOTLPProtocolsGRPCSpec defines the settings for OTLP ingestion over GRPC.
+
+
-
+
-(Optional)
+
-IssuerURL defines the URL for issuer.
+
+
+Field |
+
+Description |
-
+
+
+
+
-redirectURL
+enabled
-string
+bool
@@ -1646,45 +1654,53 @@ string
|
-(Optional)
-
- RedirectURL defines the URL for redirect.
+Enabled defines if OTLP over gRPC is enabled
|
-
+
+
- |
+## MonolithicIngestionOTLPProtocolsHTTPSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionOTLPProtocolsHTTPSpec }
-groupClaim
+
-
+(Appears on:MonolithicIngestionOTLPSpec)
-string
+
-
+
- |
+MonolithicIngestionOTLPProtocolsHTTPSpec defines the settings for OTLP ingestion over HTTP.
+
+
-
+
-(Optional)
+
-Group claim field from ID Token
+
+
+Field |
+
+Description |
-
+
+
+
+
-usernameClaim
+enabled
-string
+bool
@@ -1692,9 +1708,7 @@ string
|
-(Optional)
-
- User claim field from ID Token
+Enabled defines if OTLP over HTTP is enabled
|
@@ -1702,17 +1716,17 @@ string
-## ObjectStorageSecretSpec { #tempo-grafana-com-v1alpha1-ObjectStorageSecretSpec }
+## MonolithicIngestionOTLPSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionOTLPSpec }
-(Appears on:ObjectStorageSpec)
+(Appears on:MonolithicIngestionSpec)
- ObjectStorageSecretSpec is a secret reference containing name only, no namespace.
+ MonolithicIngestionOTLPSpec defines the settings for OTLP ingestion.
@@ -1736,13 +1750,13 @@ string
|
-type
+grpc
-
+
-ObjectStorageSecretType
+MonolithicIngestionOTLPProtocolsGRPCSpec
@@ -1752,7 +1766,7 @@ ObjectStorageSecretType
- Type of object storage that should be used
+GRPC defines the OTLP/gRPC configuration
|
|
@@ -1761,11 +1775,15 @@ ObjectStorageSecretType
-name
+http
-string
+
+
+MonolithicIngestionOTLPProtocolsHTTPSpec
+
+
@@ -1773,7 +1791,7 @@ string
|
- Name of a secret in the namespace configured for object storage secrets.
+HTTP defines the OTLP/HTTP configuration
|
@@ -1781,19 +1799,17 @@ string
-## ObjectStorageSecretType { #tempo-grafana-com-v1alpha1-ObjectStorageSecretType }
-
-(string alias)
+## MonolithicIngestionSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionSpec }
-(Appears on:ObjectStorageSecretSpec)
+(Appears on:TempoMonolithicSpec)
- ObjectStorageSecretType defines the type of storage which can be used with the Tempo cluster.
+ MonolithicIngestionSpec defines the ingestion settings.
@@ -1803,7 +1819,7 @@ string
-Value |
+Field |
Description |
@@ -1811,36 +1827,72 @@ string
- "azure" |
+
+
+
+
+
+
+otlp
+
+
+
+
+
+MonolithicIngestionOTLPSpec
+
+
+
+
- | ObjectStorageSecretAzure when using Azure Storage for Tempo storage.
|
- "gcs" |
+
+
+ OTLP defines the ingestion configuration for OTLP
- | ObjectStorageSecretGCS when using Google Cloud Storage for Tempo storage.
|
+
-"s3" |
+
+
+
+
+tls
+
+
+
+
+
+MonolithicIngestionTLSSpec
+
+
+
+
- | ObjectStorageSecretS3 when using S3 for Tempo storage.
|
-
+
+
+ TLS defines the TLS configuration for ingestion
+
+ |
+
+
+
-## ObjectStorageSpec { #tempo-grafana-com-v1alpha1-ObjectStorageSpec }
+## MonolithicIngestionTLSSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionTLSSpec }
-(Appears on:TempoStackSpec)
+(Appears on:MonolithicIngestionSpec)
- ObjectStorageSpec defines the requirements to access the object
-storage bucket to persist traces by the ingester component.
+ MonolithicIngestionTLSSpec defines the TLS settings for ingestion.
@@ -1864,15 +1916,11 @@ storage bucket to persist traces by the ingester component.
-tls
+enabled
-
-
-ObjectStorageTLSSpec
-
-
+bool
@@ -1880,9 +1928,7 @@ ObjectStorageTLSSpec
|
-(Optional)
-
- TLS configuration for reaching the object storage endpoint.
+Enabled defines if TLS is enabled for ingestion
|
@@ -1891,15 +1937,32 @@ ObjectStorageTLSSpec
-secret
+ca
-
+string
-ObjectStorageSecretSpec
+
-
+ |
+
+
+
+ CA defines the name of a secret containing the CA certificate
+
+ |
+
+
+
+
+
+
+cert
+
+
+
+string
@@ -1907,8 +1970,7 @@ ObjectStorageSecretSpec
|
- Secret for object storage authentication.
-Name of a secret in the same namespace as the TempoStack custom resource.
+Cert defines the name of a secret containing the TLS certificate and private key
|
@@ -1916,17 +1978,17 @@ Name of a secret in the same namespace as the TempoStack custom resource.
-## ObjectStorageTLSSpec { #tempo-grafana-com-v1alpha1-ObjectStorageTLSSpec }
+## MonolithicJaegerUIIngressSpec { #tempo-grafana-com-v1alpha1-MonolithicJaegerUIIngressSpec }
-(Appears on:ObjectStorageSpec)
+(Appears on:MonolithicJaegerUISpec)
- ObjectStorageTLSSpec is the TLS configuration for reaching the object storage endpoint.
+ MonolithicJaegerUIIngressSpec defines the settings for the Jaeger UI ingress.
@@ -1950,11 +2012,11 @@ Name of a secret in the same namespace as the TempoStack custom resource.
-caName
+enabled
-string
+bool
@@ -1962,10 +2024,7 @@ string
|
-(Optional)
-
- CA is the name of a ConfigMap containing a ca.crt key with a CA certificate.
-It needs to be in the same namespace as the TempoStack custom resource.
+Enabled defines if an Ingress object should be created for Jaeger UI
|
@@ -1973,17 +2032,17 @@ It needs to be in the same namespace as the TempoStack custom resource.
-## ObservabilitySpec { #tempo-grafana-com-v1alpha1-ObservabilitySpec }
+## MonolithicJaegerUIRouteSpec { #tempo-grafana-com-v1alpha1-MonolithicJaegerUIRouteSpec }
-(Appears on:TempoStackSpec)
+(Appears on:MonolithicJaegerUISpec)
- ObservabilitySpec defines how telemetry data gets handled.
+ MonolithicJaegerUIRouteSpec defines the settings for the Jaeger UI route.
@@ -2007,15 +2066,11 @@ It needs to be in the same namespace as the TempoStack custom resource.
-metrics
+enabled
-
-
-MetricsConfigSpec
-
-
+bool
@@ -2023,26 +2078,53 @@ MetricsConfigSpec
|
-(Optional)
-
- Metrics defines the metrics configuration for operands.
+Enabled defines if a Route object should be created for Jaeger UI
|
+
+
+
+## MonolithicJaegerUISpec { #tempo-grafana-com-v1alpha1-MonolithicJaegerUISpec }
+
+
+
+(Appears on:TempoMonolithicSpec)
+
+
+
+
+
+ MonolithicJaegerUISpec defines the settings for the Jaeger UI.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
-tracing
+enabled
-
-
-TracingConfigSpec
-
-
+bool
@@ -2050,9 +2132,7 @@ TracingConfigSpec
|
-(Optional)
-
- Tracing defines a config for operands.
+Enabled defines if the Jaeger UI should be enabled
|
@@ -2061,13 +2141,13 @@ TracingConfigSpec
-grafana
+ingress
-
+
-GrafanaConfigSpec
+MonolithicJaegerUIIngressSpec
@@ -2077,86 +2157,50 @@ GrafanaConfigSpec
-(Optional)
-
- Grafana defines the Grafana configuration for operands.
+Ingress defines the ingress configuration for Jaeger UI
|
- |
-
-
-## PermissionType { #tempo-grafana-com-v1alpha1-PermissionType }
-
-(string alias)
-
-
-
-(Appears on:RoleSpec)
-
-
-
-
-
- PermissionType is a Tempo Gateway RBAC permission.
-
-
-
-
-
-## PodStatusMap { #tempo-grafana-com-v1alpha1-PodStatusMap }
-
-(map[k8s.io/api/core/v1.PodPhase][]string alias)
-
-
-
-(Appears on:ComponentStatus)
+
-
+ Route defines the route configuration for Jaeger UI
-
+ |
+
-PodStatusMap defines the type for mapping pod status to pod name.
-
-
+
+
-## QueryLimit { #tempo-grafana-com-v1alpha1-QueryLimit }
+## MonolithicObservabilityMetricsPrometheusRulesSpec { #tempo-grafana-com-v1alpha1-MonolithicObservabilityMetricsPrometheusRulesSpec }
-(Appears on:RateLimitSpec)
+(Appears on:MonolithicObservabilityMetricsSpec)
- QueryLimit defines query limits.
+ MonolithicObservabilityMetricsPrometheusRulesSpec defines the PrometheusRules settings.
@@ -2180,11 +2224,11 @@ GrafanaConfigSpec
-maxBytesPerTagValues
+enabled
-int
+bool
@@ -2192,51 +2236,53 @@ int
|
-(Optional)
-
- MaxBytesPerTagValues defines the maximum size in bytes of a tag-values query.
+Enabled defines if the operator should create PrometheusRules for this Tempo deployment
|
-
+
+
-
+## MonolithicObservabilityMetricsServiceMonitorsSpec { #tempo-grafana-com-v1alpha1-MonolithicObservabilityMetricsServiceMonitorsSpec }
-maxSearchBytesPerTrace
+
-
+(Appears on:MonolithicObservabilityMetricsSpec)
-int
+
-
+
- |
+MonolithicObservabilityMetricsServiceMonitorsSpec defines the ServiceMonitor settings.
+
+
-
+
-(Optional)
+
-DEPRECATED. MaxSearchBytesPerTrace defines the maximum size of search data for a single
-trace in bytes.
-default: 0 to disable.
+
+
+Field |
+
+Description |
-
+
+
+
+
-maxSearchDuration
+enabled
-
-
-Kubernetes meta/v1.Duration
-
-
+bool
@@ -2244,10 +2290,7 @@ Kubernetes meta/v1.Duration
|
-(Optional)
-
- MaxSearchDuration defines the maximum allowed time range for a search.
-If this value is not set, then spec.search.maxDuration is used.
+Enabled defines if the operator should create ServiceMonitors for this Tempo deployment
|
@@ -2255,17 +2298,17 @@ If this value is not set, then spec.search.maxDuration is used.
-## RateLimitSpec { #tempo-grafana-com-v1alpha1-RateLimitSpec }
+## MonolithicObservabilityMetricsSpec { #tempo-grafana-com-v1alpha1-MonolithicObservabilityMetricsSpec }
-(Appears on:LimitSpec)
+(Appears on:MonolithicObservabilitySpec)
- RateLimitSpec defines rate limits for Ingestion and Query components.
+ MonolithicObservabilityMetricsSpec defines the metrics settings of the Tempo deployment.
@@ -2289,13 +2332,13 @@ If this value is not set, then spec.search.maxDuration is used.
|
-ingestion
+serviceMonitors
-
+
-IngestionLimitSpec
+MonolithicObservabilityMetricsServiceMonitorsSpec
@@ -2305,9 +2348,7 @@ IngestionLimitSpec
-(Optional)
-
- Ingestion is used to define ingestion rate limits.
+ServiceMonitors defines the ServiceMonitor configuration
|
|
@@ -2316,13 +2357,13 @@ IngestionLimitSpec
-query
+prometheusRules
-
+
-QueryLimit
+MonolithicObservabilityMetricsPrometheusRulesSpec
@@ -2332,9 +2373,7 @@ QueryLimit
-(Optional)
-
- Query is used to define query rate limits.
+ServiceMonitors defines the PrometheusRule configuration
|
@@ -2342,17 +2381,17 @@ QueryLimit
-## ReceiversTLSSpec { #tempo-grafana-com-v1alpha1-ReceiversTLSSpec }
+## MonolithicObservabilitySpec { #tempo-grafana-com-v1alpha1-MonolithicObservabilitySpec }
-(Appears on:TempoDistributorSpec)
+(Appears on:TempoMonolithicSpec)
- ReceiversTLSSpec is the TLS configuration for the receivers.
+ MonolithicObservabilitySpec defines the observability settings of the Tempo deployment.
@@ -2376,11 +2415,15 @@ QueryLimit
-enabled
+metrics
-bool
+
+
+MonolithicObservabilityMetricsSpec
+
+
@@ -2388,62 +2431,57 @@ bool
|
+ Metrics defines the metrics configuration of the Tempo deployment
+
|
-
-
-
+
+
-caName
+## MonolithicStorageSpec { #tempo-grafana-com-v1alpha1-MonolithicStorageSpec }
-
+
-string
+(Appears on:TempoMonolithicSpec)
-
+
- |
+
-
+ MonolithicStorageSpec defines the storage for the Tempo deployment.
+
+
-caName is the name of a ConfigMap containing a CA certificate.
-It needs to be in the same namespace as the Tempo custom resource.
+
-
-
+
-
-
-certName
-
-
-
-string
-
-
+ | Field |
-
+Description |
-
+ |
-certName is the name of a Secret containing a certificate and the private key
-It needs to be in the same namespace as the Tempo custom resource.
+
-
-
+
-minVersion
+traces
-string
+
+
+MonolithicTracesStorageSpec
+
+
@@ -2451,10 +2489,7 @@ string
|
-(Optional)
-
- minVersion is the name of a Secret containing a certificate and the private key
-It needs to be in the same namespace as the Tempo custom resource.
+Traces defines the backend storage configuration for traces
|
@@ -2462,17 +2497,19 @@ It needs to be in the same namespace as the Tempo custom resource.
-## Resources { #tempo-grafana-com-v1alpha1-Resources }
+## MonolithicTracesStorageBackend { #tempo-grafana-com-v1alpha1-MonolithicTracesStorageBackend }
+
+(string alias)
-(Appears on:TempoStackSpec)
+(Appears on:MonolithicTracesStorageSpec)
- Resources defines resources configuration.
+ MonolithicTracesStorageBackend defines the backend storage for traces.
@@ -2482,7 +2519,7 @@ It needs to be in the same namespace as the Tempo custom resource.
|
-Field |
+Value |
Description |
@@ -2490,52 +2527,30 @@ It needs to be in the same namespace as the Tempo custom resource.
-
-
-
-
-
-
-total
-
-
-
-
-
-Kubernetes core/v1.ResourceRequirements
-
-
-
-
+ | "memory" |
+MonolithicTracesStorageBackendMemory specifies a in-memory storage backend.
|
-
-
-(Optional)
-
- The total amount of resources for Tempo instance.
-The operator autonomously splits resources between deployed Tempo components.
-Only limits are supported, the operator calculates requests automatically.
-See http://github.com/grafana/tempo/issues/1540.
+ | "pv" |
+MonolithicTracesStorageBackendPersistentVolume specifies a Persistent Volume storage backend.
|
-
-
+
-## RetentionConfig { #tempo-grafana-com-v1alpha1-RetentionConfig }
+## MonolithicTracesStoragePersistentVolumeSpec { #tempo-grafana-com-v1alpha1-MonolithicTracesStoragePersistentVolumeSpec }
-(Appears on:RetentionSpec)
+(Appears on:MonolithicTracesStorageSpec)
- RetentionConfig defines how long data should be provided.
+ MonolithicTracesStoragePersistentVolumeSpec defines the Persistent Volume configuration.
@@ -2559,15 +2574,11 @@ See http://github.com/graf
-traces
+size
-
-
-Kubernetes meta/v1.Duration
-
-
+k8s.io/apimachinery/pkg/api/resource.Quantity
@@ -2575,11 +2586,7 @@ Kubernetes meta/v1.Duration
|
-(Optional)
-
- Traces defines retention period. Supported parameter suffixes are “s”, “m” and “h”.
-example: 336h
-default: value is 48h.
+Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
|
@@ -2587,17 +2594,17 @@ default: value is 48h.
-## RetentionSpec { #tempo-grafana-com-v1alpha1-RetentionSpec }
+## MonolithicTracesStorageSpec { #tempo-grafana-com-v1alpha1-MonolithicTracesStorageSpec }
-(Appears on:TempoStackSpec)
+(Appears on:MonolithicStorageSpec)
- RetentionSpec defines global and per tenant retention configurations.
+ MonolithicTracesStorageSpec defines the traces storage for the Tempo deployment.
@@ -2621,13 +2628,13 @@ default: value is 48h.
-perTenant
+backend
-
+
-map[string]github.com/grafana/tempo-operator/apis/tempo/v1alpha1.RetentionConfig
+MonolithicTracesStorageBackend
@@ -2637,9 +2644,7 @@ map[string]github.com/grafana/tempo-operator/apis/tempo/v1alpha1.RetentionConfig
-(Optional)
-
- PerTenant is used to configure retention per tenant.
+Backend defines the backend for storing traces
|
@@ -2648,13 +2653,13 @@ map[string]github.com/grafana/tempo-operator/apis/tempo/v1alpha1.RetentionConfig
-global
+wal
-
+
-RetentionConfig
+MonolithicTracesStorageWALSpec
@@ -2664,27 +2669,1435 @@ RetentionConfig
-(Optional)
-
- Global is used to configure global retention.
+WAL defines the write-ahead logging (WAL) configuration
|
-
-
+
+
+
+
+pv
+
+
+
+
+
+MonolithicTracesStoragePersistentVolumeSpec
+
+
+
+
+
+ |
+
+
+
+ PV defines the Persistent Volume configuration
+
+ |
+
+
+
+
+
+## MonolithicTracesStorageWALSpec { #tempo-grafana-com-v1alpha1-MonolithicTracesStorageWALSpec }
+
+
+
+(Appears on:MonolithicTracesStorageSpec)
+
+
+
+
+
+ MonolithicTracesStorageWALSpec defines the write-ahead logging (WAL) configuration.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+size
+
+
+
+k8s.io/apimachinery/pkg/api/resource.Quantity
+
+
+
+ |
+
+
+
+ Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
+
+ |
+
+
+
+
+
+## OIDCSpec { #tempo-grafana-com-v1alpha1-OIDCSpec }
+
+
+
+(Appears on:AuthenticationSpec)
+
+
+
+
+
+ OIDCSpec defines the oidc configuration spec for Tempo Gateway component.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+secret
+
+
+
+
+
+TenantSecretSpec
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Secret defines the spec for the clientID, clientSecret and issuerCAPath for tenant’s authentication.
+
+ |
+
+
+
+
+
+
+issuerURL
+
+
+
+string
+
+
+
+ |
+
+
+
+(Optional)
+
+ IssuerURL defines the URL for issuer.
+
+ |
+
+
+
+
+
+
+redirectURL
+
+
+
+string
+
+
+
+ |
+
+
+
+(Optional)
+
+ RedirectURL defines the URL for redirect.
+
+ |
+
+
+
+
+
+
+groupClaim
+
+
+
+string
+
+
+
+ |
+
+
+
+(Optional)
+
+ Group claim field from ID Token
+
+ |
+
+
+
+
+
+
+usernameClaim
+
+
+
+string
+
+
+
+ |
+
+
+
+(Optional)
+
+ User claim field from ID Token
+
+ |
+
+
+
+
+
+## ObjectStorageSecretSpec { #tempo-grafana-com-v1alpha1-ObjectStorageSecretSpec }
+
+
+
+(Appears on:ObjectStorageSpec)
+
+
+
+
+
+ ObjectStorageSecretSpec is a secret reference containing name only, no namespace.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+type
+
+
+
+
+
+ObjectStorageSecretType
+
+
+
+
+
+ |
+
+
+
+ Type of object storage that should be used
+
+ |
+
+
+
+
+
+
+name
+
+
+
+string
+
+
+
+ |
+
+
+
+ Name of a secret in the namespace configured for object storage secrets.
+
+ |
+
+
+
+
+
+## ObjectStorageSecretType { #tempo-grafana-com-v1alpha1-ObjectStorageSecretType }
+
+(string alias)
+
+
+
+(Appears on:ObjectStorageSecretSpec)
+
+
+
+
+
+ ObjectStorageSecretType defines the type of storage which can be used with the Tempo cluster.
+
+
+
+
+
+
+
+
+
+Value |
+
+Description |
+
+
+
+
+
+"azure" |
+
+ObjectStorageSecretAzure when using Azure Storage for Tempo storage.
+ |
+
+ "gcs" |
+
+ObjectStorageSecretGCS when using Google Cloud Storage for Tempo storage.
+ |
+
+ "s3" |
+
+ObjectStorageSecretS3 when using S3 for Tempo storage.
+ |
+
+
+
+
+## ObjectStorageSpec { #tempo-grafana-com-v1alpha1-ObjectStorageSpec }
+
+
+
+(Appears on:TempoStackSpec)
+
+
+
+
+
+ ObjectStorageSpec defines the requirements to access the object
+storage bucket to persist traces by the ingester component.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+tls
+
+
+
+
+
+ObjectStorageTLSSpec
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ TLS configuration for reaching the object storage endpoint.
+
+ |
+
+
+
+
+
+
+secret
+
+
+
+
+
+ObjectStorageSecretSpec
+
+
+
+
+
+ |
+
+
+
+ Secret for object storage authentication.
+Name of a secret in the same namespace as the TempoStack custom resource.
+
+ |
+
+
+
+
+
+## ObjectStorageTLSSpec { #tempo-grafana-com-v1alpha1-ObjectStorageTLSSpec }
+
+
+
+(Appears on:ObjectStorageSpec)
+
+
+
+
+
+ ObjectStorageTLSSpec is the TLS configuration for reaching the object storage endpoint.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+caName
+
+
+
+string
+
+
+
+ |
+
+
+
+(Optional)
+
+ CA is the name of a ConfigMap containing a ca.crt key with a CA certificate.
+It needs to be in the same namespace as the TempoStack custom resource.
+
+ |
+
+
+
+
+
+## ObservabilitySpec { #tempo-grafana-com-v1alpha1-ObservabilitySpec }
+
+
+
+(Appears on:TempoStackSpec)
+
+
+
+
+
+ ObservabilitySpec defines how telemetry data gets handled.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+metrics
+
+
+
+
+
+MetricsConfigSpec
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Metrics defines the metrics configuration for operands.
+
+ |
+
+
+
+
+
+
+tracing
+
+
+
+
+
+TracingConfigSpec
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Tracing defines a config for operands.
+
+ |
+
+
+
+
+
+
+grafana
+
+
+
+
+
+GrafanaConfigSpec
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Grafana defines the Grafana configuration for operands.
+
+ |
+
+
+
+
+
+## PermissionType { #tempo-grafana-com-v1alpha1-PermissionType }
+
+(string alias)
+
+
+
+(Appears on:RoleSpec)
+
+
+
+
+
+ PermissionType is a Tempo Gateway RBAC permission.
+
+
+
+
+
+
+
+
+
+Value |
+
+Description |
+
+
+
+
+
+"read" |
+
+Read gives access to read data from a tenant.
+ |
+
+ "write" |
+
+Write gives access to write data to a tenant.
+ |
+
+
+
+
+## PodStatusMap { #tempo-grafana-com-v1alpha1-PodStatusMap }
+
+(map[k8s.io/api/core/v1.PodPhase][]string alias)
+
+
+
+(Appears on:ComponentStatus)
+
+
+
+
+
+ PodStatusMap defines the type for mapping pod status to pod name.
+
+
+
+## QueryLimit { #tempo-grafana-com-v1alpha1-QueryLimit }
+
+
+
+(Appears on:RateLimitSpec)
+
+
+
+
+
+ QueryLimit defines query limits.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+maxBytesPerTagValues
+
+
+
+int
+
+
+
+ |
+
+
+
+(Optional)
+
+ MaxBytesPerTagValues defines the maximum size in bytes of a tag-values query.
+
+ |
+
+
+
+
+
+
+maxSearchBytesPerTrace
+
+
+
+int
+
+
+
+ |
+
+
+
+(Optional)
+
+ DEPRECATED. MaxSearchBytesPerTrace defines the maximum size of search data for a single
+trace in bytes.
+default: 0 to disable.
+
+ |
+
+
+
+
+
+
+maxSearchDuration
+
+
+
+
+
+Kubernetes meta/v1.Duration
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ MaxSearchDuration defines the maximum allowed time range for a search.
+If this value is not set, then spec.search.maxDuration is used.
+
+ |
+
+
+
+
+
+## RateLimitSpec { #tempo-grafana-com-v1alpha1-RateLimitSpec }
+
+
+
+(Appears on:LimitSpec)
+
+
+
+
+
+ RateLimitSpec defines rate limits for Ingestion and Query components.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+ingestion
+
+
+
+
+
+IngestionLimitSpec
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Ingestion is used to define ingestion rate limits.
+
+ |
+
+
+
+
+
+
+query
+
+
+
+
+
+QueryLimit
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Query is used to define query rate limits.
+
+ |
+
+
+
+
+
+## ReceiversTLSSpec { #tempo-grafana-com-v1alpha1-ReceiversTLSSpec }
+
+
+
+(Appears on:TempoDistributorSpec)
+
+
+
+
+
+ ReceiversTLSSpec is the TLS configuration for the receivers.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+enabled
+
+
+
+bool
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+caName
+
+
+
+string
+
+
+
+ |
+
+
+
+ caName is the name of a ConfigMap containing a CA certificate.
+It needs to be in the same namespace as the Tempo custom resource.
+
+ |
+
+
+
+
+
+
+certName
+
+
+
+string
+
+
+
+ |
+
+
+
+ certName is the name of a Secret containing a certificate and the private key
+It needs to be in the same namespace as the Tempo custom resource.
+
+ |
+
+
+
+
+
+
+minVersion
+
+
+
+string
+
+
+
+ |
+
+
+
+(Optional)
+
+ minVersion is the name of a Secret containing a certificate and the private key
+It needs to be in the same namespace as the Tempo custom resource.
+
+ |
+
+
+
+
+
+## Resources { #tempo-grafana-com-v1alpha1-Resources }
+
+
+
+(Appears on:TempoStackSpec)
+
+
+
+
+
+ Resources defines resources configuration.
+
+
+
+
+
+## RetentionConfig { #tempo-grafana-com-v1alpha1-RetentionConfig }
+
+
+
+(Appears on:RetentionSpec)
+
+
+
+
+
+ RetentionConfig defines how long data should be provided.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+traces
+
+
+
+
+
+Kubernetes meta/v1.Duration
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Traces defines retention period. Supported parameter suffixes are “s”, “m” and “h”.
+example: 336h
+default: value is 48h.
+
+ |
+
+
+
+
+
+## RetentionSpec { #tempo-grafana-com-v1alpha1-RetentionSpec }
+
+
+
+(Appears on:TempoStackSpec)
+
+
+
+
+
+ RetentionSpec defines global and per tenant retention configurations.
+
+
+
+
+
+## RoleBindingsSpec { #tempo-grafana-com-v1alpha1-RoleBindingsSpec }
+
+
+
+(Appears on:AuthorizationSpec)
+
+
+
+
+
+ RoleBindingsSpec binds a set of roles to a set of subjects.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+name
+
+
+
+string
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+subjects
+
+
+
+
+
+[]Subject
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+roles
+
+
+
+[]string
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+## RoleSpec { #tempo-grafana-com-v1alpha1-RoleSpec }
+
+
+
+(Appears on:AuthorizationSpec)
+
+
+
+
+
+ RoleSpec describes a set of permissions to interact with a tenant.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+name
+
+
+
+string
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+resources
+
+
+
+[]string
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+tenants
+
+
+
+[]string
+
+
-## RoleBindingsSpec { #tempo-grafana-com-v1alpha1-RoleBindingsSpec }
+ |
+
+
+
+ |
+
+
+
+
+
+
+permissions
+
+
+
+
+
+[]PermissionType
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+## RouteSpec { #tempo-grafana-com-v1alpha1-RouteSpec }
-(Appears on:AuthorizationSpec)
+(Appears on:IngressSpec)
- RoleBindingsSpec binds a set of roles to a set of subjects.
+ RouteSpec defines OpenShift Route specific options.
@@ -2708,11 +4121,71 @@ RetentionConfig
-name
+termination
-string
+
+
+TLSRouteTerminationType
+
+
+
+
+
+ |
+
+
+
+(Optional)
+
+ Termination specifies the termination type. By default “edge” is used.
+
+ |
+
+
+
+
+
+## SearchSpec { #tempo-grafana-com-v1alpha1-SearchSpec }
+
+
+
+(Appears on:TempoStackSpec)
+
+
+
+
+
+ SearchSpec specified the global search parameters.
+
+
+
+
+
+
+
+
+
+Field |
+
+Description |
+
+
+
+
+
+
+
+
+
+
+
+defaultResultLimit
+
+
+
+int
@@ -2720,6 +4193,10 @@ string
|
+(Optional)
+
+ Limit used for search requests if none is set by the caller (default: 20)
+
|
@@ -2727,13 +4204,13 @@ string
-subjects
+maxDuration
-
+
-[]Subject
+Kubernetes meta/v1.Duration
@@ -2743,6 +4220,10 @@ string
+(Optional)
+
+ The maximum allowed time range for a search, default: 0s which means unlimited.
+
|
@@ -2750,11 +4231,11 @@ string
-roles
+maxResultLimit
-[]string
+int
@@ -2762,23 +4243,29 @@ string
|
+(Optional)
+
+ The maximum allowed value of the limit parameter on search requests. If the search request limit parameter
+exceeds the value configured here it will be set to the value configured here.
+The default value of 0 disables this limit.
+
|
|
-## RoleSpec { #tempo-grafana-com-v1alpha1-RoleSpec }
+## Subject { #tempo-grafana-com-v1alpha1-Subject }
-(Appears on:AuthorizationSpec)
+(Appears on:RoleBindingsSpec)
- RoleSpec describes a set of permissions to interact with a tenant.
+ Subject represents a subject that has been bound to a role.
@@ -2821,11 +4308,15 @@ string
-resources
+kind
-[]string
+
+
+SubjectKind
+
+
@@ -2836,62 +4327,65 @@ string
|
-
-
-
+
+
-tenants
+## SubjectKind { #tempo-grafana-com-v1alpha1-SubjectKind }
-
+(string alias)
-[]string
+
-
+(Appears on:Subject)
- |
+
-
+
- |
-
+SubjectKind is a kind of Tempo Gateway RBAC subject.
+
+
-
+
-
+
-permissions
+
-
+Value |
-
+Description |
-[]PermissionType
+
-
+
-
+ | "group" |
+Group represents a subject that is a group.
|
-
+ | "user" |
+User represents a subject that is a user.
|
-
-
+
-## RouteSpec { #tempo-grafana-com-v1alpha1-RouteSpec }
+## TLSRouteTerminationType { #tempo-grafana-com-v1alpha1-TLSRouteTerminationType }
+
+(string alias)
-(Appears on:IngressSpec)
+(Appears on:RouteSpec)
- RouteSpec defines OpenShift Route specific options.
+ TLSRouteTerminationType is used to indicate which TLS settings should be used.
@@ -2901,7 +4395,7 @@ string
-Field |
+Value |
Description |
@@ -2909,49 +4403,51 @@ string
-
-
-
-
-
+ | "edge" |
-termination
+TLSRouteTerminationTypeEdge indicates that encryption should be terminated
+at the edge router.
+ |
-
+ "insecure" |
-
+TLSRouteTerminationTypeInsecure indicates that insecure connections are allowed.
+ |
-TLSRouteTerminationType
+ "passthrough" |
-
+TLSRouteTerminationTypePassthrough indicates that the destination service is
+responsible for decrypting traffic.
+ |
-
+ "reencrypt" |
+TLSRouteTerminationTypeReencrypt indicates that traffic will be decrypted on the edge
+and re-encrypt using a new certificate.
|
-
+ | "passthrough" |
-(Optional)
+ |
-Termination specifies the termination type. By default “edge” is used.
+ "edge" |
-
-
+ |
-
+
-## SearchSpec { #tempo-grafana-com-v1alpha1-SearchSpec }
+## TempoComponentSpec { #tempo-grafana-com-v1alpha1-TempoComponentSpec }
-(Appears on:TempoStackSpec)
+(Appears on:TempoDistributorSpec, TempoGatewaySpec, TempoQueryFrontendSpec, TempoTemplateSpec)
- SearchSpec specified the global search parameters.
+ TempoComponentSpec defines specific schedule settings for tempo components.
@@ -2975,11 +4471,11 @@ TLSRouteTerminationType
-defaultResultLimit
+replicas
-int
+int32
@@ -2989,7 +4485,7 @@ int
(Optional)
-Limit used for search requests if none is set by the caller (default: 20)
+Replicas represents the number of replicas to create for this component.
|
@@ -2998,15 +4494,11 @@ int
-maxDuration
+nodeSelector
-
-
-Kubernetes meta/v1.Duration
-
-
+map[string]string
@@ -3016,7 +4508,7 @@ Kubernetes meta/v1.Duration
(Optional)
-The maximum allowed time range for a search, default: 0s which means unlimited.
+NodeSelector is the simplest recommended form of node selection constraint.
|
@@ -3025,11 +4517,15 @@ Kubernetes meta/v1.Duration
-maxResultLimit
+tolerations
-int
+
+
+[]Kubernetes core/v1.Toleration
+
+
@@ -3039,9 +4535,7 @@ int
(Optional)
-The maximum allowed value of the limit parameter on search requests. If the search request limit parameter
-exceeds the value configured here it will be set to the value configured here.
-The default value of 0 disables this limit.
+Tolerations defines component specific pod tolerations.
|
@@ -3049,17 +4543,18 @@ The default value of 0 disables this limit.
-## Subject { #tempo-grafana-com-v1alpha1-Subject }
+## TempoDistributorSpec { #tempo-grafana-com-v1alpha1-TempoDistributorSpec }
-(Appears on:RoleBindingsSpec)
+(Appears on:TempoTemplateSpec)
- Subject represents a subject that has been bound to a role.
+ TempoDistributorSpec defines the template of all requirements to configure
+scheduling of Tempo distributor component to be deployed.
@@ -3083,11 +4578,15 @@ The default value of 0 disables this limit.
-name
+component
-string
+
+
+TempoComponentSpec
+
+
@@ -3095,6 +4594,13 @@ string
|
+(Optional)
+
+ TempoComponentSpec is embedded to extend this definition with further options.
+
+Currently, there is no way to inline this field.
+See: https://github.com/golang/go/issues/6213
+
|
@@ -3102,13 +4608,13 @@ string
-kind
+tls
-
+
-SubjectKind
+ReceiversTLSSpec
@@ -3118,25 +4624,27 @@ SubjectKind
+(Optional)
+
+ TLS defines TLS configuration for distributor receivers
+
|
-## SubjectKind { #tempo-grafana-com-v1alpha1-SubjectKind }
-
-(string alias)
+## TempoGatewaySpec { #tempo-grafana-com-v1alpha1-TempoGatewaySpec }
-(Appears on:Subject)
+(Appears on:TempoTemplateSpec)
- SubjectKind is a kind of Tempo Gateway RBAC subject.
+ TempoGatewaySpec extends TempoComponentSpec with gateway parameters.
@@ -3146,7 +4654,7 @@ SubjectKind
-Value |
+Field |
Description |
@@ -3154,94 +4662,92 @@ SubjectKind
- "group" |
+
-Group represents a subject that is a group.
- |
+
- "user" |
+
- | User represents a subject that is a user.
- |
+component
-
-
+
-## TLSRouteTerminationType { #tempo-grafana-com-v1alpha1-TLSRouteTerminationType }
+
-(string alias)
+TempoComponentSpec
-
+
-(Appears on:RouteSpec)
+
-
+ |
-
+
- TLSRouteTerminationType is used to indicate which TLS settings should be used.
-
-
+(Optional)
-
+TempoComponentSpec is embedded to extend this definition with further options.
+
+Currently there is no way to inline this field.
+See: https://github.com/golang/go/issues/6213
-
+
+
-Value |
+
- | Description |
+enabled
-
+
-
+bool
-"edge" |
+
-TLSRouteTerminationTypeEdge indicates that encryption should be terminated
-at the edge router.
|
- "insecure" |
+
- | TLSRouteTerminationTypeInsecure indicates that insecure connections are allowed.
|
+
-"passthrough" |
+
-TLSRouteTerminationTypePassthrough indicates that the destination service is
-responsible for decrypting traffic.
- |
+
- | "reencrypt" |
+ingress
-TLSRouteTerminationTypeReencrypt indicates that traffic will be decrypted on the edge
-and re-encrypt using a new certificate.
- |
+
- "passthrough" |
+
- |
+IngressSpec
- "edge" |
+
- |
+
-
-
+ |
-## TempoComponentSpec { #tempo-grafana-com-v1alpha1-TempoComponentSpec }
+
-
+(Optional)
-(Appears on:TempoDistributorSpec, TempoGatewaySpec, TempoQueryFrontendSpec, TempoTemplateSpec)
+ Ingress defines gateway Ingress options.
-
+ |
+
+
+
+
+
+## TempoMonolithic { #tempo-grafana-com-v1alpha1-TempoMonolithic }
- TempoComponentSpec defines specific schedule settings for tempo components.
+ TempoMonolithic is the Schema for the tempomonolithics API.
@@ -3265,11 +4771,15 @@ and re-encrypt using a new certificate.
-replicas
+metadata
-int32
+
+
+Kubernetes meta/v1.ObjectMeta
+
+
@@ -3277,9 +4787,9 @@ int32
|
-(Optional)
+Refer to the Kubernetes API documentation for the fields of the
- Replicas represents the number of replicas to create for this component.
+metadata field.
|
@@ -3288,11 +4798,15 @@ int32
-nodeSelector
+spec
-map[string]string
+
+
+TempoMonolithicSpec
+
+
@@ -3300,10 +4814,6 @@ map[string]string
|
-(Optional)
-
- NodeSelector is the simplest recommended form of node selection constraint.
-
|
@@ -3311,13 +4821,13 @@ map[string]string
-tolerations
+status
-
+
-[]Kubernetes core/v1.Toleration
+TempoMonolithicStatus
@@ -3327,28 +4837,23 @@ map[string]string
-(Optional)
-
- Tolerations defines component specific pod tolerations.
-
|
-## TempoDistributorSpec { #tempo-grafana-com-v1alpha1-TempoDistributorSpec }
+## TempoMonolithicSpec { #tempo-grafana-com-v1alpha1-TempoMonolithicSpec }
-(Appears on:TempoTemplateSpec)
+(Appears on:TempoMonolithic)
- TempoDistributorSpec defines the template of all requirements to configure
-scheduling of Tempo distributor component to be deployed.
+ TempoMonolithicSpec defines the desired state of TempoMonolithic.
@@ -3372,13 +4877,13 @@ scheduling of Tempo distributor component to be deployed.
-component
+storage
-
+
-TempoComponentSpec
+MonolithicStorageSpec
@@ -3388,12 +4893,7 @@ TempoComponentSpec
-(Optional)
-
- TempoComponentSpec is embedded to extend this definition with further options.
-
-Currently, there is no way to inline this field.
-See: https://github.com/golang/go/issues/6213
+Storage defines the backend storage configuration
|
@@ -3402,13 +4902,13 @@ See: https://github.com/golan
-tls
+ingestion
-
+
-ReceiversTLSSpec
+MonolithicIngestionSpec
@@ -3418,57 +4918,47 @@ ReceiversTLSSpec
-(Optional)
-
- TLS defines TLS configuration for distributor receivers
+Ingestion defines the trace ingestion configuration
|
-
-
-
-## TempoGatewaySpec { #tempo-grafana-com-v1alpha1-TempoGatewaySpec }
+
-
+
-(Appears on:TempoTemplateSpec)
+jaegerui
-
+
-
+MonolithicJaegerUISpec
-
+
-
+
-
+
-Field |
+
- | Description |
+JaegerUI defines the Jaeger UI configuration
+
-
-
-
-
-component
+management
-
+
-TempoComponentSpec
+ManagementStateType
@@ -3478,12 +4968,7 @@ TempoComponentSpec
-(Optional)
-
- TempoComponentSpec is embedded to extend this definition with further options.
-
-Currently there is no way to inline this field.
-See: https://github.com/golang/go/issues/6213
+ManagementState defines whether this instance is managed by the operator or self-managed
|
|
@@ -3492,11 +4977,15 @@ See: https://github.com/golan
-enabled
+observability
-bool
+
+
+MonolithicObservabilitySpec
+
+
@@ -3504,6 +4993,8 @@ bool
|
+ Observability defines observability configuration for the Tempo deployment
+
|
@@ -3511,13 +5002,13 @@ bool
-ingress
+extraConfig
-
+
-IngressSpec
+MonolithicExtraConfigSpec
@@ -3527,9 +5018,7 @@ IngressSpec
-(Optional)
-
- Ingress defines gateway Ingress options.
+ExtraConfig defines any extra (overlay) configuration for components
|
@@ -3537,6 +5026,20 @@ IngressSpec
|
+## TempoMonolithicStatus { #tempo-grafana-com-v1alpha1-TempoMonolithicStatus }
+
+
+
+(Appears on:TempoMonolithic)
+
+
+
+
+
+ TempoMonolithicStatus defines the observed state of TempoMonolithic.
+
+
+
## TempoQueryFrontendSpec { #tempo-grafana-com-v1alpha1-TempoQueryFrontendSpec }
diff --git a/docs/spec/tempomonolithic.yaml b/docs/spec/tempomonolithic.yaml
new file mode 100644
index 000000000..6a53a8c77
--- /dev/null
+++ b/docs/spec/tempomonolithic.yaml
@@ -0,0 +1,39 @@
+apiVersion: tempo.grafana.com/v1alpha1 # APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+kind: TempoMonolithic # Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+metadata:
+ name: example
+spec: # TempoMonolithicSpec defines the desired state of TempoMonolithic.
+ extraConfig: # ExtraConfig defines any extra (overlay) configuration for components
+ tempo: {} # Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
+ ingestion: # Ingestion defines the trace ingestion configuration
+ otlp: # OTLP defines the ingestion configuration for OTLP
+ grpc: # GRPC defines the OTLP/gRPC configuration
+ enabled: false # Enabled defines if the OTLP over gRPC is enabled
+ http: # HTTP defines the OTLP/HTTP configuration
+ enabled: false # Enabled defines if the OTLP over HTTP is enabled
+ tls: # TLS defines the TLS configuration for ingestion
+ ca: "" # CA defines the name of a secret containing the CA certificate
+ cert: "" # Cert defines the name of a secret containing the TLS certificate and private key
+ enabled: false # Enabled defines if TLS is enabled for ingestion
+ jaegerui: # JaegerUI defines the Jaeger UI configuration
+ enabled: false # Enabled defines if the Jaeger UI should be enabled
+ ingress: # Ingress defines the ingress configuration for Jaeger UI
+ enabled: false # Enabled defines if an Ingress object should be created for Jaeger UI
+ route: # Route defines the route configuration for Jaeger UI
+ enabled: false # Enabled defines if a Route object should be created for Jaeger UI
+ management: "" # ManagementState defines whether this instance is managed by the operator or self-managed
+ observability: # Observability defines observability configuration for the Tempo deployment
+ metrics: # Metrics defines the metrics configuration of the Tempo deployment
+ prometheusRules: # ServiceMonitors defines the PrometheusRule configuration
+ enabled: false # Enabled defines if the operator should create PrometheusRules for this Tempo deployment
+ serviceMonitors: # ServiceMonitors defines the ServiceMonitor configuration
+ enabled: false # Enabled defines if the operator should create ServiceMonitors for this Tempo deployment
+ storage: # Storage defines the backend storage configuration
+ traces: # Traces defines the backend storage configuration for traces
+ backend: "" # Backend defines the backend for storing traces
+ pv: # PV defines the Persistent Volume configuration
+ size: 1Gi # Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
+ secret: "" # Secret defines name of a secret containing the credentials for accessing the specified backend storage
+ wal: # WAL defines the write-ahead logging (WAL) configuration
+ size: 1Gi # Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
+status: # TempoMonolithicStatus defines the observed state of TempoMonolithic.
diff --git a/internal/manifests/manifestutils/constants.go b/internal/manifests/manifestutils/constants.go
index 90c7e5d80..0231d694d 100644
--- a/internal/manifests/manifestutils/constants.go
+++ b/internal/manifests/manifestutils/constants.go
@@ -37,6 +37,21 @@ const (
// PortGRPCServer declares the port number of the tempo gRPC port.
PortGRPCServer = 9095
+ // JaegerUIPortName declares the name of the Jaeger UI HTTP port.
+ JaegerUIPortName = "jaeger-ui"
+ // PortJaegerUI declares the port number of the Jaeger UI HTTP port.
+ PortJaegerUI = 16686
+
+ // JaegerGRPCQuery declares the name of the Jaeger UI gPRC port.
+ JaegerGRPCQuery = "jaeger-gprc"
+ // PortJaegerGRPCQuery declares the port number of the Jaeger UI gPRC port.
+ PortJaegerGRPCQuery = 16685
+
+ // JaegerMetricsPortName declares the name of the Jaeger UI metrics port.
+ JaegerMetricsPortName = "jaeger-metrics"
+ // PortJaegerMetrics declares the port number of the Jaeger UI metrics port.
+ PortJaegerMetrics = 16687
+
// OtlpGrpcPortName declares the name of the OpenTelemetry Collector gRPC receiver port.
OtlpGrpcPortName = "otlp-grpc"
// PortOtlpGrpcServer declares the port number of the OpenTelemetry Collector gRPC receiver port.
diff --git a/internal/manifests/monolithic/build.go b/internal/manifests/monolithic/build.go
new file mode 100644
index 000000000..b65037d32
--- /dev/null
+++ b/internal/manifests/monolithic/build.go
@@ -0,0 +1,28 @@
+package monolithic
+
+import (
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// BuildAll generates all manifests.
+func BuildAll(opts Options) ([]client.Object, error) {
+ var manifests []client.Object
+
+ configMap, configChecksum, err := BuildConfigMap(opts)
+ if err != nil {
+ return nil, err
+ }
+ manifests = append(manifests, configMap)
+ opts.ConfigChecksum = configChecksum
+
+ statefulSet, err := BuildTempoStatefulset(opts)
+ if err != nil {
+ return nil, err
+ }
+ manifests = append(manifests, statefulSet)
+
+ services := BuildServices(opts)
+ manifests = append(manifests, services...)
+
+ return manifests, nil
+}
diff --git a/internal/manifests/monolithic/config.go b/internal/manifests/monolithic/config.go
new file mode 100644
index 000000000..53158903d
--- /dev/null
+++ b/internal/manifests/monolithic/config.go
@@ -0,0 +1,162 @@
+package monolithic
+
+import (
+ "crypto/sha256"
+ "encoding/json"
+ "fmt"
+
+ "github.com/imdario/mergo"
+ "gopkg.in/yaml.v2"
+ v1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/grafana/tempo-operator/internal/manifests/manifestutils"
+ "github.com/grafana/tempo-operator/internal/manifests/naming"
+)
+
+type tempoConfig struct {
+ Server struct {
+ HttpListenPort int `yaml:"http_listen_port"`
+ } `yaml:"server"`
+
+ Storage struct {
+ Trace struct {
+ Backend string `yaml:"backend"`
+ WAL struct {
+ Path string `yaml:"path"`
+ } `yaml:"wal"`
+ Local struct {
+ Path string `yaml:"path"`
+ } `yaml:"local"`
+ } `yaml:"trace"`
+ } `yaml:"storage"`
+
+ Distributor struct {
+ Receivers struct {
+ OTLP struct {
+ Protocols struct {
+ GRPC *struct{} `yaml:"grpc,omitempty"`
+ HTTP *struct{} `yaml:"http,omitempty"`
+ } `yaml:"protocols"`
+ } `yaml:"otlp"`
+ } `yaml:"receivers"`
+ } `yaml:"distributor"`
+
+ UsageReport struct {
+ ReportingEnabled bool `yaml:"reporting_enabled"`
+ } `yaml:"usage_report"`
+}
+
+type tempoQueryConfig struct {
+ Backend string `yaml:"backend"`
+ TenantHeaderKey string `yaml:"tenant_header_key"`
+}
+
+// BuildConfigMap creates the Tempo ConfigMap for a monolithic deployment.
+func BuildConfigMap(opts Options) (*corev1.ConfigMap, string, error) {
+ tempo := opts.Tempo
+ labels := ComponentLabels("config", tempo.Name)
+
+ tempoConfig, err := buildTempoConfig(opts)
+ if err != nil {
+ return nil, "", err
+ }
+
+ configMap := &corev1.ConfigMap{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: v1.SchemeGroupVersion.String(),
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: naming.Name("", tempo.Name),
+ Namespace: tempo.Namespace,
+ Labels: labels,
+ },
+ Data: map[string]string{
+ "tempo.yaml": string(tempoConfig),
+ },
+ }
+
+ h := sha256.Sum256(tempoConfig)
+ checksum := fmt.Sprintf("%x", h)
+
+ if tempo.Spec.JaegerUI != nil && tempo.Spec.JaegerUI.Enabled {
+ tempoQueryConfig, err := buildTempoQueryConfig()
+ if err != nil {
+ return nil, "", err
+ }
+ configMap.Data["tempo-query.yaml"] = string(tempoQueryConfig)
+ }
+
+ return configMap, checksum, nil
+}
+
+func buildTempoConfig(opts Options) ([]byte, error) {
+ tempo := opts.Tempo
+
+ config := tempoConfig{}
+ config.Server.HttpListenPort = manifestutils.PortHTTPServer
+
+ config.Storage.Trace.WAL.Path = "/var/tempo/wal"
+ switch tempo.Spec.Storage.Traces.Backend {
+ case v1alpha1.MonolithicTracesStorageBackendMemory,
+ v1alpha1.MonolithicTracesStorageBackendPersistentVolume:
+ config.Storage.Trace.Backend = "local"
+ config.Storage.Trace.Local.Path = "/var/tempo/blocks"
+
+ default:
+ return nil, fmt.Errorf("invalid storage backend: '%s'", tempo.Spec.Storage.Traces.Backend)
+ }
+
+ if tempo.Spec.Ingestion != nil && tempo.Spec.Ingestion.OTLP != nil {
+ if tempo.Spec.Ingestion.OTLP.GRPC != nil && tempo.Spec.Ingestion.OTLP.GRPC.Enabled {
+ config.Distributor.Receivers.OTLP.Protocols.GRPC = &struct{}{}
+ }
+ if tempo.Spec.Ingestion.OTLP.HTTP != nil && tempo.Spec.Ingestion.OTLP.HTTP.Enabled {
+ config.Distributor.Receivers.OTLP.Protocols.HTTP = &struct{}{}
+ }
+ }
+
+ if tempo.Spec.ExtraConfig == nil || len(tempo.Spec.ExtraConfig.Tempo.Raw) == 0 {
+ return yaml.Marshal(config)
+ } else {
+ return overlayJson(config, tempo.Spec.ExtraConfig.Tempo.Raw)
+ }
+}
+
+func overlayJson(config tempoConfig, overlay []byte) ([]byte, error) {
+ // mergo.Merge requires that both variables have the same type
+ generatedCfg := make(map[string]interface{})
+ overlayCfg := make(map[string]interface{})
+
+ // Convert tempoConfig{} to map[string]interface{}
+ generatedYaml, err := yaml.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ if err := yaml.Unmarshal(generatedYaml, &generatedCfg); err != nil {
+ return nil, err
+ }
+
+ // Unmarshal overlay of type []byte to map[string]interface{}
+ if err := json.Unmarshal(overlay, &overlayCfg); err != nil {
+ return nil, err
+ }
+
+ // Override generated config with extra config
+ err = mergo.Merge(&generatedCfg, overlayCfg, mergo.WithOverride)
+ if err != nil {
+ return nil, err
+ }
+
+ return yaml.Marshal(generatedCfg)
+}
+
+func buildTempoQueryConfig() ([]byte, error) {
+ config := tempoQueryConfig{}
+ config.Backend = fmt.Sprintf("127.0.0.1:%d", manifestutils.PortHTTPServer)
+ config.TenantHeaderKey = manifestutils.TenantHeader
+
+ return yaml.Marshal(&config)
+}
diff --git a/internal/manifests/monolithic/labels.go b/internal/manifests/monolithic/labels.go
new file mode 100644
index 000000000..cd191fa88
--- /dev/null
+++ b/internal/manifests/monolithic/labels.go
@@ -0,0 +1,19 @@
+package monolithic
+
+import "k8s.io/apimachinery/pkg/labels"
+
+// ComponentLabels is a list of all commonLabels including the app.kubernetes.io/component: label.
+func ComponentLabels(component, instanceName string) labels.Set {
+ return labels.Merge(CommonLabels(instanceName), map[string]string{
+ "app.kubernetes.io/component": component,
+ })
+}
+
+// CommonLabels returns common labels for each TempoMonolithic object created by the operator.
+func CommonLabels(instanceName string) map[string]string {
+ return map[string]string{
+ "app.kubernetes.io/name": "tempo-monolithic",
+ "app.kubernetes.io/instance": instanceName,
+ "app.kubernetes.io/managed-by": "tempo-operator",
+ }
+}
diff --git a/internal/manifests/monolithic/options.go b/internal/manifests/monolithic/options.go
new file mode 100644
index 000000000..add1e6441
--- /dev/null
+++ b/internal/manifests/monolithic/options.go
@@ -0,0 +1,13 @@
+package monolithic
+
+import (
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+)
+
+// Options defines calculated options required to generate all manifests.
+type Options struct {
+ CtrlConfig configv1alpha1.ProjectConfig
+ Tempo v1alpha1.TempoMonolithic
+ ConfigChecksum string
+}
diff --git a/internal/manifests/monolithic/service.go b/internal/manifests/monolithic/service.go
new file mode 100644
index 000000000..52bb6bdc7
--- /dev/null
+++ b/internal/manifests/monolithic/service.go
@@ -0,0 +1,126 @@
+package monolithic
+
+import (
+ v1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ "github.com/grafana/tempo-operator/internal/manifests/manifestutils"
+ "github.com/grafana/tempo-operator/internal/manifests/naming"
+)
+
+// BuildServices creates all services for a monolithic deployment.
+func BuildServices(opts Options) []client.Object {
+ services := []client.Object{
+ buildTempoApiService(opts),
+ buildTempoIngestService(opts),
+ }
+
+ if opts.Tempo.Spec.JaegerUI != nil && opts.Tempo.Spec.JaegerUI.Enabled {
+ services = append(services, buildJaegerUIService(opts))
+ }
+
+ return services
+}
+
+func buildTempoApiService(opts Options) *corev1.Service {
+ labels := ComponentLabels("tempo", opts.Tempo.Name)
+ return &corev1.Service{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: v1.SchemeGroupVersion.String(),
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: naming.Name("api", opts.Tempo.Name),
+ Namespace: opts.Tempo.Namespace,
+ Labels: labels,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{
+ {
+ Name: manifestutils.HttpPortName,
+ Protocol: corev1.ProtocolTCP,
+ Port: manifestutils.PortHTTPServer,
+ TargetPort: intstr.FromString(manifestutils.HttpPortName),
+ },
+ },
+ Selector: labels,
+ },
+ }
+}
+
+func buildTempoIngestService(opts Options) *corev1.Service {
+ tempo := opts.Tempo
+ labels := ComponentLabels("tempo", tempo.Name)
+
+ ports := []corev1.ServicePort{}
+ // TODO: point to gateway
+ if tempo.Spec.Ingestion != nil && tempo.Spec.Ingestion.OTLP != nil {
+ if tempo.Spec.Ingestion.OTLP.GRPC != nil && tempo.Spec.Ingestion.OTLP.GRPC.Enabled {
+ ports = append(ports, corev1.ServicePort{
+ Name: manifestutils.OtlpGrpcPortName,
+ Protocol: corev1.ProtocolTCP,
+ Port: manifestutils.PortOtlpGrpcServer,
+ TargetPort: intstr.FromString(manifestutils.OtlpGrpcPortName),
+ })
+ }
+ if tempo.Spec.Ingestion.OTLP.HTTP != nil && tempo.Spec.Ingestion.OTLP.HTTP.Enabled {
+ ports = append(ports, corev1.ServicePort{
+ Name: manifestutils.PortOtlpHttpName,
+ Protocol: corev1.ProtocolTCP,
+ Port: manifestutils.PortOtlpHttp,
+ TargetPort: intstr.FromString(manifestutils.PortOtlpHttpName),
+ })
+ }
+ }
+
+ return &corev1.Service{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: v1.SchemeGroupVersion.String(),
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: naming.Name("ingest", opts.Tempo.Name),
+ Namespace: opts.Tempo.Namespace,
+ Labels: labels,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: ports,
+ Selector: labels,
+ },
+ }
+}
+
+func buildJaegerUIService(opts Options) *corev1.Service {
+ labels := ComponentLabels("tempo", opts.Tempo.Name)
+ return &corev1.Service{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: v1.SchemeGroupVersion.String(),
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: naming.Name("jaegerui", opts.Tempo.Name),
+ Namespace: opts.Tempo.Namespace,
+ Labels: labels,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{
+ {
+ Name: manifestutils.JaegerGRPCQuery,
+ Port: manifestutils.PortJaegerGRPCQuery,
+ TargetPort: intstr.FromString(manifestutils.JaegerGRPCQuery),
+ },
+ {
+ Name: manifestutils.JaegerUIPortName,
+ Port: manifestutils.PortJaegerUI,
+ TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
+ },
+ {
+ Name: manifestutils.JaegerMetricsPortName,
+ Port: manifestutils.PortJaegerMetrics,
+ TargetPort: intstr.FromString(manifestutils.JaegerMetricsPortName),
+ },
+ },
+ Selector: labels,
+ },
+ }
+}
diff --git a/internal/manifests/monolithic/statefulset.go b/internal/manifests/monolithic/statefulset.go
new file mode 100644
index 000000000..760265748
--- /dev/null
+++ b/internal/manifests/monolithic/statefulset.go
@@ -0,0 +1,252 @@
+package monolithic
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/operator-framework/operator-lib/proxy"
+ v1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
+
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/grafana/tempo-operator/internal/manifests/manifestutils"
+ "github.com/grafana/tempo-operator/internal/manifests/naming"
+)
+
+const (
+ walVolumeName = "tempo-wal"
+ blocksVolumeName = "tempo-blocks"
+)
+
+// BuildTempoStatefulset creates the Tempo statefulset for a monolithic deployment.
+func BuildTempoStatefulset(opts Options) (*v1.StatefulSet, error) {
+ tempo := opts.Tempo
+ labels := ComponentLabels("tempo", tempo.Name)
+ annotations := manifestutils.CommonAnnotations(opts.ConfigChecksum)
+
+ ss := &v1.StatefulSet{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: v1.SchemeGroupVersion.String(),
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: naming.Name("", tempo.Name),
+ Namespace: tempo.Namespace,
+ Labels: labels,
+ },
+ Spec: v1.StatefulSetSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: labels,
+ },
+
+ // Changes to a StatefulSet are not propagated to pods in a broken state (e.g. CrashLoopBackOff)
+ // See https://github.com/kubernetes/kubernetes/issues/67250
+ //
+ // This is a workaround for the above issue.
+ // This setting is also in the tempo-distributed helm chart: https://github.com/grafana/helm-charts/blob/0fdf2e1900733eb104ac734f5fb0a89dc950d2c2/charts/tempo-distributed/templates/ingester/statefulset-ingester.yaml#L21
+ PodManagementPolicy: v1.ParallelPodManagement,
+
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: labels,
+ Annotations: annotations,
+ },
+ Spec: corev1.PodSpec{
+ Affinity: manifestutils.DefaultAffinity(labels),
+ Containers: []corev1.Container{
+ {
+ Name: "tempo",
+ Image: opts.CtrlConfig.DefaultImages.Tempo,
+ Env: proxy.ReadProxyVarsFromEnv(),
+ Args: []string{
+ "-config.file=/conf/tempo.yaml",
+ "-mem-ballast-size-mbs=1024",
+ "-log.level=info",
+ },
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: manifestutils.ConfigVolumeName,
+ MountPath: "/conf",
+ ReadOnly: true,
+ },
+ {
+ Name: walVolumeName,
+ MountPath: "/var/tempo/wal",
+ },
+ },
+ Ports: buildTempoPorts(opts),
+ ReadinessProbe: manifestutils.TempoReadinessProbe(false),
+ SecurityContext: manifestutils.TempoContainerSecurityContext(),
+ },
+ },
+ Volumes: []corev1.Volume{
+ {
+ Name: manifestutils.ConfigVolumeName,
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: naming.Name("", tempo.Name),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ err := configureStorage(opts, ss)
+ if err != nil {
+ return nil, err
+ }
+
+ if tempo.Spec.JaegerUI != nil && tempo.Spec.JaegerUI.Enabled {
+ configureJaegerUI(opts, ss)
+ }
+
+ return ss, nil
+}
+
+func buildTempoPorts(opts Options) []corev1.ContainerPort {
+ tempo := opts.Tempo
+ ports := []corev1.ContainerPort{
+ {
+ Name: manifestutils.HttpPortName,
+ ContainerPort: manifestutils.PortHTTPServer,
+ Protocol: corev1.ProtocolTCP,
+ },
+ }
+
+ if tempo.Spec.Ingestion != nil && tempo.Spec.Ingestion.OTLP != nil {
+ if tempo.Spec.Ingestion.OTLP.GRPC != nil && tempo.Spec.Ingestion.OTLP.GRPC.Enabled {
+ ports = append(ports, corev1.ContainerPort{
+ Name: manifestutils.OtlpGrpcPortName,
+ ContainerPort: manifestutils.PortOtlpGrpcServer,
+ Protocol: corev1.ProtocolTCP,
+ })
+ }
+ if tempo.Spec.Ingestion.OTLP.HTTP != nil && tempo.Spec.Ingestion.OTLP.HTTP.Enabled {
+ ports = append(ports, corev1.ContainerPort{
+ Name: manifestutils.PortOtlpHttpName,
+ ContainerPort: manifestutils.PortOtlpHttp,
+ Protocol: corev1.ProtocolTCP,
+ })
+ }
+ }
+
+ return ports
+}
+
+func configureStorage(opts Options, sts *v1.StatefulSet) error {
+ tempo := opts.Tempo
+ switch tempo.Spec.Storage.Traces.Backend {
+ case v1alpha1.MonolithicTracesStorageBackendMemory:
+ sts.Spec.Template.Spec.Volumes = append(sts.Spec.Template.Spec.Volumes, corev1.Volume{
+ Name: walVolumeName,
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ Medium: corev1.StorageMediumMemory,
+ },
+ },
+ })
+
+ sts.Spec.Template.Spec.Containers[0].VolumeMounts = append(sts.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
+ Name: blocksVolumeName,
+ MountPath: "/var/tempo/blocks",
+ })
+ sts.Spec.Template.Spec.Volumes = append(sts.Spec.Template.Spec.Volumes, corev1.Volume{
+ Name: blocksVolumeName,
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ Medium: corev1.StorageMediumMemory,
+ },
+ },
+ })
+
+ case v1alpha1.MonolithicTracesStorageBackendPersistentVolume:
+ if tempo.Spec.Storage.Traces.WAL == nil {
+ return errors.New("please configure .spec.storage.traces.wal")
+ }
+ sts.Spec.VolumeClaimTemplates = append(sts.Spec.VolumeClaimTemplates, corev1.PersistentVolumeClaim{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: walVolumeName,
+ },
+ Spec: corev1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceStorage: tempo.Spec.Storage.Traces.WAL.Size,
+ },
+ },
+ VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
+ },
+ })
+
+ if tempo.Spec.Storage.Traces.PV == nil {
+ return errors.New("please configure .spec.storage.traces.pv")
+ }
+ sts.Spec.Template.Spec.Containers[0].VolumeMounts = append(sts.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
+ Name: blocksVolumeName,
+ MountPath: "/var/tempo/blocks",
+ })
+ sts.Spec.VolumeClaimTemplates = append(sts.Spec.VolumeClaimTemplates, corev1.PersistentVolumeClaim{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: blocksVolumeName,
+ },
+ Spec: corev1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceStorage: tempo.Spec.Storage.Traces.PV.Size,
+ },
+ },
+ VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
+ },
+ })
+
+ default:
+ return fmt.Errorf("invalid storage backend: '%s'", tempo.Spec.Storage.Traces.Backend)
+ }
+ return nil
+}
+
+func configureJaegerUI(opts Options, sts *v1.StatefulSet) {
+ tempoQuery := corev1.Container{
+ Name: "tempo-query",
+ Image: opts.CtrlConfig.DefaultImages.TempoQuery,
+ Env: proxy.ReadProxyVarsFromEnv(),
+ Args: []string{
+ "--query.base-path=/",
+ "--grpc-storage-plugin.configuration-file=/conf/tempo-query.yaml",
+ "--query.bearer-token-propagation=true",
+ },
+ Ports: []corev1.ContainerPort{
+ {
+ Name: manifestutils.JaegerGRPCQuery,
+ ContainerPort: manifestutils.PortJaegerGRPCQuery,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: manifestutils.JaegerUIPortName,
+ ContainerPort: manifestutils.PortJaegerUI,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: manifestutils.JaegerMetricsPortName,
+ ContainerPort: manifestutils.PortJaegerMetrics,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: manifestutils.ConfigVolumeName,
+ MountPath: "/conf",
+ ReadOnly: true,
+ },
+ },
+ }
+
+ sts.Spec.Template.Spec.Containers = append(sts.Spec.Template.Spec.Containers, tempoQuery)
+}
diff --git a/internal/manifests/mutate.go b/internal/manifests/mutate.go
index 6c2f989e5..691554e50 100644
--- a/internal/manifests/mutate.go
+++ b/internal/manifests/mutate.go
@@ -1,6 +1,7 @@
package manifests
import (
+ "fmt"
"reflect"
"github.com/ViaQ/logerr/v2/kverrors"
@@ -12,10 +13,22 @@ import (
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
rbacv1 "k8s.io/api/rbac/v1"
+ apiequality "k8s.io/apimachinery/pkg/api/equality"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
+// ImmutableErr occurs if an immutable field should be changed.
+type ImmutableErr struct {
+ field string
+ existing interface{}
+ desired interface{}
+}
+
+func (m *ImmutableErr) Error() string {
+ return fmt.Sprintf("update to immutable field %s is forbidden", m.field)
+}
+
// MutateFuncFor returns a mutate function based on the
// existing resource's concrete type. It supports currently
// only the following types or else panics:
@@ -127,6 +140,7 @@ func MutateFuncFor(existing, desired client.Object) controllerutil.MutateFn {
}
}
+// Override non-empty dst attributes with non-empty src attributes values.
func mergeWithOverride(dst, src interface{}) error {
err := mergo.Merge(dst, src, mergo.WithOverride)
if err != nil {
@@ -231,12 +245,32 @@ func mutateDeployment(existing, desired *appsv1.Deployment) error {
return nil
}
+func statefulSetVolumeClaimTemplatesChanged(existing, desired *appsv1.StatefulSet) bool {
+ if len(desired.Spec.VolumeClaimTemplates) != len(existing.Spec.VolumeClaimTemplates) {
+ return true
+ }
+ for i := range desired.Spec.VolumeClaimTemplates {
+ if desired.Spec.VolumeClaimTemplates[i].Name != existing.Spec.VolumeClaimTemplates[i].Name ||
+ !apiequality.Semantic.DeepEqual(desired.Spec.VolumeClaimTemplates[i].Annotations, existing.Spec.VolumeClaimTemplates[i].Annotations) ||
+ !apiequality.Semantic.DeepEqual(desired.Spec.VolumeClaimTemplates[i].Spec, existing.Spec.VolumeClaimTemplates[i].Spec) {
+ return true
+ }
+ }
+ return false
+}
+
func mutateStatefulSet(existing, desired *appsv1.StatefulSet) error {
- // StatefulSet selector is immutable so we set this value only if
- // a new object is going to be created
- if existing.CreationTimestamp.IsZero() {
- existing.Spec.Selector = desired.Spec.Selector
+ // list of mutable fields: https://github.com/kubernetes/kubernetes/blob/b1cf91b300a82bd05fdd7b115559e5b83680d768/pkg/apis/apps/validation/validation.go#L184
+ if !existing.CreationTimestamp.IsZero() {
+ if !apiequality.Semantic.DeepEqual(desired.Spec.Selector, existing.Spec.Selector) {
+ return &ImmutableErr{".spec.selector", existing.Spec.Selector, desired.Spec.Selector}
+ }
+ if statefulSetVolumeClaimTemplatesChanged(existing, desired) {
+ return &ImmutableErr{".spec.volumeClaimTemplates", existing.Spec.VolumeClaimTemplates, desired.Spec.VolumeClaimTemplates}
+ }
}
+
+ existing.Spec.Selector = desired.Spec.Selector
existing.Spec.PodManagementPolicy = desired.Spec.PodManagementPolicy
existing.Spec.Replicas = desired.Spec.Replicas
for i := range existing.Spec.VolumeClaimTemplates {
diff --git a/internal/manifests/queryfrontend/query_frontend.go b/internal/manifests/queryfrontend/query_frontend.go
index b5df0c92c..f76fe66f7 100644
--- a/internal/manifests/queryfrontend/query_frontend.go
+++ b/internal/manifests/queryfrontend/query_frontend.go
@@ -23,15 +23,8 @@ import (
)
const (
- grpclbPortName = "grpclb"
- jaegerMetricsPortName = "jaeger-metrics"
- jaegerGRPCQuery = "jaeger-gprc"
- jaegerUIPortName = "jaeger-ui"
- portGRPCLBServer = 9096
- portJaegerGRPCQuery = 16685
- portJaegerUI = 16686
- portJaegerMetrics = 16687
-
+ grpclbPortName = "grpclb"
+ portGRPCLBServer = 9096
thanosQuerierOpenShiftMonitoring = "https://thanos-querier.openshift-monitoring.svc.cluster.local:9091"
)
@@ -205,18 +198,18 @@ func deployment(params manifestutils.Params) (*appsv1.Deployment, error) {
},
Ports: []corev1.ContainerPort{
{
- Name: jaegerGRPCQuery,
- ContainerPort: portJaegerGRPCQuery,
+ Name: manifestutils.JaegerGRPCQuery,
+ ContainerPort: manifestutils.PortJaegerGRPCQuery,
Protocol: corev1.ProtocolTCP,
},
{
- Name: jaegerUIPortName,
- ContainerPort: portJaegerUI,
+ Name: manifestutils.JaegerUIPortName,
+ ContainerPort: manifestutils.PortJaegerUI,
Protocol: corev1.ProtocolTCP,
},
{
- Name: jaegerMetricsPortName,
- ContainerPort: portJaegerMetrics,
+ Name: manifestutils.JaegerMetricsPortName,
+ ContainerPort: manifestutils.PortJaegerMetrics,
Protocol: corev1.ProtocolTCP,
},
},
@@ -414,19 +407,19 @@ func services(tempo v1alpha1.TempoStack) []*corev1.Service {
if tempo.Spec.Template.QueryFrontend.JaegerQuery.Enabled {
jaegerPorts := []corev1.ServicePort{
{
- Name: jaegerGRPCQuery,
- Port: portJaegerGRPCQuery,
- TargetPort: intstr.FromString(jaegerGRPCQuery),
+ Name: manifestutils.JaegerGRPCQuery,
+ Port: manifestutils.PortJaegerGRPCQuery,
+ TargetPort: intstr.FromString(manifestutils.JaegerGRPCQuery),
},
{
- Name: jaegerUIPortName,
- Port: portJaegerUI,
- TargetPort: intstr.FromString(jaegerUIPortName),
+ Name: manifestutils.JaegerUIPortName,
+ Port: manifestutils.PortJaegerUI,
+ TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
},
{
- Name: jaegerMetricsPortName,
- Port: portJaegerMetrics,
- TargetPort: intstr.FromString(jaegerMetricsPortName),
+ Name: manifestutils.JaegerMetricsPortName,
+ Port: manifestutils.PortJaegerMetrics,
+ TargetPort: intstr.FromString(manifestutils.JaegerMetricsPortName),
},
}
@@ -457,7 +450,7 @@ func ingress(tempo v1alpha1.TempoStack) *networkingv1.Ingress {
Service: &networkingv1.IngressServiceBackend{
Name: queryFrontendName,
Port: networkingv1.ServiceBackendPort{
- Name: jaegerUIPortName,
+ Name: manifestutils.JaegerUIPortName,
},
},
}
@@ -519,7 +512,7 @@ func route(tempo v1alpha1.TempoStack) (*routev1.Route, error) {
Name: queryFrontendName,
},
Port: &routev1.RoutePort{
- TargetPort: intstr.FromString(jaegerUIPortName),
+ TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
},
TLS: tlsCfg,
},
diff --git a/internal/manifests/queryfrontend/query_frontend_test.go b/internal/manifests/queryfrontend/query_frontend_test.go
index 3cd128e73..91aad0d76 100644
--- a/internal/manifests/queryfrontend/query_frontend_test.go
+++ b/internal/manifests/queryfrontend/query_frontend_test.go
@@ -26,19 +26,19 @@ import (
func getJaegerServicePorts() []corev1.ServicePort {
jaegerServicePorts := []corev1.ServicePort{
{
- Name: jaegerGRPCQuery,
- Port: portJaegerGRPCQuery,
- TargetPort: intstr.FromString(jaegerGRPCQuery),
+ Name: manifestutils.JaegerGRPCQuery,
+ Port: manifestutils.PortJaegerGRPCQuery,
+ TargetPort: intstr.FromString(manifestutils.JaegerGRPCQuery),
},
{
- Name: jaegerUIPortName,
- Port: portJaegerUI,
- TargetPort: intstr.FromString(jaegerUIPortName),
+ Name: manifestutils.JaegerUIPortName,
+ Port: manifestutils.PortJaegerUI,
+ TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
},
{
- Name: jaegerMetricsPortName,
- Port: portJaegerMetrics,
- TargetPort: intstr.FromString(jaegerMetricsPortName),
+ Name: manifestutils.JaegerMetricsPortName,
+ Port: manifestutils.PortJaegerMetrics,
+ TargetPort: intstr.FromString(manifestutils.JaegerMetricsPortName),
},
}
return jaegerServicePorts
@@ -226,18 +226,18 @@ func getExpectedDeployment(withJaeger bool) *v1.Deployment {
},
Ports: []corev1.ContainerPort{
{
- Name: jaegerGRPCQuery,
- ContainerPort: portJaegerGRPCQuery,
+ Name: manifestutils.JaegerGRPCQuery,
+ ContainerPort: manifestutils.PortJaegerGRPCQuery,
Protocol: corev1.ProtocolTCP,
},
{
- Name: jaegerUIPortName,
- ContainerPort: portJaegerUI,
+ Name: manifestutils.JaegerUIPortName,
+ ContainerPort: manifestutils.PortJaegerUI,
Protocol: corev1.ProtocolTCP,
},
{
- Name: jaegerMetricsPortName,
- ContainerPort: portJaegerMetrics,
+ Name: manifestutils.JaegerMetricsPortName,
+ ContainerPort: manifestutils.PortJaegerMetrics,
Protocol: corev1.ProtocolTCP,
},
},
@@ -432,7 +432,7 @@ func TestQueryFrontendJaegerIngress(t *testing.T) {
Service: &networkingv1.IngressServiceBackend{
Name: naming.Name(manifestutils.QueryFrontendComponentName, "test"),
Port: networkingv1.ServiceBackendPort{
- Name: jaegerUIPortName,
+ Name: manifestutils.JaegerUIPortName,
},
},
},
@@ -483,7 +483,7 @@ func TestQueryFrontendJaegerRoute(t *testing.T) {
Name: naming.Name(manifestutils.QueryFrontendComponentName, "test"),
},
Port: &routev1.RoutePort{
- TargetPort: intstr.FromString(jaegerUIPortName),
+ TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
},
TLS: &routev1.TLSConfig{
Termination: routev1.TLSTerminationEdge,
From 51a2b26f8d805f4209d36143336f93e3af8f4973 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 21 Dec 2023 14:32:24 +0100
Subject: [PATCH 02/36] Add changelog
Signed-off-by: Andreas Gerstmayr
---
.chloggen/monolithic_mode.yaml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100755 .chloggen/monolithic_mode.yaml
diff --git a/.chloggen/monolithic_mode.yaml b/.chloggen/monolithic_mode.yaml
new file mode 100755
index 000000000..cd27b900e
--- /dev/null
+++ b/.chloggen/monolithic_mode.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. operator, github action)
+component: operator
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Support monolithic deployment mode
+
+# One or more tracking issues related to the change
+issues: [710]
+
+# (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:
From 41dbed1533384547071e981938860ff36a266144 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 21 Dec 2023 15:25:13 +0100
Subject: [PATCH 03/36] update mutate_test.go
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/mutate_test.go | 88 ++++++++++++++++++++++++++-----
1 file changed, 75 insertions(+), 13 deletions(-)
diff --git a/internal/manifests/mutate_test.go b/internal/manifests/mutate_test.go
index 85ef87ce4..1f7b431f6 100644
--- a/internal/manifests/mutate_test.go
+++ b/internal/manifests/mutate_test.go
@@ -642,9 +642,10 @@ func TestGeMutateFunc_MutateStatefulSetSpec(t *testing.T) {
one := int32(1)
two := int32(2)
type test struct {
+ name string
got *appsv1.StatefulSet
want *appsv1.StatefulSet
- name string
+ err error
}
table := []test{
{
@@ -710,7 +711,69 @@ func TestGeMutateFunc_MutateStatefulSetSpec(t *testing.T) {
},
},
{
- name: "update spec without selector",
+ name: "update mutable field .spec.template",
+ got: &appsv1.StatefulSet{
+ ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.Now()},
+ Spec: appsv1.StatefulSetSpec{
+ PodManagementPolicy: appsv1.ParallelPodManagement,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "test": "test",
+ },
+ },
+ Replicas: &one,
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {Name: "test"},
+ },
+ },
+ },
+ VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
+ {
+ Spec: corev1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{
+ corev1.ReadWriteOnce,
+ },
+ },
+ },
+ },
+ },
+ },
+ want: &appsv1.StatefulSet{
+ ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.Now()},
+ Spec: appsv1.StatefulSetSpec{
+ PodManagementPolicy: appsv1.OrderedReadyPodManagement,
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "test": "test",
+ },
+ },
+ Replicas: &two,
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "test",
+ Args: []string{"--do-nothing"},
+ },
+ },
+ },
+ },
+ VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
+ {
+ Spec: corev1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{
+ corev1.ReadWriteOnce,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "update immutable field .spec.volumeClaimTemplates",
got: &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{CreationTimestamp: metav1.Now()},
Spec: appsv1.StatefulSetSpec{
@@ -746,7 +809,6 @@ func TestGeMutateFunc_MutateStatefulSetSpec(t *testing.T) {
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"test": "test",
- "and": "another",
},
},
Replicas: &two,
@@ -772,6 +834,7 @@ func TestGeMutateFunc_MutateStatefulSetSpec(t *testing.T) {
},
},
},
+ err: &manifests.ImmutableErr{},
},
}
for _, tst := range table {
@@ -780,19 +843,18 @@ func TestGeMutateFunc_MutateStatefulSetSpec(t *testing.T) {
t.Parallel()
f := manifests.MutateFuncFor(tst.got, tst.want)
err := f()
- require.NoError(t, err)
- // Ensure conditional mutation applied
- if tst.got.CreationTimestamp.IsZero() {
- require.Equal(t, tst.got.Spec.Selector, tst.want.Spec.Selector)
+ if tst.err != nil {
+ require.ErrorAs(t, err, &tst.err)
} else {
- require.NotEqual(t, tst.got.Spec.Selector, tst.want.Spec.Selector)
- }
+ require.NoError(t, err)
- // Ensure partial mutation applied
- require.Equal(t, tst.got.Spec.Replicas, tst.want.Spec.Replicas)
- require.Equal(t, tst.got.Spec.Template, tst.want.Spec.Template)
- require.Equal(t, tst.got.Spec.VolumeClaimTemplates, tst.got.Spec.VolumeClaimTemplates)
+ // Ensure partial mutation applied
+ require.Equal(t, tst.got.Spec.Selector, tst.want.Spec.Selector)
+ require.Equal(t, tst.got.Spec.Replicas, tst.want.Spec.Replicas)
+ require.Equal(t, tst.got.Spec.Template, tst.want.Spec.Template)
+ require.Equal(t, tst.got.Spec.VolumeClaimTemplates, tst.want.Spec.VolumeClaimTemplates)
+ }
})
}
}
From 8aaa8b53f916e1e29a7044c51c81b037934b883a Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 21 Dec 2023 18:45:20 +0100
Subject: [PATCH 04/36] add webhook tests
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_types.go | 6 +-
.../tempo/v1alpha1/tempomonolithic_webhook.go | 2 +-
.../v1alpha1/tempomonolithic_webhook_test.go | 121 ++++++++++++++++++
apis/tempo/v1alpha1/zz_generated.deepcopy.go | 8 +-
.../tempo/tempomonolithic_controller.go | 5 +
5 files changed, 134 insertions(+), 8 deletions(-)
create mode 100644 apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index ee535f8df..5a80f00de 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -62,7 +62,7 @@ type MonolithicTracesStorageSpec struct {
// PV defines the Persistent Volume configuration
//
// +kubebuilder:validation:Required
- PV *MonolithicTracesStoragePersistentVolumeSpec `json:"pv"`
+ PV *MonolithicTracesStoragePVSpec `json:"pv"`
}
// MonolithicTracesStorageBackend defines the backend storage for traces.
@@ -85,8 +85,8 @@ type MonolithicTracesStorageWALSpec struct {
Size resource.Quantity `json:"size"`
}
-// MonolithicTracesStoragePersistentVolumeSpec defines the Persistent Volume configuration.
-type MonolithicTracesStoragePersistentVolumeSpec struct {
+// MonolithicTracesStoragePVSpec defines the Persistent Volume configuration.
+type MonolithicTracesStoragePVSpec struct {
// Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
//
// +kubebuilder:validation:Required
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
index ff7d71b5d..683f1002d 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -34,7 +34,7 @@ func (r *TempoMonolithic) Default() {
}
if r.Spec.Storage.Traces.Backend == MonolithicTracesStorageBackendPersistentVolume && r.Spec.Storage.Traces.PV == nil {
- r.Spec.Storage.Traces.PV = &MonolithicTracesStoragePersistentVolumeSpec{
+ r.Spec.Storage.Traces.PV = &MonolithicTracesStoragePVSpec{
Size: tenGBQuantity,
}
}
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go b/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
new file mode 100644
index 000000000..f0f4a7668
--- /dev/null
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
@@ -0,0 +1,121 @@
+package v1alpha1
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMonolithicDefault(t *testing.T) {
+ tests := []struct {
+ name string
+ input *TempoMonolithic
+ expected *TempoMonolithic
+ }{
+ {
+ name: "empty spec, set memory backend and enable OTLP/gRPC",
+ input: &TempoMonolithic{
+ Spec: TempoMonolithicSpec{},
+ },
+ expected: &TempoMonolithic{
+ Spec: TempoMonolithicSpec{
+ Storage: MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ Ingestion: &MonolithicIngestionSpec{
+ OTLP: &MonolithicIngestionOTLPSpec{
+ GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "set default values for PV",
+ input: &TempoMonolithic{
+ Spec: TempoMonolithicSpec{
+ Storage: MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "pv",
+ },
+ },
+ },
+ },
+ expected: &TempoMonolithic{
+ Spec: TempoMonolithicSpec{
+ Storage: MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "pv",
+ WAL: &MonolithicTracesStorageWALSpec{
+ Size: tenGBQuantity,
+ },
+ PV: &MonolithicTracesStoragePVSpec{
+ Size: tenGBQuantity,
+ },
+ },
+ },
+ Ingestion: &MonolithicIngestionSpec{
+ OTLP: &MonolithicIngestionOTLPSpec{
+ GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "do not change already set values",
+ input: &TempoMonolithic{
+ Spec: TempoMonolithicSpec{
+ Storage: MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "s3",
+ WAL: &MonolithicTracesStorageWALSpec{
+ Size: tenGBQuantity,
+ },
+ },
+ },
+ Ingestion: &MonolithicIngestionSpec{
+ OTLP: &MonolithicIngestionOTLPSpec{
+ // HTTP is already set, GRPC should not be enabled by webhook
+ HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ },
+ expected: &TempoMonolithic{
+ Spec: TempoMonolithicSpec{
+ Storage: MonolithicStorageSpec{
+ Traces: MonolithicTracesStorageSpec{
+ Backend: "s3",
+ WAL: &MonolithicTracesStorageWALSpec{
+ Size: tenGBQuantity,
+ },
+ },
+ },
+ Ingestion: &MonolithicIngestionSpec{
+ OTLP: &MonolithicIngestionOTLPSpec{
+ HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ test.input.Default()
+ assert.Equal(t, test.expected, test.input)
+ })
+ }
+}
diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
index 7829eda3a..47a5aeb26 100644
--- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -624,17 +624,17 @@ func (in *MonolithicStorageSpec) DeepCopy() *MonolithicStorageSpec {
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MonolithicTracesStoragePersistentVolumeSpec) DeepCopyInto(out *MonolithicTracesStoragePersistentVolumeSpec) {
+func (in *MonolithicTracesStoragePVSpec) DeepCopyInto(out *MonolithicTracesStoragePVSpec) {
*out = *in
out.Size = in.Size.DeepCopy()
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicTracesStoragePersistentVolumeSpec.
-func (in *MonolithicTracesStoragePersistentVolumeSpec) DeepCopy() *MonolithicTracesStoragePersistentVolumeSpec {
+func (in *MonolithicTracesStoragePVSpec) DeepCopy() *MonolithicTracesStoragePVSpec {
if in == nil {
return nil
}
- out := new(MonolithicTracesStoragePersistentVolumeSpec)
+ out := new(MonolithicTracesStoragePVSpec)
in.DeepCopyInto(out)
return out
}
@@ -649,7 +649,7 @@ func (in *MonolithicTracesStorageSpec) DeepCopyInto(out *MonolithicTracesStorage
}
if in.PV != nil {
in, out := &in.PV, &out.PV
- *out = new(MonolithicTracesStoragePersistentVolumeSpec)
+ *out = new(MonolithicTracesStoragePVSpec)
(*in).DeepCopyInto(*out)
}
}
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
index dde031b05..ccf663bdc 100644
--- a/controllers/tempo/tempomonolithic_controller.go
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -5,6 +5,8 @@ import (
"fmt"
appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ networkingv1 "k8s.io/api/networking/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
@@ -73,6 +75,9 @@ func (r *TempoMonolithicReconciler) Reconcile(ctx context.Context, req ctrl.Requ
func (r *TempoMonolithicReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&v1alpha1.TempoMonolithic{}).
+ Owns(&corev1.ConfigMap{}).
+ Owns(&corev1.Service{}).
Owns(&appsv1.StatefulSet{}).
+ Owns(&networkingv1.Ingress{}).
Complete(r)
}
From 442004c459ac2251a9804725d0fc1c617544bba6 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 21 Dec 2023 18:50:24 +0100
Subject: [PATCH 05/36] add generated files
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/zz_generated.deepcopy.go | 2 +-
docs/operator/api.md | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
index 47a5aeb26..48cbc8993 100644
--- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -629,7 +629,7 @@ func (in *MonolithicTracesStoragePVSpec) DeepCopyInto(out *MonolithicTracesStora
out.Size = in.Size.DeepCopy()
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicTracesStoragePersistentVolumeSpec.
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicTracesStoragePVSpec.
func (in *MonolithicTracesStoragePVSpec) DeepCopy() *MonolithicTracesStoragePVSpec {
if in == nil {
return nil
diff --git a/docs/operator/api.md b/docs/operator/api.md
index cab1608b2..4fd16c30c 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -2540,7 +2540,7 @@ MonolithicTracesStorageSpec
|
-## MonolithicTracesStoragePersistentVolumeSpec { #tempo-grafana-com-v1alpha1-MonolithicTracesStoragePersistentVolumeSpec }
+## MonolithicTracesStoragePVSpec { #tempo-grafana-com-v1alpha1-MonolithicTracesStoragePVSpec }
@@ -2550,7 +2550,7 @@ MonolithicTracesStorageSpec
- MonolithicTracesStoragePersistentVolumeSpec defines the Persistent Volume configuration.
+ MonolithicTracesStoragePVSpec defines the Persistent Volume configuration.
@@ -2682,9 +2682,9 @@ MonolithicTracesStorageWALSpec
-
+
-MonolithicTracesStoragePersistentVolumeSpec
+MonolithicTracesStoragePVSpec
From 7d3ce55f61a1a9bbed49600ca800ec1995f6fb45 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 21 Dec 2023 20:05:01 +0100
Subject: [PATCH 06/36] support pruning unmanaged objects
Signed-off-by: Andreas Gerstmayr
---
controllers/tempo/common.go | 43 ++++++++--
.../tempo/tempomonolithic_controller.go | 85 ++++++++++++++++++-
.../tempo/tempostack_controller_test.go | 2 +-
internal/manifests/monolithic/config.go | 5 +-
internal/manifests/monolithic/service.go | 11 ++-
internal/manifests/monolithic/statefulset.go | 17 ++--
6 files changed, 142 insertions(+), 21 deletions(-)
diff --git a/controllers/tempo/common.go b/controllers/tempo/common.go
index d0ce86fa8..801ae73c2 100644
--- a/controllers/tempo/common.go
+++ b/controllers/tempo/common.go
@@ -9,6 +9,7 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -26,7 +27,18 @@ func isNamespaceScoped(obj client.Object) bool {
// reconcileManagedObjects creates or updates all managed objects.
// If immutable fields are changed, the object will be deleted and re-created.
-func reconcileManagedObjects(ctx context.Context, log logr.Logger, k8sclient client.Client, owner metav1.Object, scheme *runtime.Scheme, managedObjects []client.Object) error {
+func reconcileManagedObjects(
+ ctx context.Context,
+ log logr.Logger,
+ k8sclient client.Client,
+ owner metav1.Object,
+ scheme *runtime.Scheme,
+ managedObjects []client.Object,
+ ownedObjects map[types.UID]client.Object,
+) error {
+ pruneObjects := ownedObjects
+
+ // Create or update all objects managed by the operator
errs := []error{}
for _, obj := range managedObjects {
l := log.WithValues(
@@ -44,7 +56,6 @@ func reconcileManagedObjects(ctx context.Context, log logr.Logger, k8sclient cli
desired := obj.DeepCopyObject().(client.Object)
mutateFn := manifests.MutateFuncFor(obj, desired)
-
op, err := ctrl.CreateOrUpdate(ctx, k8sclient, obj, mutateFn)
var immutableErr *manifests.ImmutableErr
@@ -52,17 +63,39 @@ func reconcileManagedObjects(ctx context.Context, log logr.Logger, k8sclient cli
l.Error(err, "detected a change in an immutable field. The object will be deleted, and re-created on next reconcile", "obj", obj.GetName())
err = k8sclient.Delete(ctx, desired)
}
+
if err != nil {
l.Error(err, "failed to configure resource")
errs = append(errs, err)
- continue
+ } else {
+ l.V(1).Info(fmt.Sprintf("resource has been %s", op))
}
- l.V(1).Info(fmt.Sprintf("resource has been %s", op))
+ // This object is still managed by the operator, remove it from the list of objects to prune
+ delete(pruneObjects, obj.GetUID())
}
-
if len(errs) > 0 {
return fmt.Errorf("failed to create objects for %s: %w", owner.GetName(), errors.Join(errs...))
}
+
+ // Prune owned objects in the cluster which are not managed anymore
+ pruneErrs := []error{}
+ for _, obj := range pruneObjects {
+ l := log.WithValues(
+ "objectName", obj.GetName(),
+ "objectKind", obj.GetObjectKind(),
+ )
+
+ l.Info("pruning unmanaged resource")
+ err := k8sclient.Delete(ctx, obj)
+ if err != nil {
+ l.Error(err, "failed to delete resource")
+ pruneErrs = append(pruneErrs, err)
+ }
+ }
+ if len(pruneErrs) > 0 {
+ return fmt.Errorf("failed to prune objects for %s: %w", owner.GetName(), errors.Join(pruneErrs...))
+ }
+
return nil
}
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
index ccf663bdc..a67fd7d9e 100644
--- a/controllers/tempo/tempomonolithic_controller.go
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -8,14 +8,19 @@ import (
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
+ grafanav1 "github.com/grafana-operator/grafana-operator/v5/api/v1beta1"
configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
"github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
"github.com/grafana/tempo-operator/internal/manifests/monolithic"
+ routev1 "github.com/openshift/api/route/v1"
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
// TempoMonolithicReconciler reconciles a TempoMonolithic object.
@@ -63,7 +68,12 @@ func (r *TempoMonolithicReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, fmt.Errorf("error building manifests: %w", err)
}
- err = reconcileManagedObjects(ctx, log, r.Client, &tempo, r.Scheme, managedObjects)
+ ownedObjects, err := r.getOwnedObjects(ctx, tempo)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ err = reconcileManagedObjects(ctx, log, r.Client, &tempo, r.Scheme, managedObjects, ownedObjects)
if err != nil {
return ctrl.Result{}, err
}
@@ -71,6 +81,79 @@ func (r *TempoMonolithicReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, nil
}
+func (r *TempoMonolithicReconciler) getOwnedObjects(ctx context.Context, tempo v1alpha1.TempoMonolithic) (map[types.UID]client.Object, error) {
+ ownedObjects := map[types.UID]client.Object{}
+ listOps := &client.ListOptions{
+ Namespace: tempo.GetNamespace(),
+ LabelSelector: labels.SelectorFromSet(monolithic.CommonLabels(tempo.Name)),
+ }
+
+ // Add all resources where the operator can conditionally create an object.
+ // For example, Ingress and Route can be enabled or disabled in the CR.
+
+ serviceList := &corev1.ServiceList{}
+ err := r.List(ctx, serviceList, listOps)
+ if err != nil {
+ return nil, fmt.Errorf("error listing services: %w", err)
+ }
+ for i := range serviceList.Items {
+ ownedObjects[serviceList.Items[i].GetUID()] = &serviceList.Items[i]
+ }
+
+ ingressList := &networkingv1.IngressList{}
+ err = r.List(ctx, ingressList, listOps)
+ if err != nil {
+ return nil, fmt.Errorf("error listing ingress: %w", err)
+ }
+ for i := range ingressList.Items {
+ ownedObjects[ingressList.Items[i].GetUID()] = &ingressList.Items[i]
+ }
+
+ if r.CtrlConfig.Gates.PrometheusOperator {
+ servicemonitorList := &monitoringv1.ServiceMonitorList{}
+ err := r.List(ctx, servicemonitorList, listOps)
+ if err != nil {
+ return nil, fmt.Errorf("error listing service monitors: %w", err)
+ }
+ for i := range servicemonitorList.Items {
+ ownedObjects[servicemonitorList.Items[i].GetUID()] = servicemonitorList.Items[i]
+ }
+
+ prometheusRulesList := &monitoringv1.PrometheusRuleList{}
+ err = r.List(ctx, prometheusRulesList, listOps)
+ if err != nil {
+ return nil, fmt.Errorf("error listing prometheus rules: %w", err)
+ }
+ for i := range prometheusRulesList.Items {
+ ownedObjects[prometheusRulesList.Items[i].GetUID()] = prometheusRulesList.Items[i]
+ }
+ }
+
+ if r.CtrlConfig.Gates.OpenShift.OpenShiftRoute {
+ routesList := &routev1.RouteList{}
+ err := r.List(ctx, routesList, listOps)
+ if err != nil {
+ return nil, fmt.Errorf("error listing routes: %w", err)
+ }
+ for i := range routesList.Items {
+ ownedObjects[routesList.Items[i].GetUID()] = &routesList.Items[i]
+ }
+ }
+
+ if r.CtrlConfig.Gates.GrafanaOperator {
+ datasourceList := &grafanav1.GrafanaDatasourceList{}
+ err := r.List(ctx, datasourceList, listOps)
+ if err != nil {
+ return nil, fmt.Errorf("error listing datasources: %w", err)
+ }
+ for i := range datasourceList.Items {
+ ownedObjects[datasourceList.Items[i].GetUID()] = &datasourceList.Items[i]
+ }
+ }
+
+ return ownedObjects, nil
+}
+
// SetupWithManager sets up the controller with the Manager.
func (r *TempoMonolithicReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
diff --git a/controllers/tempo/tempostack_controller_test.go b/controllers/tempo/tempostack_controller_test.go
index f9c8b98d4..823da603e 100644
--- a/controllers/tempo/tempostack_controller_test.go
+++ b/controllers/tempo/tempostack_controller_test.go
@@ -517,7 +517,7 @@ func TestStorageCustomCA(t *testing.T) {
{
Type: string(v1alpha1.ConditionReady),
Status: "True",
- LastTransitionTime: updatedTempo2.Status.Conditions[0].LastTransitionTime,
+ LastTransitionTime: updatedTempo3.Status.Conditions[0].LastTransitionTime,
Reason: string(v1alpha1.ReasonReady),
Message: "All components are operational",
},
diff --git a/internal/manifests/monolithic/config.go b/internal/manifests/monolithic/config.go
index 53158903d..dec159dfb 100644
--- a/internal/manifests/monolithic/config.go
+++ b/internal/manifests/monolithic/config.go
@@ -7,7 +7,7 @@ import (
"github.com/imdario/mergo"
"gopkg.in/yaml.v2"
- v1 "k8s.io/api/apps/v1"
+ appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -66,7 +66,8 @@ func BuildConfigMap(opts Options) (*corev1.ConfigMap, string, error) {
configMap := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
- APIVersion: v1.SchemeGroupVersion.String(),
+ APIVersion: appsv1.SchemeGroupVersion.String(),
+ Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: naming.Name("", tempo.Name),
diff --git a/internal/manifests/monolithic/service.go b/internal/manifests/monolithic/service.go
index 52bb6bdc7..e9a2d25c6 100644
--- a/internal/manifests/monolithic/service.go
+++ b/internal/manifests/monolithic/service.go
@@ -1,7 +1,7 @@
package monolithic
import (
- v1 "k8s.io/api/apps/v1"
+ appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
@@ -29,7 +29,8 @@ func buildTempoApiService(opts Options) *corev1.Service {
labels := ComponentLabels("tempo", opts.Tempo.Name)
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
- APIVersion: v1.SchemeGroupVersion.String(),
+ APIVersion: appsv1.SchemeGroupVersion.String(),
+ Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
Name: naming.Name("api", opts.Tempo.Name),
@@ -77,7 +78,8 @@ func buildTempoIngestService(opts Options) *corev1.Service {
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
- APIVersion: v1.SchemeGroupVersion.String(),
+ APIVersion: appsv1.SchemeGroupVersion.String(),
+ Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
Name: naming.Name("ingest", opts.Tempo.Name),
@@ -95,7 +97,8 @@ func buildJaegerUIService(opts Options) *corev1.Service {
labels := ComponentLabels("tempo", opts.Tempo.Name)
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
- APIVersion: v1.SchemeGroupVersion.String(),
+ APIVersion: appsv1.SchemeGroupVersion.String(),
+ Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
Name: naming.Name("jaegerui", opts.Tempo.Name),
diff --git a/internal/manifests/monolithic/statefulset.go b/internal/manifests/monolithic/statefulset.go
index 760265748..76036e0a3 100644
--- a/internal/manifests/monolithic/statefulset.go
+++ b/internal/manifests/monolithic/statefulset.go
@@ -5,7 +5,7 @@ import (
"fmt"
"github.com/operator-framework/operator-lib/proxy"
- v1 "k8s.io/api/apps/v1"
+ appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
@@ -21,21 +21,22 @@ const (
)
// BuildTempoStatefulset creates the Tempo statefulset for a monolithic deployment.
-func BuildTempoStatefulset(opts Options) (*v1.StatefulSet, error) {
+func BuildTempoStatefulset(opts Options) (*appsv1.StatefulSet, error) {
tempo := opts.Tempo
labels := ComponentLabels("tempo", tempo.Name)
annotations := manifestutils.CommonAnnotations(opts.ConfigChecksum)
- ss := &v1.StatefulSet{
+ ss := &appsv1.StatefulSet{
TypeMeta: metav1.TypeMeta{
- APIVersion: v1.SchemeGroupVersion.String(),
+ APIVersion: appsv1.SchemeGroupVersion.String(),
+ Kind: "StatefulSet",
},
ObjectMeta: metav1.ObjectMeta{
Name: naming.Name("", tempo.Name),
Namespace: tempo.Namespace,
Labels: labels,
},
- Spec: v1.StatefulSetSpec{
+ Spec: appsv1.StatefulSetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
@@ -45,7 +46,7 @@ func BuildTempoStatefulset(opts Options) (*v1.StatefulSet, error) {
//
// This is a workaround for the above issue.
// This setting is also in the tempo-distributed helm chart: https://github.com/grafana/helm-charts/blob/0fdf2e1900733eb104ac734f5fb0a89dc950d2c2/charts/tempo-distributed/templates/ingester/statefulset-ingester.yaml#L21
- PodManagementPolicy: v1.ParallelPodManagement,
+ PodManagementPolicy: appsv1.ParallelPodManagement,
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
@@ -139,7 +140,7 @@ func buildTempoPorts(opts Options) []corev1.ContainerPort {
return ports
}
-func configureStorage(opts Options, sts *v1.StatefulSet) error {
+func configureStorage(opts Options, sts *appsv1.StatefulSet) error {
tempo := opts.Tempo
switch tempo.Spec.Storage.Traces.Backend {
case v1alpha1.MonolithicTracesStorageBackendMemory:
@@ -212,7 +213,7 @@ func configureStorage(opts Options, sts *v1.StatefulSet) error {
return nil
}
-func configureJaegerUI(opts Options, sts *v1.StatefulSet) {
+func configureJaegerUI(opts Options, sts *appsv1.StatefulSet) {
tempoQuery := corev1.Container{
Name: "tempo-query",
Image: opts.CtrlConfig.DefaultImages.TempoQuery,
From 84cba0cb8b902a15116c0c24801398f0630a480d Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Fri, 22 Dec 2023 15:03:16 +0100
Subject: [PATCH 07/36] use common reconcile/prune function
Signed-off-by: Andreas Gerstmayr
---
.../tempo/tempostack_create_or_update.go | 71 +++----------------
internal/manifests/alerts/prometheus.go | 3 +-
internal/manifests/config/configmap.go | 5 +-
internal/manifests/gateway/openshift.go | 1 +
4 files changed, 16 insertions(+), 64 deletions(-)
diff --git a/controllers/tempo/tempostack_create_or_update.go b/controllers/tempo/tempostack_create_or_update.go
index 0d9ebdece..eb62d2598 100644
--- a/controllers/tempo/tempostack_create_or_update.go
+++ b/controllers/tempo/tempostack_create_or_update.go
@@ -2,7 +2,6 @@ package controllers
import (
"context"
- "errors"
"fmt"
"strings"
@@ -114,15 +113,6 @@ func (r *TempoStackReconciler) createOrUpdate(ctx context.Context, log logr.Logg
}
- // Collect all objects owned by the operator, to be able to prune objects
- // which exist in the cluster but are not managed by the operator anymore.
- // For example, when the Jaeger Query Ingress is enabled and later disabled,
- // the Ingress object should be removed from the cluster.
- pruneObjects, err := r.findObjectsOwnedByTempoOperator(ctx, tempo)
- if err != nil {
- return err
- }
-
var tenantSecrets []*manifestutils.GatewayTenantOIDCSecret
if tempo.Spec.Tenants != nil && tempo.Spec.Tenants.Mode == v1alpha1.ModeStatic {
tenantSecrets, err = gateway.GetOIDCTenantSecrets(ctx, r.Client, tempo)
@@ -153,59 +143,18 @@ func (r *TempoStackReconciler) createOrUpdate(ctx context.Context, log logr.Logg
return fmt.Errorf("error building manifests: %w", err)
}
- errs := []error{}
- for _, obj := range managedObjects {
- l := log.WithValues(
- "object_name", obj.GetName(),
- "object_kind", obj.GetObjectKind(),
- )
-
- if isNamespaceScoped(obj) {
- obj.SetNamespace(req.Namespace)
- if err := ctrl.SetControllerReference(&tempo, obj, r.Scheme); err != nil {
- l.Error(err, "failed to set controller owner reference to resource")
- errs = append(errs, err)
- continue
- }
- }
-
- desired := obj.DeepCopyObject().(client.Object)
- mutateFn := manifests.MutateFuncFor(obj, desired)
-
- op, err := ctrl.CreateOrUpdate(ctx, r.Client, obj, mutateFn)
- if err != nil {
- l.Error(err, "failed to configure resource")
- errs = append(errs, err)
- continue
- }
-
- l.V(1).Info(fmt.Sprintf("resource has been %s", op))
-
- // This object is still managed by the operator, remove it from the list of objects to prune
- delete(pruneObjects, obj.GetUID())
- }
-
- if len(errs) > 0 {
- return fmt.Errorf("failed to create objects for TempoStack %s: %w", req.NamespacedName, errors.Join(errs...))
+ // Collect all objects owned by the operator, to be able to prune objects
+ // which exist in the cluster but are not managed by the operator anymore.
+ // For example, when the Jaeger Query Ingress is enabled and later disabled,
+ // the Ingress object should be removed from the cluster.
+ ownedObjects, err := r.findObjectsOwnedByTempoOperator(ctx, tempo)
+ if err != nil {
+ return err
}
- // Prune owned objects in the cluster which are not managed anymore.
- pruneErrs := []error{}
- for _, obj := range pruneObjects {
- l := log.WithValues(
- "object_name", obj.GetName(),
- "object_kind", obj.GetObjectKind(),
- )
- l.Info("pruning unmanaged resource")
-
- err = r.Delete(ctx, obj)
- if err != nil {
- l.Error(err, "failed to delete resource")
- pruneErrs = append(pruneErrs, err)
- }
- }
- if len(pruneErrs) > 0 {
- return fmt.Errorf("failed to prune objects of TempoStack %s: %w", req.NamespacedName, errors.Join(pruneErrs...))
+ err = reconcileManagedObjects(ctx, log, r.Client, &tempo, r.Scheme, managedObjects, ownedObjects)
+ if err != nil {
+ return err
}
return nil
diff --git a/internal/manifests/alerts/prometheus.go b/internal/manifests/alerts/prometheus.go
index 34e1fc28d..86a16f3b7 100644
--- a/internal/manifests/alerts/prometheus.go
+++ b/internal/manifests/alerts/prometheus.go
@@ -44,7 +44,8 @@ func newPrometheusRule(stackName, namespace string) (*monitoringv1.PrometheusRul
},
ObjectMeta: metav1.ObjectMeta{
- Name: naming.PrometheusRuleName(stackName),
+ Name: naming.PrometheusRuleName(stackName),
+ Namespace: namespace,
Labels: map[string]string{
"openshift.io/prometheus-rule-evaluation-scope": "leaf-prometheus",
},
diff --git a/internal/manifests/config/configmap.go b/internal/manifests/config/configmap.go
index 06fc0cf3a..09940501a 100644
--- a/internal/manifests/config/configmap.go
+++ b/internal/manifests/config/configmap.go
@@ -37,8 +37,9 @@ func BuildConfigMap(params manifestutils.Params) (*corev1.ConfigMap, string, err
labels := manifestutils.ComponentLabels("config", tempo.Name)
configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
- Name: naming.Name("", tempo.Name),
- Labels: labels,
+ Name: naming.Name("", tempo.Name),
+ Namespace: tempo.Namespace,
+ Labels: labels,
},
Data: map[string]string{
"tempo.yaml": string(config),
diff --git a/internal/manifests/gateway/openshift.go b/internal/manifests/gateway/openshift.go
index c85f18857..1ff5b9092 100644
--- a/internal/manifests/gateway/openshift.go
+++ b/internal/manifests/gateway/openshift.go
@@ -126,6 +126,7 @@ func configMapCABundle(tempo v1alpha1.TempoStack) *corev1.ConfigMap {
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: naming.Name("gateway-cabundle", tempo.Name),
+ Namespace: tempo.Namespace,
Labels: manifestutils.ComponentLabels(manifestutils.GatewayComponentName, tempo.Name),
Annotations: map[string]string{"service.beta.openshift.io/inject-cabundle": "true"},
},
From cd797bce46d43cbe093a840109a9994e4022135e Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Fri, 22 Dec 2023 15:29:45 +0100
Subject: [PATCH 08/36] fix linter
Signed-off-by: Andreas Gerstmayr
---
controllers/tempo/tempomonolithic_controller.go | 6 +++---
controllers/tempo/tempostack_controller.go | 2 +-
controllers/tempo/tempostack_controller_test.go | 3 +--
controllers/tempo/tempostack_create_or_update.go | 3 +--
4 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
index a67fd7d9e..69d9b72fe 100644
--- a/controllers/tempo/tempomonolithic_controller.go
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -4,6 +4,9 @@ import (
"context"
"fmt"
+ grafanav1 "github.com/grafana-operator/grafana-operator/v5/api/v1beta1"
+ routev1 "github.com/openshift/api/route/v1"
+ monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
@@ -15,12 +18,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
- grafanav1 "github.com/grafana-operator/grafana-operator/v5/api/v1beta1"
configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
"github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
"github.com/grafana/tempo-operator/internal/manifests/monolithic"
- routev1 "github.com/openshift/api/route/v1"
- monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
)
// TempoMonolithicReconciler reconciles a TempoMonolithic object.
diff --git a/controllers/tempo/tempostack_controller.go b/controllers/tempo/tempostack_controller.go
index 4a2bb396f..6f0bd87ab 100644
--- a/controllers/tempo/tempostack_controller.go
+++ b/controllers/tempo/tempostack_controller.go
@@ -113,7 +113,7 @@ func (r *TempoStackReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
}
- err := r.createOrUpdate(ctx, log, req, tempo)
+ err := r.createOrUpdate(ctx, log, tempo)
if err != nil {
return r.handleReconcileStatus(ctx, log, tempo, err)
}
diff --git a/controllers/tempo/tempostack_controller_test.go b/controllers/tempo/tempostack_controller_test.go
index 823da603e..e8d7138cf 100644
--- a/controllers/tempo/tempostack_controller_test.go
+++ b/controllers/tempo/tempostack_controller_test.go
@@ -888,8 +888,7 @@ func TestReconcileManifestsValidateModes(t *testing.T) {
err := k8sClient.Update(context.Background(), tempo)
require.NoError(t, err)
reconciler := TempoStackReconciler{Client: k8sClient, Scheme: testScheme}
- req := ctrl.Request{NamespacedName: nsn}
- err = reconciler.createOrUpdate(context.Background(), logr.Discard(), req, *tempo)
+ err = reconciler.createOrUpdate(context.Background(), logr.Discard(), *tempo)
tc.validate(t, err)
})
}
diff --git a/controllers/tempo/tempostack_create_or_update.go b/controllers/tempo/tempostack_create_or_update.go
index eb62d2598..c2d912187 100644
--- a/controllers/tempo/tempostack_create_or_update.go
+++ b/controllers/tempo/tempostack_create_or_update.go
@@ -14,7 +14,6 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
- ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
@@ -73,7 +72,7 @@ func (r *TempoStackReconciler) getStorageConfig(ctx context.Context, tempo v1alp
return params, nil
}
-func (r *TempoStackReconciler) createOrUpdate(ctx context.Context, log logr.Logger, req ctrl.Request, tempo v1alpha1.TempoStack) error {
+func (r *TempoStackReconciler) createOrUpdate(ctx context.Context, log logr.Logger, tempo v1alpha1.TempoStack) error {
storageConfig, err := r.getStorageConfig(ctx, tempo)
if err != nil {
return &status.ConfigurationError{
From 355a79e93949c6b2f78ed0286b04dece5a424e98 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Mon, 8 Jan 2024 19:51:42 +0100
Subject: [PATCH 09/36] add sts tests
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_types.go | 12 +-
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 2 -
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 2 -
.../tempo.grafana.com_tempomonolithics.yaml | 2 -
.../manifests/monolithic/statefulset_test.go | 336 ++++++++++++++++++
7 files changed, 344 insertions(+), 14 deletions(-)
create mode 100644 internal/manifests/monolithic/statefulset_test.go
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 5a80f00de..8215d6d1f 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -11,7 +11,7 @@ type TempoMonolithicSpec struct {
// Storage defines the backend storage configuration
//
// +kubebuilder:validation:Optional
- Storage MonolithicStorageSpec `json:"storage"`
+ Storage MonolithicStorageSpec `json:"storage,omitempty"`
// Ingestion defines the trace ingestion configuration
//
@@ -25,7 +25,7 @@ type TempoMonolithicSpec struct {
// ManagementState defines whether this instance is managed by the operator or self-managed
//
- // +kubebuilder:validation:Required
+ // +kubebuilder:validation:Optional
Management ManagementStateType `json:"management,omitempty"`
// Observability defines observability configuration for the Tempo deployment
@@ -56,13 +56,13 @@ type MonolithicTracesStorageSpec struct {
// WAL defines the write-ahead logging (WAL) configuration
//
- // +kubebuilder:validation:Required
- WAL *MonolithicTracesStorageWALSpec `json:"wal"`
+ // +kubebuilder:validation:Optional
+ WAL *MonolithicTracesStorageWALSpec `json:"wal,omitempty"`
// PV defines the Persistent Volume configuration
//
- // +kubebuilder:validation:Required
- PV *MonolithicTracesStoragePVSpec `json:"pv"`
+ // +kubebuilder:validation:Optional
+ PV *MonolithicTracesStoragePVSpec `json:"pv,omitempty"`
}
// MonolithicTracesStorageBackend defines the backend storage for traces.
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 26fcd0a89..6e020dd7e 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2023-12-21T12:56:45Z"
+ createdAt: "2024-01-08T18:44:24Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
index 04502402a..a725edd00 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -205,8 +205,6 @@ spec:
type: object
required:
- backend
- - pv
- - wal
type: object
required:
- traces
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index 8951a1ee8..b07d5fc64 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2023-12-21T12:56:44Z"
+ createdAt: "2024-01-08T18:44:22Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
index 04502402a..a725edd00 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -205,8 +205,6 @@ spec:
type: object
required:
- backend
- - pv
- - wal
type: object
required:
- traces
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
index 857af2d41..9dc254f55 100644
--- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -202,8 +202,6 @@ spec:
type: object
required:
- backend
- - pv
- - wal
type: object
required:
- traces
diff --git a/internal/manifests/monolithic/statefulset_test.go b/internal/manifests/monolithic/statefulset_test.go
new file mode 100644
index 000000000..45ad0c27a
--- /dev/null
+++ b/internal/manifests/monolithic/statefulset_test.go
@@ -0,0 +1,336 @@
+package monolithic
+
+import (
+ "testing"
+
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/grafana/tempo-operator/internal/manifests/manifestutils"
+ "github.com/operator-framework/operator-lib/proxy"
+ "github.com/stretchr/testify/require"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/resource"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
+)
+
+var (
+ oneGBQuantity = resource.MustParse("1Gi")
+ tenGBQuantity = resource.MustParse("10Gi")
+)
+
+func TestStatefulsetMemoryStorage(t *testing.T) {
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ Tempo: "docker.io/grafana/tempo:x.y.z",
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ Ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ },
+ }
+ sts, err := BuildTempoStatefulset(opts)
+ require.NoError(t, err)
+
+ labels := ComponentLabels("tempo", "sample")
+ annotations := manifestutils.CommonAnnotations("")
+ require.Equal(t, &appsv1.StatefulSet{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "StatefulSet",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tempo-sample",
+ Namespace: "default",
+ Labels: labels,
+ },
+ Spec: appsv1.StatefulSetSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: labels,
+ },
+ PodManagementPolicy: appsv1.ParallelPodManagement,
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: labels,
+ Annotations: annotations,
+ },
+ Spec: corev1.PodSpec{
+ Affinity: manifestutils.DefaultAffinity(labels),
+ Containers: []corev1.Container{
+ {
+ Name: "tempo",
+ Image: "docker.io/grafana/tempo:x.y.z",
+ Env: proxy.ReadProxyVarsFromEnv(),
+ Args: []string{
+ "-config.file=/conf/tempo.yaml",
+ "-mem-ballast-size-mbs=1024",
+ "-log.level=info",
+ },
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "tempo-conf",
+ MountPath: "/conf",
+ ReadOnly: true,
+ },
+ {
+ Name: "tempo-wal",
+ MountPath: "/var/tempo/wal",
+ },
+ {
+ Name: "tempo-blocks",
+ MountPath: "/var/tempo/blocks",
+ },
+ },
+ Ports: []corev1.ContainerPort{
+ {
+ Name: "http",
+ ContainerPort: 3200,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: "otlp-grpc",
+ ContainerPort: 4317,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ ReadinessProbe: manifestutils.TempoReadinessProbe(false),
+ SecurityContext: manifestutils.TempoContainerSecurityContext(),
+ },
+ },
+ Volumes: []corev1.Volume{
+ {
+ Name: "tempo-conf",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "tempo-sample",
+ },
+ },
+ },
+ },
+ {
+ Name: "tempo-wal",
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ Medium: corev1.StorageMediumMemory,
+ },
+ },
+ },
+ {
+ Name: "tempo-blocks",
+ VolumeSource: corev1.VolumeSource{
+ EmptyDir: &corev1.EmptyDirVolumeSource{
+ Medium: corev1.StorageMediumMemory,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }, sts)
+}
+
+func TestStatefulsetPVStorage(t *testing.T) {
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ Tempo: "docker.io/grafana/tempo:x.y.z",
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "pv",
+ WAL: &v1alpha1.MonolithicTracesStorageWALSpec{
+ Size: oneGBQuantity,
+ },
+ PV: &v1alpha1.MonolithicTracesStoragePVSpec{
+ Size: tenGBQuantity,
+ },
+ },
+ },
+ },
+ },
+ }
+ sts, err := BuildTempoStatefulset(opts)
+ require.NoError(t, err)
+
+ require.Equal(t, []corev1.VolumeMount{
+ {
+ Name: "tempo-conf",
+ MountPath: "/conf",
+ ReadOnly: true,
+ },
+ {
+ Name: "tempo-wal",
+ MountPath: "/var/tempo/wal",
+ },
+ {
+ Name: "tempo-blocks",
+ MountPath: "/var/tempo/blocks",
+ },
+ }, sts.Spec.Template.Spec.Containers[0].VolumeMounts)
+
+ require.Equal(t, []corev1.Volume{
+ {
+ Name: "tempo-conf",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "tempo-sample",
+ },
+ },
+ },
+ },
+ }, sts.Spec.Template.Spec.Volumes)
+
+ require.Equal(t, []corev1.PersistentVolumeClaim{
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tempo-wal",
+ },
+ Spec: corev1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceStorage: oneGBQuantity,
+ },
+ },
+ VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
+ },
+ },
+ {
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tempo-blocks",
+ },
+ Spec: corev1.PersistentVolumeClaimSpec{
+ AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
+ Resources: corev1.ResourceRequirements{
+ Requests: corev1.ResourceList{
+ corev1.ResourceStorage: tenGBQuantity,
+ },
+ },
+ VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
+ },
+ },
+ }, sts.Spec.VolumeClaimTemplates)
+}
+
+func TestStatefulsetPorts(t *testing.T) {
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ Tempo: "docker.io/grafana/tempo:x.y.z",
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ },
+ },
+ }
+
+ tests := []struct {
+ name string
+ input *v1alpha1.MonolithicIngestionSpec
+ expected []corev1.ContainerPort
+ }{
+ {
+ name: "no ingestion ports",
+ input: nil,
+ expected: []corev1.ContainerPort{
+ {
+ Name: "http",
+ ContainerPort: 3200,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ },
+ {
+ name: "OTLP/gRPC",
+ input: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ expected: []corev1.ContainerPort{
+ {
+ Name: "http",
+ ContainerPort: 3200,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: "otlp-grpc",
+ ContainerPort: 4317,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ },
+ {
+ name: "OTLP/HTTP",
+ input: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
+ },
+ },
+ expected: []corev1.ContainerPort{
+ {
+ Name: "http",
+ ContainerPort: 3200,
+ Protocol: corev1.ProtocolTCP,
+ },
+ {
+ Name: "otlp-http",
+ ContainerPort: 4318,
+ Protocol: corev1.ProtocolTCP,
+ },
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ opts.Tempo.Spec.Ingestion = test.input
+ sts, err := BuildTempoStatefulset(opts)
+ require.NoError(t, err)
+ require.Equal(t, test.expected, sts.Spec.Template.Spec.Containers[0].Ports)
+ })
+ }
+}
From 82fef56ccb477d0e6da4d4f763335148a733f5b5 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Mon, 8 Jan 2024 20:05:13 +0100
Subject: [PATCH 10/36] add service tests
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/manifestutils/constants.go | 2 +-
internal/manifests/monolithic/service_test.go | 177 ++++++++++++++++++
2 files changed, 178 insertions(+), 1 deletion(-)
create mode 100644 internal/manifests/monolithic/service_test.go
diff --git a/internal/manifests/manifestutils/constants.go b/internal/manifests/manifestutils/constants.go
index 0231d694d..481d915eb 100644
--- a/internal/manifests/manifestutils/constants.go
+++ b/internal/manifests/manifestutils/constants.go
@@ -43,7 +43,7 @@ const (
PortJaegerUI = 16686
// JaegerGRPCQuery declares the name of the Jaeger UI gPRC port.
- JaegerGRPCQuery = "jaeger-gprc"
+ JaegerGRPCQuery = "jaeger-grpc"
// PortJaegerGRPCQuery declares the port number of the Jaeger UI gPRC port.
PortJaegerGRPCQuery = 16685
diff --git a/internal/manifests/monolithic/service_test.go b/internal/manifests/monolithic/service_test.go
new file mode 100644
index 000000000..644a2f12a
--- /dev/null
+++ b/internal/manifests/monolithic/service_test.go
@@ -0,0 +1,177 @@
+package monolithic
+
+import (
+ "testing"
+
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/stretchr/testify/require"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
+)
+
+func TestBuildTempoApiService(t *testing.T) {
+ opts := Options{
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ },
+ }
+
+ svc := buildTempoApiService(opts)
+
+ labels := ComponentLabels("tempo", "sample")
+ require.Equal(t, &corev1.Service{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Service",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tempo-sample-api",
+ Namespace: "default",
+ Labels: labels,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{
+ {
+ Name: "http",
+ Protocol: corev1.ProtocolTCP,
+ Port: 3200,
+ TargetPort: intstr.FromString("http"),
+ },
+ },
+ Selector: labels,
+ },
+ }, svc)
+}
+
+func TestBuildTempoIngestService(t *testing.T) {
+ opts := Options{
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{},
+ },
+ }
+
+ tests := []struct {
+ name string
+ input *v1alpha1.MonolithicIngestionSpec
+ expected []corev1.ServicePort
+ }{
+ {
+ name: "no ingestion ports",
+ input: nil,
+ expected: []corev1.ServicePort{},
+ },
+ {
+ name: "OTLP/gRPC",
+ input: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ expected: []corev1.ServicePort{
+ {
+ Name: "otlp-grpc",
+ Protocol: corev1.ProtocolTCP,
+ Port: 4317,
+ TargetPort: intstr.FromString("otlp-grpc"),
+ },
+ },
+ },
+ {
+ name: "OTLP/HTTP",
+ input: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
+ },
+ },
+ expected: []corev1.ServicePort{
+ {
+ Name: "otlp-http",
+ Protocol: corev1.ProtocolTCP,
+ Port: 4318,
+ TargetPort: intstr.FromString("otlp-http"),
+ },
+ },
+ },
+ }
+
+ labels := ComponentLabels("tempo", "sample")
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ opts.Tempo.Spec.Ingestion = test.input
+ svc := buildTempoIngestService(opts)
+ require.Equal(t, &corev1.Service{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Service",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tempo-sample-ingest",
+ Namespace: "default",
+ Labels: labels,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: test.expected,
+ Selector: labels,
+ },
+ }, svc)
+ })
+ }
+}
+
+func TestBuildJaegerUIService(t *testing.T) {
+ opts := Options{
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ },
+ }
+
+ svc := buildJaegerUIService(opts)
+
+ labels := ComponentLabels("tempo", "sample")
+ require.Equal(t, &corev1.Service{
+ TypeMeta: metav1.TypeMeta{
+ APIVersion: "apps/v1",
+ Kind: "Service",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tempo-sample-jaegerui",
+ Namespace: "default",
+ Labels: labels,
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{
+ {
+ Name: "jaeger-grpc",
+ Port: 16685,
+ TargetPort: intstr.FromString("jaeger-grpc"),
+ },
+ {
+ Name: "jaeger-ui",
+ Port: 16686,
+ TargetPort: intstr.FromString("jaeger-ui"),
+ },
+ {
+ Name: "jaeger-metrics",
+ Port: 16687,
+ TargetPort: intstr.FromString("jaeger-metrics"),
+ },
+ },
+ Selector: labels,
+ },
+ }, svc)
+}
From 0f490ddbdc1bbf366dc2e697c1d301f56fabfb96 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Tue, 9 Jan 2024 17:51:37 +0100
Subject: [PATCH 11/36] add configmap tests
Signed-off-by: Andreas Gerstmayr
---
.../monolithic/{config.go => configmap.go} | 0
.../manifests/monolithic/configmap_test.go | 141 ++++++++++++++++++
2 files changed, 141 insertions(+)
rename internal/manifests/monolithic/{config.go => configmap.go} (100%)
create mode 100644 internal/manifests/monolithic/configmap_test.go
diff --git a/internal/manifests/monolithic/config.go b/internal/manifests/monolithic/configmap.go
similarity index 100%
rename from internal/manifests/monolithic/config.go
rename to internal/manifests/monolithic/configmap.go
diff --git a/internal/manifests/monolithic/configmap_test.go b/internal/manifests/monolithic/configmap_test.go
new file mode 100644
index 000000000..a7a2fa71a
--- /dev/null
+++ b/internal/manifests/monolithic/configmap_test.go
@@ -0,0 +1,141 @@
+package monolithic
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "testing"
+
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/stretchr/testify/require"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestBuildConfigMap(t *testing.T) {
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ Tempo: "docker.io/grafana/tempo:x.y.z",
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ Ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ },
+ },
+ }
+
+ cm, checksum, err := BuildConfigMap(opts)
+ require.NoError(t, err)
+ require.NotNil(t, cm.Data)
+ require.NotNil(t, cm.Data["tempo.yaml"])
+ require.Equal(t, fmt.Sprintf("%x", sha256.Sum256([]byte(cm.Data["tempo.yaml"]))), checksum)
+}
+
+func TestBuildConfig(t *testing.T) {
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ Tempo: "docker.io/grafana/tempo:x.y.z",
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{},
+ },
+ }
+
+ tests := []struct {
+ name string
+ storage v1alpha1.MonolithicStorageSpec
+ ingestion *v1alpha1.MonolithicIngestionSpec
+ expected string
+ }{
+ {
+ name: "memory storage",
+ storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ expected: `
+server:
+ http_listen_port: 3200
+storage:
+ trace:
+ backend: local
+ wal:
+ path: /var/tempo/wal
+ local:
+ path: /var/tempo/blocks
+distributor:
+ receivers:
+ otlp:
+ protocols: {}
+usage_report:
+ reporting_enabled: false
+`,
+ },
+ {
+ name: "PV storage with OTLP/gRPC and OTLP/HTTP",
+ storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "pv",
+ },
+ },
+ ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ },
+ },
+ expected: `
+server:
+ http_listen_port: 3200
+storage:
+ trace:
+ backend: local
+ wal:
+ path: /var/tempo/wal
+ local:
+ path: /var/tempo/blocks
+distributor:
+ receivers:
+ otlp:
+ protocols:
+ grpc: {}
+usage_report:
+ reporting_enabled: false
+`,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ opts.Tempo.Spec.Storage = test.storage
+ opts.Tempo.Spec.Ingestion = test.ingestion
+ cfg, err := buildTempoConfig(opts)
+ require.NoError(t, err)
+ require.YAMLEq(t, test.expected, string(cfg))
+ })
+ }
+}
From c84f6bd4c9ec2265a67c90ddc26c191b8d44ea6e Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 10 Jan 2024 20:09:03 +0100
Subject: [PATCH 12/36] use a single service, because the monolithic deployment
will use a single pod
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/monolithic/build.go | 4 +-
internal/manifests/monolithic/service.go | 108 +++--------
internal/manifests/monolithic/service_test.go | 172 ++++++++----------
3 files changed, 103 insertions(+), 181 deletions(-)
diff --git a/internal/manifests/monolithic/build.go b/internal/manifests/monolithic/build.go
index b65037d32..df13c49d5 100644
--- a/internal/manifests/monolithic/build.go
+++ b/internal/manifests/monolithic/build.go
@@ -21,8 +21,8 @@ func BuildAll(opts Options) ([]client.Object, error) {
}
manifests = append(manifests, statefulSet)
- services := BuildServices(opts)
- manifests = append(manifests, services...)
+ service := BuildTempoService(opts)
+ manifests = append(manifests, service)
return manifests, nil
}
diff --git a/internal/manifests/monolithic/service.go b/internal/manifests/monolithic/service.go
index e9a2d25c6..c41bec7ed 100644
--- a/internal/manifests/monolithic/service.go
+++ b/internal/manifests/monolithic/service.go
@@ -5,57 +5,24 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
- "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/grafana/tempo-operator/internal/manifests/manifestutils"
"github.com/grafana/tempo-operator/internal/manifests/naming"
)
-// BuildServices creates all services for a monolithic deployment.
-func BuildServices(opts Options) []client.Object {
- services := []client.Object{
- buildTempoApiService(opts),
- buildTempoIngestService(opts),
- }
-
- if opts.Tempo.Spec.JaegerUI != nil && opts.Tempo.Spec.JaegerUI.Enabled {
- services = append(services, buildJaegerUIService(opts))
- }
-
- return services
-}
-
-func buildTempoApiService(opts Options) *corev1.Service {
- labels := ComponentLabels("tempo", opts.Tempo.Name)
- return &corev1.Service{
- TypeMeta: metav1.TypeMeta{
- APIVersion: appsv1.SchemeGroupVersion.String(),
- Kind: "Service",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: naming.Name("api", opts.Tempo.Name),
- Namespace: opts.Tempo.Namespace,
- Labels: labels,
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
- {
- Name: manifestutils.HttpPortName,
- Protocol: corev1.ProtocolTCP,
- Port: manifestutils.PortHTTPServer,
- TargetPort: intstr.FromString(manifestutils.HttpPortName),
- },
- },
- Selector: labels,
+// BuildTempoService creates the service for a monolithic deployment.
+func BuildTempoService(opts Options) *corev1.Service {
+ tempo := opts.Tempo
+ labels := CommonLabels(opts.Tempo.Name)
+ ports := []corev1.ServicePort{
+ {
+ Name: manifestutils.HttpPortName,
+ Protocol: corev1.ProtocolTCP,
+ Port: manifestutils.PortHTTPServer,
+ TargetPort: intstr.FromString(manifestutils.HttpPortName),
},
}
-}
-func buildTempoIngestService(opts Options) *corev1.Service {
- tempo := opts.Tempo
- labels := ComponentLabels("tempo", tempo.Name)
-
- ports := []corev1.ServicePort{}
// TODO: point to gateway
if tempo.Spec.Ingestion != nil && tempo.Spec.Ingestion.OTLP != nil {
if tempo.Spec.Ingestion.OTLP.GRPC != nil && tempo.Spec.Ingestion.OTLP.GRPC.Enabled {
@@ -76,53 +43,38 @@ func buildTempoIngestService(opts Options) *corev1.Service {
}
}
- return &corev1.Service{
- TypeMeta: metav1.TypeMeta{
- APIVersion: appsv1.SchemeGroupVersion.String(),
- Kind: "Service",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: naming.Name("ingest", opts.Tempo.Name),
- Namespace: opts.Tempo.Namespace,
- Labels: labels,
- },
- Spec: corev1.ServiceSpec{
- Ports: ports,
- Selector: labels,
- },
+ if opts.Tempo.Spec.JaegerUI != nil && opts.Tempo.Spec.JaegerUI.Enabled {
+ ports = append(ports, []corev1.ServicePort{
+ {
+ Name: manifestutils.JaegerGRPCQuery,
+ Port: manifestutils.PortJaegerGRPCQuery,
+ TargetPort: intstr.FromString(manifestutils.JaegerGRPCQuery),
+ },
+ {
+ Name: manifestutils.JaegerUIPortName,
+ Port: manifestutils.PortJaegerUI,
+ TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
+ },
+ {
+ Name: manifestutils.JaegerMetricsPortName,
+ Port: manifestutils.PortJaegerMetrics,
+ TargetPort: intstr.FromString(manifestutils.JaegerMetricsPortName),
+ },
+ }...)
}
-}
-func buildJaegerUIService(opts Options) *corev1.Service {
- labels := ComponentLabels("tempo", opts.Tempo.Name)
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: appsv1.SchemeGroupVersion.String(),
Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
- Name: naming.Name("jaegerui", opts.Tempo.Name),
+ Name: naming.Name("", opts.Tempo.Name),
Namespace: opts.Tempo.Namespace,
Labels: labels,
},
Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
- {
- Name: manifestutils.JaegerGRPCQuery,
- Port: manifestutils.PortJaegerGRPCQuery,
- TargetPort: intstr.FromString(manifestutils.JaegerGRPCQuery),
- },
- {
- Name: manifestutils.JaegerUIPortName,
- Port: manifestutils.PortJaegerUI,
- TargetPort: intstr.FromString(manifestutils.JaegerUIPortName),
- },
- {
- Name: manifestutils.JaegerMetricsPortName,
- Port: manifestutils.PortJaegerMetrics,
- TargetPort: intstr.FromString(manifestutils.JaegerMetricsPortName),
- },
- },
+ Ports: ports,
Selector: labels,
},
}
diff --git a/internal/manifests/monolithic/service_test.go b/internal/manifests/monolithic/service_test.go
index 644a2f12a..6ad5d30f4 100644
--- a/internal/manifests/monolithic/service_test.go
+++ b/internal/manifests/monolithic/service_test.go
@@ -10,7 +10,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)
-func TestBuildTempoApiService(t *testing.T) {
+func TestBuildTempoService(t *testing.T) {
opts := Options{
Tempo: v1alpha1.TempoMonolithic{
ObjectMeta: metav1.ObjectMeta{
@@ -20,21 +20,15 @@ func TestBuildTempoApiService(t *testing.T) {
},
}
- svc := buildTempoApiService(opts)
-
- labels := ComponentLabels("tempo", "sample")
- require.Equal(t, &corev1.Service{
- TypeMeta: metav1.TypeMeta{
- APIVersion: "apps/v1",
- Kind: "Service",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "tempo-sample-api",
- Namespace: "default",
- Labels: labels,
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
+ tests := []struct {
+ name string
+ input v1alpha1.TempoMonolithicSpec
+ expected []corev1.ServicePort
+ }{
+ {
+ name: "no ingestion ports, no jaeger ui",
+ input: v1alpha1.TempoMonolithicSpec{},
+ expected: []corev1.ServicePort{
{
Name: "http",
Protocol: corev1.ProtocolTCP,
@@ -42,42 +36,25 @@ func TestBuildTempoApiService(t *testing.T) {
TargetPort: intstr.FromString("http"),
},
},
- Selector: labels,
- },
- }, svc)
-}
-
-func TestBuildTempoIngestService(t *testing.T) {
- opts := Options{
- Tempo: v1alpha1.TempoMonolithic{
- ObjectMeta: metav1.ObjectMeta{
- Name: "sample",
- Namespace: "default",
- },
- Spec: v1alpha1.TempoMonolithicSpec{},
- },
- }
-
- tests := []struct {
- name string
- input *v1alpha1.MonolithicIngestionSpec
- expected []corev1.ServicePort
- }{
- {
- name: "no ingestion ports",
- input: nil,
- expected: []corev1.ServicePort{},
},
{
- name: "OTLP/gRPC",
- input: &v1alpha1.MonolithicIngestionSpec{
- OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
- GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
- Enabled: true,
+ name: "ingest OTLP/gRPC",
+ input: v1alpha1.TempoMonolithicSpec{
+ Ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
},
},
},
expected: []corev1.ServicePort{
+ {
+ Name: "http",
+ Protocol: corev1.ProtocolTCP,
+ Port: 3200,
+ TargetPort: intstr.FromString("http"),
+ },
{
Name: "otlp-grpc",
Protocol: corev1.ProtocolTCP,
@@ -87,15 +64,23 @@ func TestBuildTempoIngestService(t *testing.T) {
},
},
{
- name: "OTLP/HTTP",
- input: &v1alpha1.MonolithicIngestionSpec{
- OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
- HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
- Enabled: true,
+ name: "ingest OTLP/HTTP",
+ input: v1alpha1.TempoMonolithicSpec{
+ Ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
},
},
},
expected: []corev1.ServicePort{
+ {
+ Name: "http",
+ Protocol: corev1.ProtocolTCP,
+ Port: 3200,
+ TargetPort: intstr.FromString("http"),
+ },
{
Name: "otlp-http",
Protocol: corev1.ProtocolTCP,
@@ -104,20 +89,51 @@ func TestBuildTempoIngestService(t *testing.T) {
},
},
},
+ {
+ name: "enable JaegerUI",
+ input: v1alpha1.TempoMonolithicSpec{
+ JaegerUI: &v1alpha1.MonolithicJaegerUISpec{
+ Enabled: true,
+ },
+ },
+ expected: []corev1.ServicePort{
+ {
+ Name: "http",
+ Protocol: corev1.ProtocolTCP,
+ Port: 3200,
+ TargetPort: intstr.FromString("http"),
+ },
+ {
+ Name: "jaeger-grpc",
+ Port: 16685,
+ TargetPort: intstr.FromString("jaeger-grpc"),
+ },
+ {
+ Name: "jaeger-ui",
+ Port: 16686,
+ TargetPort: intstr.FromString("jaeger-ui"),
+ },
+ {
+ Name: "jaeger-metrics",
+ Port: 16687,
+ TargetPort: intstr.FromString("jaeger-metrics"),
+ },
+ },
+ },
}
- labels := ComponentLabels("tempo", "sample")
+ labels := CommonLabels("sample")
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- opts.Tempo.Spec.Ingestion = test.input
- svc := buildTempoIngestService(opts)
+ opts.Tempo.Spec = test.input
+ svc := BuildTempoService(opts)
require.Equal(t, &corev1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: "apps/v1",
Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
- Name: "tempo-sample-ingest",
+ Name: "tempo-sample",
Namespace: "default",
Labels: labels,
},
@@ -129,49 +145,3 @@ func TestBuildTempoIngestService(t *testing.T) {
})
}
}
-
-func TestBuildJaegerUIService(t *testing.T) {
- opts := Options{
- Tempo: v1alpha1.TempoMonolithic{
- ObjectMeta: metav1.ObjectMeta{
- Name: "sample",
- Namespace: "default",
- },
- },
- }
-
- svc := buildJaegerUIService(opts)
-
- labels := ComponentLabels("tempo", "sample")
- require.Equal(t, &corev1.Service{
- TypeMeta: metav1.TypeMeta{
- APIVersion: "apps/v1",
- Kind: "Service",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "tempo-sample-jaegerui",
- Namespace: "default",
- Labels: labels,
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
- {
- Name: "jaeger-grpc",
- Port: 16685,
- TargetPort: intstr.FromString("jaeger-grpc"),
- },
- {
- Name: "jaeger-ui",
- Port: 16686,
- TargetPort: intstr.FromString("jaeger-ui"),
- },
- {
- Name: "jaeger-metrics",
- Port: 16687,
- TargetPort: intstr.FromString("jaeger-metrics"),
- },
- },
- Selector: labels,
- },
- }, svc)
-}
From bd54f6b508239f8fb94d83c2b43944403156d660 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 10 Jan 2024 20:11:57 +0100
Subject: [PATCH 13/36] drop component from labels
Signed-off-by: Andreas Gerstmayr
---
controllers/tempo/tempomonolithic_controller.go | 2 +-
internal/manifests/monolithic/configmap.go | 2 +-
internal/manifests/monolithic/labels.go | 13 ++-----------
internal/manifests/monolithic/service.go | 2 +-
internal/manifests/monolithic/service_test.go | 2 +-
internal/manifests/monolithic/statefulset.go | 2 +-
internal/manifests/monolithic/statefulset_test.go | 2 +-
7 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
index 69d9b72fe..a5b6f8a59 100644
--- a/controllers/tempo/tempomonolithic_controller.go
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -85,7 +85,7 @@ func (r *TempoMonolithicReconciler) getOwnedObjects(ctx context.Context, tempo v
ownedObjects := map[types.UID]client.Object{}
listOps := &client.ListOptions{
Namespace: tempo.GetNamespace(),
- LabelSelector: labels.SelectorFromSet(monolithic.CommonLabels(tempo.Name)),
+ LabelSelector: labels.SelectorFromSet(monolithic.Labels(tempo.Name)),
}
// Add all resources where the operator can conditionally create an object.
diff --git a/internal/manifests/monolithic/configmap.go b/internal/manifests/monolithic/configmap.go
index dec159dfb..da1035202 100644
--- a/internal/manifests/monolithic/configmap.go
+++ b/internal/manifests/monolithic/configmap.go
@@ -57,7 +57,7 @@ type tempoQueryConfig struct {
// BuildConfigMap creates the Tempo ConfigMap for a monolithic deployment.
func BuildConfigMap(opts Options) (*corev1.ConfigMap, string, error) {
tempo := opts.Tempo
- labels := ComponentLabels("config", tempo.Name)
+ labels := Labels(tempo.Name)
tempoConfig, err := buildTempoConfig(opts)
if err != nil {
diff --git a/internal/manifests/monolithic/labels.go b/internal/manifests/monolithic/labels.go
index cd191fa88..9469ba3ef 100644
--- a/internal/manifests/monolithic/labels.go
+++ b/internal/manifests/monolithic/labels.go
@@ -1,16 +1,7 @@
package monolithic
-import "k8s.io/apimachinery/pkg/labels"
-
-// ComponentLabels is a list of all commonLabels including the app.kubernetes.io/component: label.
-func ComponentLabels(component, instanceName string) labels.Set {
- return labels.Merge(CommonLabels(instanceName), map[string]string{
- "app.kubernetes.io/component": component,
- })
-}
-
-// CommonLabels returns common labels for each TempoMonolithic object created by the operator.
-func CommonLabels(instanceName string) map[string]string {
+// Labels returns common labels for each TempoMonolithic object created by the operator.
+func Labels(instanceName string) map[string]string {
return map[string]string{
"app.kubernetes.io/name": "tempo-monolithic",
"app.kubernetes.io/instance": instanceName,
diff --git a/internal/manifests/monolithic/service.go b/internal/manifests/monolithic/service.go
index c41bec7ed..4a3a2d202 100644
--- a/internal/manifests/monolithic/service.go
+++ b/internal/manifests/monolithic/service.go
@@ -13,7 +13,7 @@ import (
// BuildTempoService creates the service for a monolithic deployment.
func BuildTempoService(opts Options) *corev1.Service {
tempo := opts.Tempo
- labels := CommonLabels(opts.Tempo.Name)
+ labels := Labels(opts.Tempo.Name)
ports := []corev1.ServicePort{
{
Name: manifestutils.HttpPortName,
diff --git a/internal/manifests/monolithic/service_test.go b/internal/manifests/monolithic/service_test.go
index 6ad5d30f4..fdfb76589 100644
--- a/internal/manifests/monolithic/service_test.go
+++ b/internal/manifests/monolithic/service_test.go
@@ -122,7 +122,7 @@ func TestBuildTempoService(t *testing.T) {
},
}
- labels := CommonLabels("sample")
+ labels := Labels("sample")
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
opts.Tempo.Spec = test.input
diff --git a/internal/manifests/monolithic/statefulset.go b/internal/manifests/monolithic/statefulset.go
index 76036e0a3..2f3113a81 100644
--- a/internal/manifests/monolithic/statefulset.go
+++ b/internal/manifests/monolithic/statefulset.go
@@ -23,7 +23,7 @@ const (
// BuildTempoStatefulset creates the Tempo statefulset for a monolithic deployment.
func BuildTempoStatefulset(opts Options) (*appsv1.StatefulSet, error) {
tempo := opts.Tempo
- labels := ComponentLabels("tempo", tempo.Name)
+ labels := Labels(tempo.Name)
annotations := manifestutils.CommonAnnotations(opts.ConfigChecksum)
ss := &appsv1.StatefulSet{
diff --git a/internal/manifests/monolithic/statefulset_test.go b/internal/manifests/monolithic/statefulset_test.go
index 45ad0c27a..dc4ab81f1 100644
--- a/internal/manifests/monolithic/statefulset_test.go
+++ b/internal/manifests/monolithic/statefulset_test.go
@@ -51,7 +51,7 @@ func TestStatefulsetMemoryStorage(t *testing.T) {
sts, err := BuildTempoStatefulset(opts)
require.NoError(t, err)
- labels := ComponentLabels("tempo", "sample")
+ labels := Labels("sample")
annotations := manifestutils.CommonAnnotations("")
require.Equal(t, &appsv1.StatefulSet{
TypeMeta: metav1.TypeMeta{
From 8c66093f8005ab53ee0b3414862d4f29a3e71ccc Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 10 Jan 2024 20:23:05 +0100
Subject: [PATCH 14/36] fix configmap
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/monolithic/configmap.go | 18 ++++++++++--------
.../manifests/monolithic/configmap_test.go | 10 +++++-----
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/internal/manifests/monolithic/configmap.go b/internal/manifests/monolithic/configmap.go
index da1035202..6f44380cf 100644
--- a/internal/manifests/monolithic/configmap.go
+++ b/internal/manifests/monolithic/configmap.go
@@ -37,12 +37,12 @@ type tempoConfig struct {
Receivers struct {
OTLP struct {
Protocols struct {
- GRPC *struct{} `yaml:"grpc,omitempty"`
- HTTP *struct{} `yaml:"http,omitempty"`
- } `yaml:"protocols"`
- } `yaml:"otlp"`
- } `yaml:"receivers"`
- } `yaml:"distributor"`
+ GRPC *interface{} `yaml:"grpc,omitempty"`
+ HTTP *interface{} `yaml:"http,omitempty"`
+ } `yaml:"protocols,omitempty"`
+ } `yaml:"otlp,omitempty"`
+ } `yaml:"receivers,omitempty"`
+ } `yaml:"distributor,omitempty"`
UsageReport struct {
ReportingEnabled bool `yaml:"reporting_enabled"`
@@ -112,10 +112,12 @@ func buildTempoConfig(opts Options) ([]byte, error) {
if tempo.Spec.Ingestion != nil && tempo.Spec.Ingestion.OTLP != nil {
if tempo.Spec.Ingestion.OTLP.GRPC != nil && tempo.Spec.Ingestion.OTLP.GRPC.Enabled {
- config.Distributor.Receivers.OTLP.Protocols.GRPC = &struct{}{}
+ var i interface{}
+ config.Distributor.Receivers.OTLP.Protocols.GRPC = &i
}
if tempo.Spec.Ingestion.OTLP.HTTP != nil && tempo.Spec.Ingestion.OTLP.HTTP.Enabled {
- config.Distributor.Receivers.OTLP.Protocols.HTTP = &struct{}{}
+ var i interface{}
+ config.Distributor.Receivers.OTLP.Protocols.HTTP = &i
}
}
diff --git a/internal/manifests/monolithic/configmap_test.go b/internal/manifests/monolithic/configmap_test.go
index a7a2fa71a..28115af73 100644
--- a/internal/manifests/monolithic/configmap_test.go
+++ b/internal/manifests/monolithic/configmap_test.go
@@ -86,10 +86,6 @@ storage:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
-distributor:
- receivers:
- otlp:
- protocols: {}
usage_report:
reporting_enabled: false
`,
@@ -106,6 +102,9 @@ usage_report:
GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
Enabled: true,
},
+ HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
},
},
expected: `
@@ -122,7 +121,8 @@ distributor:
receivers:
otlp:
protocols:
- grpc: {}
+ grpc:
+ http:
usage_report:
reporting_enabled: false
`,
From 5874547286f70948fbf06deaf841f4d705568805 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 10 Jan 2024 20:26:47 +0100
Subject: [PATCH 15/36] TestBuildAll()
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/monolithic/build_test.go | 31 +++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 internal/manifests/monolithic/build_test.go
diff --git a/internal/manifests/monolithic/build_test.go b/internal/manifests/monolithic/build_test.go
new file mode 100644
index 000000000..943f2a961
--- /dev/null
+++ b/internal/manifests/monolithic/build_test.go
@@ -0,0 +1,31 @@
+package monolithic
+
+import (
+ "testing"
+
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/stretchr/testify/require"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestBuildAll(t *testing.T) {
+ opts := Options{
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: v1alpha1.TempoMonolithicSpec{
+ Storage: v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
+ },
+ },
+ },
+ }
+
+ objects, err := BuildAll(opts)
+ require.NoError(t, err)
+ require.Len(t, objects, 3)
+}
From 3b86d3afe337a2a6a7961aac741edd1e7e17108d Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 10 Jan 2024 20:44:04 +0100
Subject: [PATCH 16/36] add e2e test
Signed-off-by: Andreas Gerstmayr
---
tests/e2e/monolithic-smoketest/01-assert.yaml | 56 +++++++++++++++++++
.../01-install-tempo.yaml | 7 +++
tests/e2e/monolithic-smoketest/03-assert.yaml | 8 +++
.../03-generate-traces.yaml | 17 ++++++
tests/e2e/monolithic-smoketest/04-assert.yaml | 8 +++
.../04-verify-traces-jaeger.yaml | 36 ++++++++++++
tests/e2e/monolithic-smoketest/05-assert.yaml | 8 +++
.../05-verify-traces-grafana.yaml | 46 +++++++++++++++
8 files changed, 186 insertions(+)
create mode 100644 tests/e2e/monolithic-smoketest/01-assert.yaml
create mode 100644 tests/e2e/monolithic-smoketest/01-install-tempo.yaml
create mode 100644 tests/e2e/monolithic-smoketest/03-assert.yaml
create mode 100644 tests/e2e/monolithic-smoketest/03-generate-traces.yaml
create mode 100644 tests/e2e/monolithic-smoketest/04-assert.yaml
create mode 100644 tests/e2e/monolithic-smoketest/04-verify-traces-jaeger.yaml
create mode 100644 tests/e2e/monolithic-smoketest/05-assert.yaml
create mode 100644 tests/e2e/monolithic-smoketest/05-verify-traces-grafana.yaml
diff --git a/tests/e2e/monolithic-smoketest/01-assert.yaml b/tests/e2e/monolithic-smoketest/01-assert.yaml
new file mode 100644
index 000000000..2c50d42e4
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/01-assert.yaml
@@ -0,0 +1,56 @@
+apiVersion: tempo.grafana.com/v1alpha1
+kind: TempoMonolithic
+metadata:
+ name: simplest
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: tempo-simplest
+ labels:
+ app.kubernetes.io/instance: simplest
+ app.kubernetes.io/managed-by: tempo-operator
+ app.kubernetes.io/name: tempo-monolithic
+spec:
+ selector:
+ matchLabels:
+ app.kubernetes.io/instance: simplest
+ app.kubernetes.io/managed-by: tempo-operator
+ app.kubernetes.io/name: tempo-monolithic
+status:
+ readyReplicas: 1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app.kubernetes.io/instance: simplest
+ app.kubernetes.io/managed-by: tempo-operator
+ app.kubernetes.io/name: tempo-monolithic
+ name: tempo-simplest
+spec:
+ ports:
+ - name: http
+ port: 3200
+ protocol: TCP
+ targetPort: http
+ - name: otlp-grpc
+ port: 4317
+ protocol: TCP
+ targetPort: otlp-grpc
+ - name: jaeger-grpc
+ port: 16685
+ protocol: TCP
+ targetPort: jaeger-grpc
+ - name: jaeger-ui
+ port: 16686
+ protocol: TCP
+ targetPort: jaeger-ui
+ - name: jaeger-metrics
+ port: 16687
+ protocol: TCP
+ targetPort: jaeger-metrics
+ selector:
+ app.kubernetes.io/instance: simplest
+ app.kubernetes.io/managed-by: tempo-operator
+ app.kubernetes.io/name: tempo-monolithic
diff --git a/tests/e2e/monolithic-smoketest/01-install-tempo.yaml b/tests/e2e/monolithic-smoketest/01-install-tempo.yaml
new file mode 100644
index 000000000..7a3a5f84d
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/01-install-tempo.yaml
@@ -0,0 +1,7 @@
+apiVersion: tempo.grafana.com/v1alpha1
+kind: TempoMonolithic
+metadata:
+ name: simplest
+spec:
+ jaegerui:
+ enabled: true
diff --git a/tests/e2e/monolithic-smoketest/03-assert.yaml b/tests/e2e/monolithic-smoketest/03-assert.yaml
new file mode 100644
index 000000000..3f7323066
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/03-assert.yaml
@@ -0,0 +1,8 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: generate-traces
+status:
+ conditions:
+ - status: "True"
+ type: Complete
diff --git a/tests/e2e/monolithic-smoketest/03-generate-traces.yaml b/tests/e2e/monolithic-smoketest/03-generate-traces.yaml
new file mode 100644
index 000000000..87e2fbc76
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/03-generate-traces.yaml
@@ -0,0 +1,17 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: generate-traces
+spec:
+ template:
+ spec:
+ containers:
+ - name: telemetrygen
+ image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:v0.75.0
+ args:
+ - traces
+ - --otlp-endpoint=tempo-simplest:4317
+ - --otlp-insecure
+ - --traces=10
+ restartPolicy: Never
+ backoffLimit: 4
diff --git a/tests/e2e/monolithic-smoketest/04-assert.yaml b/tests/e2e/monolithic-smoketest/04-assert.yaml
new file mode 100644
index 000000000..ab9e98db3
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/04-assert.yaml
@@ -0,0 +1,8 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: verify-traces-jaeger
+status:
+ conditions:
+ - status: "True"
+ type: Complete
diff --git a/tests/e2e/monolithic-smoketest/04-verify-traces-jaeger.yaml b/tests/e2e/monolithic-smoketest/04-verify-traces-jaeger.yaml
new file mode 100644
index 000000000..8c1127424
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/04-verify-traces-jaeger.yaml
@@ -0,0 +1,36 @@
+# Simulate Jaeger Query API requests.
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: verify-traces-jaeger
+spec:
+ template:
+ spec:
+ containers:
+ - name: verify-traces-jaeger
+ image: ghcr.io/grafana/tempo-operator/test-utils:main
+ command:
+ - /bin/bash
+ - -eux
+ - -c
+ args:
+ - |
+ # The query frontend must be accessible via HTTP (no mTLS) to enable connections from Grafana
+ curl \
+ -v -G \
+ http://tempo-simplest:3200/api/search \
+ --data-urlencode "q={}" \
+ | tee /tmp/tempo.out
+ num_traces=$(jq ".traces | length" /tmp/tempo.out)
+ if [[ "$num_traces" -ne 10 ]]; then
+ echo && echo "The Tempo API returned $num_traces instead of 10 traces."
+ exit 1
+ fi
+
+ curl -v -G http://tempo-simplest:16686/api/traces --data-urlencode "service=telemetrygen" | tee /tmp/jaeger.out
+ num_traces=$(jq ".data | length" /tmp/jaeger.out)
+ if [[ "$num_traces" -ne 10 ]]; then
+ echo && echo "The Jaeger API returned $num_traces instead of 10 traces."
+ exit 1
+ fi
+ restartPolicy: Never
diff --git a/tests/e2e/monolithic-smoketest/05-assert.yaml b/tests/e2e/monolithic-smoketest/05-assert.yaml
new file mode 100644
index 000000000..7eec01bfb
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/05-assert.yaml
@@ -0,0 +1,8 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: verify-traces-grafana
+status:
+ conditions:
+ - status: "True"
+ type: Complete
diff --git a/tests/e2e/monolithic-smoketest/05-verify-traces-grafana.yaml b/tests/e2e/monolithic-smoketest/05-verify-traces-grafana.yaml
new file mode 100644
index 000000000..82c56c300
--- /dev/null
+++ b/tests/e2e/monolithic-smoketest/05-verify-traces-grafana.yaml
@@ -0,0 +1,46 @@
+# Simulate Grafana Dashboard API requests.
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: verify-traces-grafana
+spec:
+ template:
+ spec:
+ containers:
+ - name: verify-traces-grafana
+ image: registry.gitlab.com/gitlab-ci-utils/curl-jq:1.1.0
+ command:
+ - /bin/bash
+ - -eux
+ - -c
+ args:
+ - |
+ # Get the current Unix timestamp for "end" time, which is the current time
+ end_time=$(date -u +%s)
+
+ # Calculate "start" time by subtracting 24 hours (86400 seconds) from the "end" time
+ start_time=$((end_time - 86400))
+
+ # The query frontend must be accessible via HTTP (no mTLS) to enable connections from Grafana
+
+ # Run the curl command and capture the HTTP status code and output in a file
+ response_file=$(mktemp)
+ http_status=$(curl -s -o "$response_file" -w "%{http_code}" "http://tempo-simplest:3200/api/search?tags=%20service.name%3D%22telemetrygen%22%20name%3D%22okey-dokey%22&limit=20&start=$start_time&end=$end_time")
+
+ # Check the HTTP status code to detect API call failures
+ if [[ "$http_status" -ne 200 ]]; then
+ echo "API call failed with HTTP status code $http_status."
+ exit 1
+ fi
+
+ # Parse the JSON output from the file and check if the "traces" array is empty
+ output=$(cat "$response_file" | jq .)
+
+ if [[ "$(echo "$output" | jq -r '.traces | length')" -eq 0 ]]; then
+ echo "The Tempo API returned 0 Traces."
+ exit 1
+ else
+ echo "Traces found."
+ exit 0
+ fi
+ restartPolicy: Never
From 3faae98265bde66815feaf8c3193924cbe1ece9e Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 11 Jan 2024 13:44:51 +0100
Subject: [PATCH 17/36] drop defaulter webhook for TempoMonolithic
Signed-off-by: Andreas Gerstmayr
---
Makefile | 1 +
apis/tempo/v1alpha1/tempomonolithic_types.go | 2 +-
.../tempo/v1alpha1/tempomonolithic_webhook.go | 8 +++----
.../v1alpha1/tempomonolithic_webhook_test.go | 10 ++++-----
apis/tempo/v1alpha1/zz_generated.deepcopy.go | 6 ++++-
.../tempo-operator.clusterserviceversion.yaml | 22 +------------------
.../tempo-operator.clusterserviceversion.yaml | 22 +------------------
config/webhook/manifests.yaml | 20 -----------------
.../tempo/tempomonolithic_controller.go | 3 +++
internal/manifests/monolithic/build_test.go | 2 +-
.../manifests/monolithic/configmap_test.go | 8 +++----
.../manifests/monolithic/statefulset_test.go | 6 ++---
12 files changed, 29 insertions(+), 81 deletions(-)
diff --git a/Makefile b/Makefile
index d91fb91d9..073a3beb3 100644
--- a/Makefile
+++ b/Makefile
@@ -129,6 +129,7 @@ build: generate fmt ## Build manager binary.
run: manifests generate fmt ## Run a controller from your host.
# Disabled webhooks only affects local runs, not the build or in-cluster deployments.
@echo -e "\033[33mWebhooks are disabled! Use the normal deployment method to enable full operator functionality.\033[0m"
+ kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-validating-webhook-configuration
ENABLE_WEBHOOKS=false go run ./main.go start
.PHONY: docker-build
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 8215d6d1f..30d1791c0 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -11,7 +11,7 @@ type TempoMonolithicSpec struct {
// Storage defines the backend storage configuration
//
// +kubebuilder:validation:Optional
- Storage MonolithicStorageSpec `json:"storage,omitempty"`
+ Storage *MonolithicStorageSpec `json:"storage,omitempty"`
// Ingestion defines the trace ingestion configuration
//
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
index 683f1002d..18411e2f8 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -14,15 +14,15 @@ func (r *TempoMonolithic) SetupWebhookWithManager(mgr ctrl.Manager) error {
Complete()
}
-//+kubebuilder:webhook:path=/mutate-tempo-grafana-com-v1alpha1-tempomonolithic,mutating=true,failurePolicy=fail,sideEffects=None,groups=tempo.grafana.com,resources=tempomonolithics,verbs=create;update,versions=v1alpha1,name=mtempomonolithic.kb.io,admissionReviewVersions=v1
-
-var _ webhook.Defaulter = &TempoMonolithic{}
-
// Default implements webhook.Defaulter so a webhook will be registered for the type.
func (r *TempoMonolithic) Default() {
log := ctrl.Log.WithName("tempomonolithic-webhook")
log.V(1).Info("running defaulter webhook", "name", r.Name)
+ if r.Spec.Storage == nil {
+ r.Spec.Storage = &MonolithicStorageSpec{}
+ }
+
if r.Spec.Storage.Traces.Backend == "" {
r.Spec.Storage.Traces.Backend = MonolithicTracesStorageBackendMemory
}
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go b/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
index f0f4a7668..49ae4d72e 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
@@ -19,7 +19,7 @@ func TestMonolithicDefault(t *testing.T) {
},
expected: &TempoMonolithic{
Spec: TempoMonolithicSpec{
- Storage: MonolithicStorageSpec{
+ Storage: &MonolithicStorageSpec{
Traces: MonolithicTracesStorageSpec{
Backend: "memory",
},
@@ -38,7 +38,7 @@ func TestMonolithicDefault(t *testing.T) {
name: "set default values for PV",
input: &TempoMonolithic{
Spec: TempoMonolithicSpec{
- Storage: MonolithicStorageSpec{
+ Storage: &MonolithicStorageSpec{
Traces: MonolithicTracesStorageSpec{
Backend: "pv",
},
@@ -47,7 +47,7 @@ func TestMonolithicDefault(t *testing.T) {
},
expected: &TempoMonolithic{
Spec: TempoMonolithicSpec{
- Storage: MonolithicStorageSpec{
+ Storage: &MonolithicStorageSpec{
Traces: MonolithicTracesStorageSpec{
Backend: "pv",
WAL: &MonolithicTracesStorageWALSpec{
@@ -72,7 +72,7 @@ func TestMonolithicDefault(t *testing.T) {
name: "do not change already set values",
input: &TempoMonolithic{
Spec: TempoMonolithicSpec{
- Storage: MonolithicStorageSpec{
+ Storage: &MonolithicStorageSpec{
Traces: MonolithicTracesStorageSpec{
Backend: "s3",
WAL: &MonolithicTracesStorageWALSpec{
@@ -92,7 +92,7 @@ func TestMonolithicDefault(t *testing.T) {
},
expected: &TempoMonolithic{
Spec: TempoMonolithicSpec{
- Storage: MonolithicStorageSpec{
+ Storage: &MonolithicStorageSpec{
Traces: MonolithicTracesStorageSpec{
Backend: "s3",
WAL: &MonolithicTracesStorageWALSpec{
diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
index 48cbc8993..5807ebdbf 100644
--- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -1147,7 +1147,11 @@ func (in *TempoMonolithicList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TempoMonolithicSpec) DeepCopyInto(out *TempoMonolithicSpec) {
*out = *in
- in.Storage.DeepCopyInto(&out.Storage)
+ if in.Storage != nil {
+ in, out := &in.Storage, &out.Storage
+ *out = new(MonolithicStorageSpec)
+ (*in).DeepCopyInto(*out)
+ }
if in.Ingestion != nil {
in, out := &in.Ingestion, &out.Ingestion
*out = new(MonolithicIngestionSpec)
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 6e020dd7e..ee830dea9 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-08T18:44:24Z"
+ createdAt: "2024-01-10T20:43:08Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -1010,26 +1010,6 @@ spec:
name: tempo-gateway-opa
version: 0.6.0
webhookdefinitions:
- - admissionReviewVersions:
- - v1
- containerPort: 443
- deploymentName: tempo-operator-controller
- failurePolicy: Fail
- generateName: mtempomonolithic.kb.io
- rules:
- - apiGroups:
- - tempo.grafana.com
- apiVersions:
- - v1alpha1
- operations:
- - CREATE
- - UPDATE
- resources:
- - tempomonolithics
- sideEffects: None
- targetPort: 9443
- type: MutatingAdmissionWebhook
- webhookPath: /mutate-tempo-grafana-com-v1alpha1-tempomonolithic
- admissionReviewVersions:
- v1
containerPort: 443
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index b07d5fc64..13e58e248 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-08T18:44:22Z"
+ createdAt: "2024-01-10T20:43:07Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -1021,26 +1021,6 @@ spec:
name: tempo-gateway-opa
version: 0.6.0
webhookdefinitions:
- - admissionReviewVersions:
- - v1
- containerPort: 443
- deploymentName: tempo-operator-controller
- failurePolicy: Fail
- generateName: mtempomonolithic.kb.io
- rules:
- - apiGroups:
- - tempo.grafana.com
- apiVersions:
- - v1alpha1
- operations:
- - CREATE
- - UPDATE
- resources:
- - tempomonolithics
- sideEffects: None
- targetPort: 9443
- type: MutatingAdmissionWebhook
- webhookPath: /mutate-tempo-grafana-com-v1alpha1-tempomonolithic
- admissionReviewVersions:
- v1
containerPort: 443
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
index 5ec8c2305..b51b201fb 100644
--- a/config/webhook/manifests.yaml
+++ b/config/webhook/manifests.yaml
@@ -5,26 +5,6 @@ metadata:
creationTimestamp: null
name: mutating-webhook-configuration
webhooks:
-- admissionReviewVersions:
- - v1
- clientConfig:
- service:
- name: webhook-service
- namespace: system
- path: /mutate-tempo-grafana-com-v1alpha1-tempomonolithic
- failurePolicy: Fail
- name: mtempomonolithic.kb.io
- rules:
- - apiGroups:
- - tempo.grafana.com
- apiVersions:
- - v1alpha1
- operations:
- - CREATE
- - UPDATE
- resources:
- - tempomonolithics
- sideEffects: None
- admissionReviewVersions:
- v1
clientConfig:
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
index a5b6f8a59..9f2240c5a 100644
--- a/controllers/tempo/tempomonolithic_controller.go
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -55,6 +55,9 @@ func (r *TempoMonolithicReconciler) Reconcile(ctx context.Context, req ctrl.Requ
return ctrl.Result{}, nil
}
+ // apply defaults
+ tempo.Default()
+
if tempo.Spec.Management == v1alpha1.ManagementStateUnmanaged {
log.Info("Skipping reconciliation for unmanaged TempoMonolithic resource", "name", req.String())
return ctrl.Result{}, nil
diff --git a/internal/manifests/monolithic/build_test.go b/internal/manifests/monolithic/build_test.go
index 943f2a961..43844425a 100644
--- a/internal/manifests/monolithic/build_test.go
+++ b/internal/manifests/monolithic/build_test.go
@@ -16,7 +16,7 @@ func TestBuildAll(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.TempoMonolithicSpec{
- Storage: v1alpha1.MonolithicStorageSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "memory",
},
diff --git a/internal/manifests/monolithic/configmap_test.go b/internal/manifests/monolithic/configmap_test.go
index 28115af73..ffc81771e 100644
--- a/internal/manifests/monolithic/configmap_test.go
+++ b/internal/manifests/monolithic/configmap_test.go
@@ -24,7 +24,7 @@ func TestBuildConfigMap(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.TempoMonolithicSpec{
- Storage: v1alpha1.MonolithicStorageSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "memory",
},
@@ -65,13 +65,13 @@ func TestBuildConfig(t *testing.T) {
tests := []struct {
name string
- storage v1alpha1.MonolithicStorageSpec
+ storage *v1alpha1.MonolithicStorageSpec
ingestion *v1alpha1.MonolithicIngestionSpec
expected string
}{
{
name: "memory storage",
- storage: v1alpha1.MonolithicStorageSpec{
+ storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "memory",
},
@@ -92,7 +92,7 @@ usage_report:
},
{
name: "PV storage with OTLP/gRPC and OTLP/HTTP",
- storage: v1alpha1.MonolithicStorageSpec{
+ storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "pv",
},
diff --git a/internal/manifests/monolithic/statefulset_test.go b/internal/manifests/monolithic/statefulset_test.go
index dc4ab81f1..897129903 100644
--- a/internal/manifests/monolithic/statefulset_test.go
+++ b/internal/manifests/monolithic/statefulset_test.go
@@ -33,7 +33,7 @@ func TestStatefulsetMemoryStorage(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.TempoMonolithicSpec{
- Storage: v1alpha1.MonolithicStorageSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "memory",
},
@@ -163,7 +163,7 @@ func TestStatefulsetPVStorage(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.TempoMonolithicSpec{
- Storage: v1alpha1.MonolithicStorageSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "pv",
WAL: &v1alpha1.MonolithicTracesStorageWALSpec{
@@ -254,7 +254,7 @@ func TestStatefulsetPorts(t *testing.T) {
Namespace: "default",
},
Spec: v1alpha1.TempoMonolithicSpec{
- Storage: v1alpha1.MonolithicStorageSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
Traces: v1alpha1.MonolithicTracesStorageSpec{
Backend: "memory",
},
From a027746bd035d84fbccdcdc859cf2e233b85fb99 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 11 Jan 2024 15:01:32 +0100
Subject: [PATCH 18/36] delete operator namespace and webhooks in make run
Signed-off-by: Andreas Gerstmayr
---
Makefile | 7 ++++++-
env | 4 ++++
2 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 env
diff --git a/Makefile b/Makefile
index 073a3beb3..4cb4ebc94 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,6 @@
+include env
+export $(shell sed 's/=.*//' env)
+
# Current Operator version
VERSION_DATE ?= $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
VERSION_PKG ?= github.com/grafana/tempo-operator/internal/version
@@ -129,7 +132,9 @@ build: generate fmt ## Build manager binary.
run: manifests generate fmt ## Run a controller from your host.
# Disabled webhooks only affects local runs, not the build or in-cluster deployments.
@echo -e "\033[33mWebhooks are disabled! Use the normal deployment method to enable full operator functionality.\033[0m"
- kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-validating-webhook-configuration
+ -kubectl delete ns $(OPERATOR_NAMESPACE)
+ -kubectl delete mutatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-mutating-webhook-configuration
+ -kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-validating-webhook-configuration
ENABLE_WEBHOOKS=false go run ./main.go start
.PHONY: docker-build
diff --git a/env b/env
new file mode 100644
index 000000000..94de74570
--- /dev/null
+++ b/env
@@ -0,0 +1,4 @@
+RELATED_IMAGE_TEMPO=docker.io/grafana/tempo:2.3.0
+RELATED_IMAGE_TEMPO_QUERY=docker.io/grafana/tempo-query:2.3.0
+RELATED_IMAGE_TEMPO_GATEWAY=quay.io/observatorium/api:main-2023-11-20-81f8fdf
+RELATED_IMAGE_TEMPO_GATEWAY_OPA=quay.io/observatorium/opa-openshift:main-2023-10-13-13d8960
From 19d6e07e9763158522ec45060400a2c1764d074a Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 11 Jan 2024 17:36:26 +0100
Subject: [PATCH 19/36] change the way to include .env file
Signed-off-by: Andreas Gerstmayr
---
env => .env | 0
Makefile | 5 +----
2 files changed, 1 insertion(+), 4 deletions(-)
rename env => .env (100%)
mode change 100644 => 100755
diff --git a/env b/.env
old mode 100644
new mode 100755
similarity index 100%
rename from env
rename to .env
diff --git a/Makefile b/Makefile
index 87e6633c5..8ead9162f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,3 @@
-include env
-export $(shell sed 's/=.*//' env)
-
# Current Operator version
VERSION_DATE ?= $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
VERSION_PKG ?= github.com/grafana/tempo-operator/internal/version
@@ -135,7 +132,7 @@ run: manifests generate fmt ## Run a controller from your host.
-kubectl delete ns $(OPERATOR_NAMESPACE)
-kubectl delete mutatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-mutating-webhook-configuration
-kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-validating-webhook-configuration
- ENABLE_WEBHOOKS=false go run ./main.go start
+ set -a && . .env && ENABLE_WEBHOOKS=false go run ./main.go start
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
From f29369f82ad42ebe7aa3dda03b5cd76f7f815f12 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 11 Jan 2024 17:55:13 +0100
Subject: [PATCH 20/36] rebuild bundle, fix linter
Signed-off-by: Andreas Gerstmayr
---
.../tempo-operator.clusterserviceversion.yaml | 20 +++++++++++--------
.../tempo-operator.clusterserviceversion.yaml | 20 +++++++++++--------
docs/spec/tempomonolithic.yaml | 5 ++---
internal/manifests/monolithic/build_test.go | 3 ++-
.../manifests/monolithic/configmap_test.go | 5 +++--
internal/manifests/monolithic/service_test.go | 3 ++-
.../manifests/monolithic/statefulset_test.go | 7 ++++---
7 files changed, 37 insertions(+), 26 deletions(-)
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index ee830dea9..2566a66d3 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-10T20:43:08Z"
+ createdAt: "2024-01-11T16:44:31Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -65,7 +65,7 @@ metadata:
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
repository: https://github.com/grafana/tempo-operator
support: Grafana Tempo Operator SIG
- name: tempo-operator.v0.6.0
+ name: tempo-operator.v0.7.0
namespace: placeholder
spec:
apiservicedefinitions: {}
@@ -106,6 +106,10 @@ spec:
name: ""
version: v1
specDescriptors:
+ - displayName: Extra Configurations
+ path: extraConfig
+ - displayName: Tempo Extra Configurations
+ path: extraConfig.tempo
- description: HashRing defines the spec for the distributed hash ring configuration.
displayName: Hash Ring
path: hashRing
@@ -856,14 +860,14 @@ spec:
- --config=controller_manager_config.yaml
env:
- name: RELATED_IMAGE_TEMPO
- value: docker.io/grafana/tempo:2.3.0
+ value: docker.io/grafana/tempo:2.3.1
- name: RELATED_IMAGE_TEMPO_QUERY
- value: docker.io/grafana/tempo-query:2.3.0
+ value: docker.io/grafana/tempo-query:2.3.1
- name: RELATED_IMAGE_TEMPO_GATEWAY
value: quay.io/observatorium/api:main-2023-11-20-81f8fdf
- name: RELATED_IMAGE_TEMPO_GATEWAY_OPA
value: quay.io/observatorium/opa-openshift:main-2023-10-13-13d8960
- image: ghcr.io/grafana/tempo-operator/tempo-operator:v0.6.0
+ image: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
livenessProbe:
httpGet:
path: /healthz
@@ -1000,15 +1004,15 @@ spec:
provider:
name: Grafana Tempo Operator SIG
relatedImages:
- - image: docker.io/grafana/tempo:2.3.0
+ - image: docker.io/grafana/tempo:2.3.1
name: tempo
- - image: docker.io/grafana/tempo-query:2.3.0
+ - image: docker.io/grafana/tempo-query:2.3.1
name: tempo-query
- image: quay.io/observatorium/api:main-2023-11-20-81f8fdf
name: tempo-gateway
- image: quay.io/observatorium/opa-openshift:main-2023-10-13-13d8960
name: tempo-gateway-opa
- version: 0.6.0
+ version: 0.7.0
webhookdefinitions:
- admissionReviewVersions:
- v1
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index 13e58e248..f08a89369 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-10T20:43:07Z"
+ createdAt: "2024-01-11T16:44:29Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -65,7 +65,7 @@ metadata:
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
repository: https://github.com/grafana/tempo-operator
support: Grafana Tempo Operator SIG
- name: tempo-operator.v0.6.0
+ name: tempo-operator.v0.7.0
namespace: placeholder
spec:
apiservicedefinitions: {}
@@ -106,6 +106,10 @@ spec:
name: ""
version: v1
specDescriptors:
+ - displayName: Extra Configurations
+ path: extraConfig
+ - displayName: Tempo Extra Configurations
+ path: extraConfig.tempo
- description: HashRing defines the spec for the distributed hash ring configuration.
displayName: Hash Ring
path: hashRing
@@ -856,14 +860,14 @@ spec:
- --config=controller_manager_config.yaml
env:
- name: RELATED_IMAGE_TEMPO
- value: docker.io/grafana/tempo:2.3.0
+ value: docker.io/grafana/tempo:2.3.1
- name: RELATED_IMAGE_TEMPO_QUERY
- value: docker.io/grafana/tempo-query:2.3.0
+ value: docker.io/grafana/tempo-query:2.3.1
- name: RELATED_IMAGE_TEMPO_GATEWAY
value: quay.io/observatorium/api:main-2023-11-20-81f8fdf
- name: RELATED_IMAGE_TEMPO_GATEWAY_OPA
value: quay.io/observatorium/opa-openshift:main-2023-10-13-13d8960
- image: ghcr.io/grafana/tempo-operator/tempo-operator:v0.6.0
+ image: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
livenessProbe:
httpGet:
path: /healthz
@@ -1011,15 +1015,15 @@ spec:
provider:
name: Grafana Tempo Operator SIG
relatedImages:
- - image: docker.io/grafana/tempo:2.3.0
+ - image: docker.io/grafana/tempo:2.3.1
name: tempo
- - image: docker.io/grafana/tempo-query:2.3.0
+ - image: docker.io/grafana/tempo-query:2.3.1
name: tempo-query
- image: quay.io/observatorium/api:main-2023-11-20-81f8fdf
name: tempo-gateway
- image: quay.io/observatorium/opa-openshift:main-2023-10-13-13d8960
name: tempo-gateway-opa
- version: 0.6.0
+ version: 0.7.0
webhookdefinitions:
- admissionReviewVersions:
- v1
diff --git a/docs/spec/tempomonolithic.yaml b/docs/spec/tempomonolithic.yaml
index 6a53a8c77..bdbf9c1fa 100644
--- a/docs/spec/tempomonolithic.yaml
+++ b/docs/spec/tempomonolithic.yaml
@@ -8,9 +8,9 @@ spec: # TempoMonolithicSpec defines the desir
ingestion: # Ingestion defines the trace ingestion configuration
otlp: # OTLP defines the ingestion configuration for OTLP
grpc: # GRPC defines the OTLP/gRPC configuration
- enabled: false # Enabled defines if the OTLP over gRPC is enabled
+ enabled: false # Enabled defines if OTLP over gRPC is enabled
http: # HTTP defines the OTLP/HTTP configuration
- enabled: false # Enabled defines if the OTLP over HTTP is enabled
+ enabled: false # Enabled defines if OTLP over HTTP is enabled
tls: # TLS defines the TLS configuration for ingestion
ca: "" # CA defines the name of a secret containing the CA certificate
cert: "" # Cert defines the name of a secret containing the TLS certificate and private key
@@ -33,7 +33,6 @@ spec: # TempoMonolithicSpec defines the desir
backend: "" # Backend defines the backend for storing traces
pv: # PV defines the Persistent Volume configuration
size: 1Gi # Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
- secret: "" # Secret defines name of a secret containing the credentials for accessing the specified backend storage
wal: # WAL defines the write-ahead logging (WAL) configuration
size: 1Gi # Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
status: # TempoMonolithicStatus defines the observed state of TempoMonolithic.
diff --git a/internal/manifests/monolithic/build_test.go b/internal/manifests/monolithic/build_test.go
index 43844425a..781ecc78e 100644
--- a/internal/manifests/monolithic/build_test.go
+++ b/internal/manifests/monolithic/build_test.go
@@ -3,9 +3,10 @@ package monolithic
import (
"testing"
- "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
)
func TestBuildAll(t *testing.T) {
diff --git a/internal/manifests/monolithic/configmap_test.go b/internal/manifests/monolithic/configmap_test.go
index ffc81771e..ec24d1c17 100644
--- a/internal/manifests/monolithic/configmap_test.go
+++ b/internal/manifests/monolithic/configmap_test.go
@@ -5,10 +5,11 @@ import (
"fmt"
"testing"
- configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
- "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
)
func TestBuildConfigMap(t *testing.T) {
diff --git a/internal/manifests/monolithic/service_test.go b/internal/manifests/monolithic/service_test.go
index fdfb76589..9e2bbfe7a 100644
--- a/internal/manifests/monolithic/service_test.go
+++ b/internal/manifests/monolithic/service_test.go
@@ -3,11 +3,12 @@ package monolithic
import (
"testing"
- "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
+
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
)
func TestBuildTempoService(t *testing.T) {
diff --git a/internal/manifests/monolithic/statefulset_test.go b/internal/manifests/monolithic/statefulset_test.go
index 897129903..53698e8fd 100644
--- a/internal/manifests/monolithic/statefulset_test.go
+++ b/internal/manifests/monolithic/statefulset_test.go
@@ -3,9 +3,6 @@ package monolithic
import (
"testing"
- configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
- "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
- "github.com/grafana/tempo-operator/internal/manifests/manifestutils"
"github.com/operator-framework/operator-lib/proxy"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
@@ -13,6 +10,10 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
+
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ "github.com/grafana/tempo-operator/internal/manifests/manifestutils"
)
var (
From f0c9ffc1192122de3edd9fec22419e9cbb5126a8 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 11 Jan 2024 18:39:38 +0100
Subject: [PATCH 21/36] fix typo in jaeger-grpc port name
Signed-off-by: Andreas Gerstmayr
---
tests/e2e-openshift/monitoring/02-assert.yaml | 4 ++--
tests/e2e/compatibility/01-assert.yaml | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/tests/e2e-openshift/monitoring/02-assert.yaml b/tests/e2e-openshift/monitoring/02-assert.yaml
index 8da18ae97..d221c4bc9 100644
--- a/tests/e2e-openshift/monitoring/02-assert.yaml
+++ b/tests/e2e-openshift/monitoring/02-assert.yaml
@@ -75,10 +75,10 @@ spec:
port: 9095
protocol: TCP
targetPort: grpc
- - name: jaeger-gprc
+ - name: jaeger-grpc
port: 16685
protocol: TCP
- targetPort: jaeger-gprc
+ targetPort: jaeger-grpc
- name: jaeger-ui
port: 16686
protocol: TCP
diff --git a/tests/e2e/compatibility/01-assert.yaml b/tests/e2e/compatibility/01-assert.yaml
index a7b1fdea0..56d28738b 100644
--- a/tests/e2e/compatibility/01-assert.yaml
+++ b/tests/e2e/compatibility/01-assert.yaml
@@ -291,10 +291,10 @@ spec:
port: 9095
protocol: TCP
targetPort: grpc
- - name: jaeger-gprc
+ - name: jaeger-grpc
port: 16685
protocol: TCP
- targetPort: jaeger-gprc
+ targetPort: jaeger-grpc
- name: jaeger-ui
port: 16686
protocol: TCP
@@ -334,10 +334,10 @@ spec:
port: 9096
protocol: TCP
targetPort: grpclb
- - name: jaeger-gprc
+ - name: jaeger-grpc
port: 16685
protocol: TCP
- targetPort: jaeger-gprc
+ targetPort: jaeger-grpc
- name: jaeger-ui
port: 16686
protocol: TCP
From c0343f123c0c037277bf9ff3b346e8bea5bddda2 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Mon, 15 Jan 2024 19:17:32 +0100
Subject: [PATCH 22/36] add warning when overriding tempo config
Signed-off-by: Andreas Gerstmayr
---
Makefile | 2 +-
.../tempo/v1alpha1/tempomonolithic_webhook.go | 22 ++++++++++++++-----
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile
index 8ead9162f..4d53838c0 100644
--- a/Makefile
+++ b/Makefile
@@ -132,7 +132,7 @@ run: manifests generate fmt ## Run a controller from your host.
-kubectl delete ns $(OPERATOR_NAMESPACE)
-kubectl delete mutatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-mutating-webhook-configuration
-kubectl delete validatingwebhookconfigurations.admissionregistration.k8s.io tempo-operator-validating-webhook-configuration
- set -a && . .env && ENABLE_WEBHOOKS=false go run ./main.go start
+ set -a && . .env && ENABLE_WEBHOOKS=false go run ./main.go --zap-log-level=info start
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
index 18411e2f8..3947202d1 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -1,7 +1,9 @@
package v1alpha1
import (
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
@@ -16,9 +18,6 @@ func (r *TempoMonolithic) SetupWebhookWithManager(mgr ctrl.Manager) error {
// Default implements webhook.Defaulter so a webhook will be registered for the type.
func (r *TempoMonolithic) Default() {
- log := ctrl.Log.WithName("tempomonolithic-webhook")
- log.V(1).Info("running defaulter webhook", "name", r.Name)
-
if r.Spec.Storage == nil {
r.Spec.Storage = &MonolithicStorageSpec{}
}
@@ -70,8 +69,19 @@ func (r *TempoMonolithic) ValidateDelete() (admission.Warnings, error) {
return r.validate()
}
-func (r *TempoMonolithic) validate() (admission.Warnings, error) {
+func (tempo *TempoMonolithic) validate() (admission.Warnings, error) {
log := ctrl.Log.WithName("tempomonolithic-webhook")
- log.V(1).Info("running validating webhook", "name", r.Name)
- return nil, nil
+ log.V(1).Info("running validating webhook", "name", tempo.Name)
+
+ allWarnings := admission.Warnings{}
+ allErrors := field.ErrorList{}
+
+ if tempo.Spec.ExtraConfig != nil && len(tempo.Spec.ExtraConfig.Tempo.Raw) > 0 {
+ allWarnings = append(allWarnings, "overriding Tempo configuration could potentially break the deployment, use it carefully")
+ }
+
+ if len(allErrors) == 0 {
+ return allWarnings, nil
+ }
+ return allWarnings, apierrors.NewInvalid(tempo.GroupVersionKind().GroupKind(), tempo.Name, allErrors)
}
From 0c9b6e66a76d2acb395b78b390adca82df6e1a2d Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Tue, 16 Jan 2024 12:53:03 +0100
Subject: [PATCH 23/36] specify default value of storage.traces.backend
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_types.go | 1 +
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 1 +
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 1 +
.../tempo.grafana.com_tempomonolithics.yaml | 1 +
docs/spec/tempomonolithic.yaml | 38 -------------------
7 files changed, 6 insertions(+), 40 deletions(-)
delete mode 100644 docs/spec/tempomonolithic.yaml
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 30d1791c0..35da682b5 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -52,6 +52,7 @@ type MonolithicTracesStorageSpec struct {
// Backend defines the backend for storing traces
//
// +kubebuilder:validation:Required
+ // +kubebuilder:default=memory
Backend MonolithicTracesStorageBackend `json:"backend"`
// WAL defines the write-ahead logging (WAL) configuration
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 2566a66d3..b92b974cf 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-11T16:44:31Z"
+ createdAt: "2024-01-16T11:52:12Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
index a725edd00..f338fcd21 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -170,6 +170,7 @@ spec:
for traces
properties:
backend:
+ default: memory
description: Backend defines the backend for storing traces
enum:
- memory
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index f08a89369..214db9f84 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-11T16:44:29Z"
+ createdAt: "2024-01-16T11:52:11Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
index a725edd00..f338fcd21 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -170,6 +170,7 @@ spec:
for traces
properties:
backend:
+ default: memory
description: Backend defines the backend for storing traces
enum:
- memory
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
index 9dc254f55..c4209d910 100644
--- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -167,6 +167,7 @@ spec:
for traces
properties:
backend:
+ default: memory
description: Backend defines the backend for storing traces
enum:
- memory
diff --git a/docs/spec/tempomonolithic.yaml b/docs/spec/tempomonolithic.yaml
deleted file mode 100644
index bdbf9c1fa..000000000
--- a/docs/spec/tempomonolithic.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-apiVersion: tempo.grafana.com/v1alpha1 # APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
-kind: TempoMonolithic # Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
-metadata:
- name: example
-spec: # TempoMonolithicSpec defines the desired state of TempoMonolithic.
- extraConfig: # ExtraConfig defines any extra (overlay) configuration for components
- tempo: {} # Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
- ingestion: # Ingestion defines the trace ingestion configuration
- otlp: # OTLP defines the ingestion configuration for OTLP
- grpc: # GRPC defines the OTLP/gRPC configuration
- enabled: false # Enabled defines if OTLP over gRPC is enabled
- http: # HTTP defines the OTLP/HTTP configuration
- enabled: false # Enabled defines if OTLP over HTTP is enabled
- tls: # TLS defines the TLS configuration for ingestion
- ca: "" # CA defines the name of a secret containing the CA certificate
- cert: "" # Cert defines the name of a secret containing the TLS certificate and private key
- enabled: false # Enabled defines if TLS is enabled for ingestion
- jaegerui: # JaegerUI defines the Jaeger UI configuration
- enabled: false # Enabled defines if the Jaeger UI should be enabled
- ingress: # Ingress defines the ingress configuration for Jaeger UI
- enabled: false # Enabled defines if an Ingress object should be created for Jaeger UI
- route: # Route defines the route configuration for Jaeger UI
- enabled: false # Enabled defines if a Route object should be created for Jaeger UI
- management: "" # ManagementState defines whether this instance is managed by the operator or self-managed
- observability: # Observability defines observability configuration for the Tempo deployment
- metrics: # Metrics defines the metrics configuration of the Tempo deployment
- prometheusRules: # ServiceMonitors defines the PrometheusRule configuration
- enabled: false # Enabled defines if the operator should create PrometheusRules for this Tempo deployment
- serviceMonitors: # ServiceMonitors defines the ServiceMonitor configuration
- enabled: false # Enabled defines if the operator should create ServiceMonitors for this Tempo deployment
- storage: # Storage defines the backend storage configuration
- traces: # Traces defines the backend storage configuration for traces
- backend: "" # Backend defines the backend for storing traces
- pv: # PV defines the Persistent Volume configuration
- size: 1Gi # Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
- wal: # WAL defines the write-ahead logging (WAL) configuration
- size: 1Gi # Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
-status: # TempoMonolithicStatus defines the observed state of TempoMonolithic.
From fd37ff8dd5d1c8d53b23d8ca1316322f7daed6f5 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 17 Jan 2024 15:13:43 +0100
Subject: [PATCH 24/36] update storage docs
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_types.go | 6 +++---
.../manifests/tempo-operator.clusterserviceversion.yaml | 2 +-
.../manifests/tempo.grafana.com_tempomonolithics.yaml | 3 ++-
.../manifests/tempo-operator.clusterserviceversion.yaml | 2 +-
.../manifests/tempo.grafana.com_tempomonolithics.yaml | 3 ++-
config/crd/bases/tempo.grafana.com_tempomonolithics.yaml | 3 ++-
docs/operator/api.md | 6 +++---
7 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 35da682b5..1043b8d5b 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -49,7 +49,7 @@ type MonolithicStorageSpec struct {
// MonolithicTracesStorageSpec defines the traces storage for the Tempo deployment.
type MonolithicTracesStorageSpec struct {
- // Backend defines the backend for storing traces
+ // Backend defines the backend for storing traces. Default: memory
//
// +kubebuilder:validation:Required
// +kubebuilder:default=memory
@@ -72,9 +72,9 @@ type MonolithicTracesStorageSpec struct {
type MonolithicTracesStorageBackend string
const (
- // MonolithicTracesStorageBackendMemory specifies a in-memory storage backend.
+ // MonolithicTracesStorageBackendMemory defines storing traces in a tmpfs (in-memory filesystem).
MonolithicTracesStorageBackendMemory MonolithicTracesStorageBackend = "memory"
- // MonolithicTracesStorageBackendPersistentVolume specifies a Persistent Volume storage backend.
+ // MonolithicTracesStorageBackendPersistentVolume defines storing traces in a Persistent Volume.
MonolithicTracesStorageBackendPersistentVolume MonolithicTracesStorageBackend = "pv"
)
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index b92b974cf..ac82af739 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-16T11:52:12Z"
+ createdAt: "2024-01-17T14:13:24Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
index f338fcd21..3e5a76f3a 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -171,7 +171,8 @@ spec:
properties:
backend:
default: memory
- description: Backend defines the backend for storing traces
+ description: 'Backend defines the backend for storing traces.
+ Default: memory'
enum:
- memory
- pv
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index 214db9f84..80bd368c3 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator
- createdAt: "2024-01-16T11:52:11Z"
+ createdAt: "2024-01-17T14:13:23Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
index f338fcd21..3e5a76f3a 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -171,7 +171,8 @@ spec:
properties:
backend:
default: memory
- description: Backend defines the backend for storing traces
+ description: 'Backend defines the backend for storing traces.
+ Default: memory'
enum:
- memory
- pv
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
index c4209d910..8f9be083b 100644
--- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -168,7 +168,8 @@ spec:
properties:
backend:
default: memory
- description: Backend defines the backend for storing traces
+ description: 'Backend defines the backend for storing traces.
+ Default: memory'
enum:
- memory
- pv
diff --git a/docs/operator/api.md b/docs/operator/api.md
index 7b3d6db0d..9c2cc921a 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -2588,12 +2588,12 @@ MonolithicTracesStorageSpec
"memory" |
-MonolithicTracesStorageBackendMemory specifies a in-memory storage backend.
+ | MonolithicTracesStorageBackendMemory defines storing traces in a tmpfs (in-memory filesystem).
|
"pv" |
-MonolithicTracesStorageBackendPersistentVolume specifies a Persistent Volume storage backend.
+ | MonolithicTracesStorageBackendPersistentVolume defines storing traces in a Persistent Volume.
|
@@ -2703,7 +2703,7 @@ MonolithicTracesStorageBackend
- Backend defines the backend for storing traces
+Backend defines the backend for storing traces. Default: memory
|
From 754486e33aa298b80d7433253dbcf08f823b5d0b Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 17 Jan 2024 18:25:38 +0100
Subject: [PATCH 25/36] drop .env file
Signed-off-by: Andreas Gerstmayr
---
.env | 4 ----
1 file changed, 4 deletions(-)
delete mode 100755 .env
diff --git a/.env b/.env
deleted file mode 100755
index 94de74570..000000000
--- a/.env
+++ /dev/null
@@ -1,4 +0,0 @@
-RELATED_IMAGE_TEMPO=docker.io/grafana/tempo:2.3.0
-RELATED_IMAGE_TEMPO_QUERY=docker.io/grafana/tempo-query:2.3.0
-RELATED_IMAGE_TEMPO_GATEWAY=quay.io/observatorium/api:main-2023-11-20-81f8fdf
-RELATED_IMAGE_TEMPO_GATEWAY_OPA=quay.io/observatorium/opa-openshift:main-2023-10-13-13d8960
From 3f57be48dda5d823d3ccdc8a74b55b67af2b5c97 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 18 Jan 2024 13:26:48 +0100
Subject: [PATCH 26/36] reconcile: retry on conflict
Signed-off-by: Andreas Gerstmayr
---
controllers/tempo/common.go | 10 +++++++++-
controllers/tempo/tempomonolithic_controller.go | 11 +----------
internal/manifests/monolithic/build.go | 2 +-
internal/manifests/monolithic/service.go | 8 ++++----
4 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/controllers/tempo/common.go b/controllers/tempo/common.go
index 801ae73c2..9806ce3db 100644
--- a/controllers/tempo/common.go
+++ b/controllers/tempo/common.go
@@ -10,8 +10,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/util/retry"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"github.com/grafana/tempo-operator/internal/manifests"
)
@@ -56,7 +58,13 @@ func reconcileManagedObjects(
desired := obj.DeepCopyObject().(client.Object)
mutateFn := manifests.MutateFuncFor(obj, desired)
- op, err := ctrl.CreateOrUpdate(ctx, k8sclient, obj, mutateFn)
+
+ var op controllerutil.OperationResult
+ err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
+ var err error
+ op, err = ctrl.CreateOrUpdate(ctx, k8sclient, obj, mutateFn)
+ return err
+ })
var immutableErr *manifests.ImmutableErr
if err != nil && errors.As(err, &immutableErr) {
diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go
index 9f2240c5a..0e3492d1d 100644
--- a/controllers/tempo/tempomonolithic_controller.go
+++ b/controllers/tempo/tempomonolithic_controller.go
@@ -94,17 +94,8 @@ func (r *TempoMonolithicReconciler) getOwnedObjects(ctx context.Context, tempo v
// Add all resources where the operator can conditionally create an object.
// For example, Ingress and Route can be enabled or disabled in the CR.
- serviceList := &corev1.ServiceList{}
- err := r.List(ctx, serviceList, listOps)
- if err != nil {
- return nil, fmt.Errorf("error listing services: %w", err)
- }
- for i := range serviceList.Items {
- ownedObjects[serviceList.Items[i].GetUID()] = &serviceList.Items[i]
- }
-
ingressList := &networkingv1.IngressList{}
- err = r.List(ctx, ingressList, listOps)
+ err := r.List(ctx, ingressList, listOps)
if err != nil {
return nil, fmt.Errorf("error listing ingress: %w", err)
}
diff --git a/internal/manifests/monolithic/build.go b/internal/manifests/monolithic/build.go
index df13c49d5..4a2662772 100644
--- a/internal/manifests/monolithic/build.go
+++ b/internal/manifests/monolithic/build.go
@@ -6,7 +6,7 @@ import (
// BuildAll generates all manifests.
func BuildAll(opts Options) ([]client.Object, error) {
- var manifests []client.Object
+ manifests := []client.Object{}
configMap, configChecksum, err := BuildConfigMap(opts)
if err != nil {
diff --git a/internal/manifests/monolithic/service.go b/internal/manifests/monolithic/service.go
index 4a3a2d202..6cdeda695 100644
--- a/internal/manifests/monolithic/service.go
+++ b/internal/manifests/monolithic/service.go
@@ -13,7 +13,7 @@ import (
// BuildTempoService creates the service for a monolithic deployment.
func BuildTempoService(opts Options) *corev1.Service {
tempo := opts.Tempo
- labels := Labels(opts.Tempo.Name)
+ labels := Labels(tempo.Name)
ports := []corev1.ServicePort{
{
Name: manifestutils.HttpPortName,
@@ -43,7 +43,7 @@ func BuildTempoService(opts Options) *corev1.Service {
}
}
- if opts.Tempo.Spec.JaegerUI != nil && opts.Tempo.Spec.JaegerUI.Enabled {
+ if tempo.Spec.JaegerUI != nil && tempo.Spec.JaegerUI.Enabled {
ports = append(ports, []corev1.ServicePort{
{
Name: manifestutils.JaegerGRPCQuery,
@@ -69,8 +69,8 @@ func BuildTempoService(opts Options) *corev1.Service {
Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
- Name: naming.Name("", opts.Tempo.Name),
- Namespace: opts.Tempo.Namespace,
+ Name: naming.Name("", tempo.Name),
+ Namespace: tempo.Namespace,
Labels: labels,
},
Spec: corev1.ServiceSpec{
From 19ca826da44fa1755298d0833fd4a2e775162d0d Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 18 Jan 2024 16:12:09 +0100
Subject: [PATCH 27/36] update changelog, set size defaults, add api docs
Signed-off-by: Andreas Gerstmayr
---
.chloggen/monolithic_mode.yaml | 4 +-
Makefile | 2 +-
apis/tempo/v1alpha1/tempomonolithic_types.go | 7 +++-
.../tempo/v1alpha1/tempomonolithic_webhook.go | 2 +-
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 3 ++
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 3 ++
.../tempo.grafana.com_tempomonolithics.yaml | 3 ++
docs/operator/api.md | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 38 +++++++++++++++++++
internal/manifests/monolithic/configmap.go | 2 +-
internal/manifests/monolithic/statefulset.go | 11 +++++-
13 files changed, 70 insertions(+), 11 deletions(-)
create mode 100644 docs/spec/tempo.grafana.com_tempomonolithics.yaml
diff --git a/.chloggen/monolithic_mode.yaml b/.chloggen/monolithic_mode.yaml
index cd27b900e..7d811f2ac 100755
--- a/.chloggen/monolithic_mode.yaml
+++ b/.chloggen/monolithic_mode.yaml
@@ -13,4 +13,6 @@ issues: [710]
# (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:
+subtext: |
+ The operator exposes a new CRD `TempoMonolithic`, which runs a Tempo instance in monolithic mode.
+ The monolithic mode supports the following additional storage backends: **in-memory and file system (persistent volume)**.
diff --git a/Makefile b/Makefile
index 0a1c0d05f..aa0596902 100644
--- a/Makefile
+++ b/Makefile
@@ -455,7 +455,7 @@ cmctl:
}
.PHONY: api-docs
-api-docs: docs/operator/api.md docs/operator/feature-gates.md docs/spec/tempo.grafana.com_tempostacks.yaml
+api-docs: docs/operator/api.md docs/operator/feature-gates.md docs/spec/tempo.grafana.com_tempostacks.yaml docs/spec/tempo.grafana.com_tempomonolithics.yaml
TYPES_TARGET := $(shell find apis/tempo -type f -iname "*_types.go")
docs/operator/api.md: $(TYPES_TARGET) gen-crd-api-reference-docs
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 1043b8d5b..34e31a8f7 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -74,8 +74,8 @@ type MonolithicTracesStorageBackend string
const (
// MonolithicTracesStorageBackendMemory defines storing traces in a tmpfs (in-memory filesystem).
MonolithicTracesStorageBackendMemory MonolithicTracesStorageBackend = "memory"
- // MonolithicTracesStorageBackendPersistentVolume defines storing traces in a Persistent Volume.
- MonolithicTracesStorageBackendPersistentVolume MonolithicTracesStorageBackend = "pv"
+ // MonolithicTracesStorageBackendPV defines storing traces in a Persistent Volume.
+ MonolithicTracesStorageBackendPV MonolithicTracesStorageBackend = "pv"
)
// MonolithicTracesStorageWALSpec defines the write-ahead logging (WAL) configuration.
@@ -83,6 +83,7 @@ type MonolithicTracesStorageWALSpec struct {
// Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
//
// +kubebuilder:validation:Required
+ // +kubebuilder:default="10Gi"
Size resource.Quantity `json:"size"`
}
@@ -91,6 +92,7 @@ type MonolithicTracesStoragePVSpec struct {
// Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
//
// +kubebuilder:validation:Required
+ // +kubebuilder:default="10Gi"
Size resource.Quantity `json:"size"`
}
@@ -125,6 +127,7 @@ type MonolithicIngestionOTLPProtocolsGRPCSpec struct {
// Enabled defines if OTLP over gRPC is enabled
//
// +kubebuilder:validation:Required
+ // +kubebuilder:default=true
Enabled bool `json:"enabled"`
}
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
index 3947202d1..422f42e8b 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -32,7 +32,7 @@ func (r *TempoMonolithic) Default() {
}
}
- if r.Spec.Storage.Traces.Backend == MonolithicTracesStorageBackendPersistentVolume && r.Spec.Storage.Traces.PV == nil {
+ if r.Spec.Storage.Traces.Backend == MonolithicTracesStorageBackendPV && r.Spec.Storage.Traces.PV == nil {
r.Spec.Storage.Traces.PV = &MonolithicTracesStoragePVSpec{
Size: tenGBQuantity,
}
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 43f767e83..22ce8c6a9 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
- createdAt: "2024-01-17T16:42:02Z"
+ createdAt: "2024-01-18T14:39:12Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
index 3e5a76f3a..9d35d0453 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -57,6 +57,7 @@ spec:
description: GRPC defines the OTLP/gRPC configuration
properties:
enabled:
+ default: true
description: Enabled defines if OTLP over gRPC is enabled
type: boolean
required:
@@ -184,6 +185,7 @@ spec:
anyOf:
- type: integer
- type: string
+ default: 10Gi
description: Size defines the size of the Persistent Volume
for storing the traces. Defaults to 10Gi.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
@@ -198,6 +200,7 @@ spec:
anyOf:
- type: integer
- type: string
+ default: 10Gi
description: Size defines the size of the Persistent Volume
for storing the WAL. Defaults to 10Gi.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index d5db0c530..e6c436619 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
- createdAt: "2024-01-17T16:42:01Z"
+ createdAt: "2024-01-18T14:39:10Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
index 3e5a76f3a..9d35d0453 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -57,6 +57,7 @@ spec:
description: GRPC defines the OTLP/gRPC configuration
properties:
enabled:
+ default: true
description: Enabled defines if OTLP over gRPC is enabled
type: boolean
required:
@@ -184,6 +185,7 @@ spec:
anyOf:
- type: integer
- type: string
+ default: 10Gi
description: Size defines the size of the Persistent Volume
for storing the traces. Defaults to 10Gi.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
@@ -198,6 +200,7 @@ spec:
anyOf:
- type: integer
- type: string
+ default: 10Gi
description: Size defines the size of the Persistent Volume
for storing the WAL. Defaults to 10Gi.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
index 8f9be083b..75252b61d 100644
--- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -54,6 +54,7 @@ spec:
description: GRPC defines the OTLP/gRPC configuration
properties:
enabled:
+ default: true
description: Enabled defines if OTLP over gRPC is enabled
type: boolean
required:
@@ -181,6 +182,7 @@ spec:
anyOf:
- type: integer
- type: string
+ default: 10Gi
description: Size defines the size of the Persistent Volume
for storing the traces. Defaults to 10Gi.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
@@ -195,6 +197,7 @@ spec:
anyOf:
- type: integer
- type: string
+ default: 10Gi
description: Size defines the size of the Persistent Volume
for storing the WAL. Defaults to 10Gi.
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
diff --git a/docs/operator/api.md b/docs/operator/api.md
index 9c2cc921a..f778a4dc5 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -2593,7 +2593,7 @@ MonolithicTracesStorageSpec
"pv" |
-MonolithicTracesStorageBackendPersistentVolume defines storing traces in a Persistent Volume.
+ | MonolithicTracesStorageBackendPV defines storing traces in a Persistent Volume.
|
diff --git a/docs/spec/tempo.grafana.com_tempomonolithics.yaml b/docs/spec/tempo.grafana.com_tempomonolithics.yaml
new file mode 100644
index 000000000..0f6f4002b
--- /dev/null
+++ b/docs/spec/tempo.grafana.com_tempomonolithics.yaml
@@ -0,0 +1,38 @@
+apiVersion: tempo.grafana.com/v1alpha1 # APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+kind: TempoMonolithic # Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+metadata:
+ name: example
+spec: # TempoMonolithicSpec defines the desired state of TempoMonolithic.
+ extraConfig: # ExtraConfig defines any extra (overlay) configuration for components
+ tempo: {} # Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
+ ingestion: # Ingestion defines the trace ingestion configuration
+ otlp: # OTLP defines the ingestion configuration for OTLP
+ grpc: # GRPC defines the OTLP/gRPC configuration
+ enabled: true # Enabled defines if OTLP over gRPC is enabled
+ http: # HTTP defines the OTLP/HTTP configuration
+ enabled: false # Enabled defines if OTLP over HTTP is enabled
+ tls: # TLS defines the TLS configuration for ingestion
+ ca: "" # CA defines the name of a secret containing the CA certificate
+ cert: "" # Cert defines the name of a secret containing the TLS certificate and private key
+ enabled: false # Enabled defines if TLS is enabled for ingestion
+ jaegerui: # JaegerUI defines the Jaeger UI configuration
+ enabled: false # Enabled defines if the Jaeger UI should be enabled
+ ingress: # Ingress defines the ingress configuration for Jaeger UI
+ enabled: false # Enabled defines if an Ingress object should be created for Jaeger UI
+ route: # Route defines the route configuration for Jaeger UI
+ enabled: false # Enabled defines if a Route object should be created for Jaeger UI
+ management: "" # ManagementState defines whether this instance is managed by the operator or self-managed
+ observability: # Observability defines observability configuration for the Tempo deployment
+ metrics: # Metrics defines the metrics configuration of the Tempo deployment
+ prometheusRules: # ServiceMonitors defines the PrometheusRule configuration
+ enabled: false # Enabled defines if the operator should create PrometheusRules for this Tempo deployment
+ serviceMonitors: # ServiceMonitors defines the ServiceMonitor configuration
+ enabled: false # Enabled defines if the operator should create ServiceMonitors for this Tempo deployment
+ storage: # Storage defines the backend storage configuration
+ traces: # Traces defines the backend storage configuration for traces
+ backend: "memory" # Backend defines the backend for storing traces. Default: memory
+ pv: # PV defines the Persistent Volume configuration
+ size: "10Gi" # Size defines the size of the Persistent Volume for storing the traces. Defaults to 10Gi.
+ wal: # WAL defines the write-ahead logging (WAL) configuration
+ size: "10Gi" # Size defines the size of the Persistent Volume for storing the WAL. Defaults to 10Gi.
+status: # TempoMonolithicStatus defines the observed state of TempoMonolithic.
diff --git a/internal/manifests/monolithic/configmap.go b/internal/manifests/monolithic/configmap.go
index 6f44380cf..e104e5465 100644
--- a/internal/manifests/monolithic/configmap.go
+++ b/internal/manifests/monolithic/configmap.go
@@ -102,7 +102,7 @@ func buildTempoConfig(opts Options) ([]byte, error) {
config.Storage.Trace.WAL.Path = "/var/tempo/wal"
switch tempo.Spec.Storage.Traces.Backend {
case v1alpha1.MonolithicTracesStorageBackendMemory,
- v1alpha1.MonolithicTracesStorageBackendPersistentVolume:
+ v1alpha1.MonolithicTracesStorageBackendPV:
config.Storage.Trace.Backend = "local"
config.Storage.Trace.Local.Path = "/var/tempo/blocks"
diff --git a/internal/manifests/monolithic/statefulset.go b/internal/manifests/monolithic/statefulset.go
index 2f3113a81..a014cc0c1 100644
--- a/internal/manifests/monolithic/statefulset.go
+++ b/internal/manifests/monolithic/statefulset.go
@@ -65,6 +65,13 @@ func BuildTempoStatefulset(opts Options) (*appsv1.StatefulSet, error) {
"-mem-ballast-size-mbs=1024",
"-log.level=info",
},
+
+ // The Tempo Helm chart mounts /var/tempo if persistence is enabled.
+ // Tempo writes its WAL to /var/tempo/wal, and if the local storage backend is enabled, parquet blocks to /var/tempo/blocks.
+ //
+ // Let's mount /var/tempo as WAL, in case Tempo writes caches to additional locations in /var/tempo in the future.
+ // If memory or pv storage is enabled, /var/tempo/blocks will be mounted in a different volume (configured in configureStorage()).
+ // This is to avoid confusion why a PV is required when selecting object storage.
VolumeMounts: []corev1.VolumeMount{
{
Name: manifestutils.ConfigVolumeName,
@@ -73,7 +80,7 @@ func BuildTempoStatefulset(opts Options) (*appsv1.StatefulSet, error) {
},
{
Name: walVolumeName,
- MountPath: "/var/tempo/wal",
+ MountPath: "/var/tempo",
},
},
Ports: buildTempoPorts(opts),
@@ -166,7 +173,7 @@ func configureStorage(opts Options, sts *appsv1.StatefulSet) error {
},
})
- case v1alpha1.MonolithicTracesStorageBackendPersistentVolume:
+ case v1alpha1.MonolithicTracesStorageBackendPV:
if tempo.Spec.Storage.Traces.WAL == nil {
return errors.New("please configure .spec.storage.traces.wal")
}
From cd64880e04af84818ec1716b683e0a9f650deb94 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 18 Jan 2024 16:13:40 +0100
Subject: [PATCH 28/36] update changelog
Signed-off-by: Andreas Gerstmayr
---
.chloggen/monolithic_mode.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.chloggen/monolithic_mode.yaml b/.chloggen/monolithic_mode.yaml
index 7d811f2ac..ddca4642f 100755
--- a/.chloggen/monolithic_mode.yaml
+++ b/.chloggen/monolithic_mode.yaml
@@ -14,5 +14,5 @@ issues: [710]
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
- The operator exposes a new CRD `TempoMonolithic`, which runs a Tempo instance in monolithic mode.
- The monolithic mode supports the following additional storage backends: **in-memory and file system (persistent volume)**.
+ The operator exposes a new CRD `TempoMonolithic`, which manages a Tempo instance in monolithic mode.
+ The monolithic mode supports the following additional storage backends: in-memory and file system (persistent volume).
From a9e41e97b286e7d5c1fee6594cb9b3d0d6e45c69 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 18 Jan 2024 16:19:13 +0100
Subject: [PATCH 29/36] fix test
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/monolithic/statefulset_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/internal/manifests/monolithic/statefulset_test.go b/internal/manifests/monolithic/statefulset_test.go
index 53698e8fd..ff35eb612 100644
--- a/internal/manifests/monolithic/statefulset_test.go
+++ b/internal/manifests/monolithic/statefulset_test.go
@@ -94,7 +94,7 @@ func TestStatefulsetMemoryStorage(t *testing.T) {
},
{
Name: "tempo-wal",
- MountPath: "/var/tempo/wal",
+ MountPath: "/var/tempo",
},
{
Name: "tempo-blocks",
@@ -189,7 +189,7 @@ func TestStatefulsetPVStorage(t *testing.T) {
},
{
Name: "tempo-wal",
- MountPath: "/var/tempo/wal",
+ MountPath: "/var/tempo",
},
{
Name: "tempo-blocks",
From 6657c890668f1e43bbc50563b6ade05c775cbde7 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 18 Jan 2024 17:45:56 +0100
Subject: [PATCH 30/36] add controller test
Signed-off-by: Andreas Gerstmayr
---
.../tempo/tempomonolithic_controller_test.go | 66 +++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 controllers/tempo/tempomonolithic_controller_test.go
diff --git a/controllers/tempo/tempomonolithic_controller_test.go b/controllers/tempo/tempomonolithic_controller_test.go
new file mode 100644
index 000000000..2114df792
--- /dev/null
+++ b/controllers/tempo/tempomonolithic_controller_test.go
@@ -0,0 +1,66 @@
+package controllers
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
+ "github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+)
+
+func TestReconcileMonolithic(t *testing.T) {
+ nsn := types.NamespacedName{Name: "sample", Namespace: "default"}
+ tempo := &v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: nsn.Name,
+ Namespace: nsn.Namespace,
+ },
+ }
+ err := k8sClient.Create(context.Background(), tempo)
+ require.NoError(t, err)
+
+ reconciler := TempoMonolithicReconciler{
+ Client: k8sClient,
+ Scheme: testScheme,
+ CtrlConfig: configv1alpha1.ProjectConfig{},
+ }
+ reconcile, err := reconciler.Reconcile(context.Background(), ctrl.Request{NamespacedName: nsn})
+ require.NoError(t, err)
+ assert.Equal(t, false, reconcile.Requeue)
+
+ // Check if objects of specific types were created and are managed by the operator
+ opts := []client.ListOption{
+ client.InNamespace(nsn.Namespace),
+ client.MatchingLabels(map[string]string{
+ "app.kubernetes.io/instance": nsn.Name,
+ "app.kubernetes.io/managed-by": "tempo-operator",
+ }),
+ }
+ {
+ list := &corev1.ConfigMapList{}
+ err = k8sClient.List(context.Background(), list, opts...)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, list.Items)
+ }
+ {
+ list := &appsv1.StatefulSetList{}
+ 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)
+ }
+}
From 9a95fcebca1840ac7e52978ac4f8f36a3b0a82fb Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Wed, 24 Jan 2024 19:33:36 +0100
Subject: [PATCH 31/36] enable OTLP/HTTP by default
Signed-off-by: Andreas Gerstmayr
---
.../tempo/v1alpha1/tempomonolithic_webhook.go | 19 +++++++++++++------
.../v1alpha1/tempomonolithic_webhook_test.go | 16 ++++++++++++++--
tests/e2e/monolithic-smoketest/01-assert.yaml | 4 ++++
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
index 422f42e8b..8285556e9 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -39,12 +39,19 @@ func (r *TempoMonolithic) Default() {
}
if r.Spec.Ingestion == nil {
- r.Spec.Ingestion = &MonolithicIngestionSpec{
- OTLP: &MonolithicIngestionOTLPSpec{
- GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
- Enabled: true,
- },
- },
+ r.Spec.Ingestion = &MonolithicIngestionSpec{}
+ }
+ if r.Spec.Ingestion.OTLP == nil {
+ r.Spec.Ingestion.OTLP = &MonolithicIngestionOTLPSpec{}
+ }
+ if r.Spec.Ingestion.OTLP.GRPC == nil {
+ r.Spec.Ingestion.OTLP.GRPC = &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ }
+ }
+ if r.Spec.Ingestion.OTLP.HTTP == nil {
+ r.Spec.Ingestion.OTLP.HTTP = &MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
}
}
}
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go b/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
index 49ae4d72e..93c68c8db 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook_test.go
@@ -13,7 +13,7 @@ func TestMonolithicDefault(t *testing.T) {
expected *TempoMonolithic
}{
{
- name: "empty spec, set memory backend and enable OTLP/gRPC",
+ name: "empty spec, set memory backend and enable OTLP/gRPC and OTLP/HTTP",
input: &TempoMonolithic{
Spec: TempoMonolithicSpec{},
},
@@ -29,6 +29,9 @@ func TestMonolithicDefault(t *testing.T) {
GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
Enabled: true,
},
+ HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
},
},
},
@@ -63,6 +66,9 @@ func TestMonolithicDefault(t *testing.T) {
GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
Enabled: true,
},
+ HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
},
},
},
@@ -82,7 +88,10 @@ func TestMonolithicDefault(t *testing.T) {
},
Ingestion: &MonolithicIngestionSpec{
OTLP: &MonolithicIngestionOTLPSpec{
- // HTTP is already set, GRPC should not be enabled by webhook
+ // GRPC is explicitly disabled and should not be enabled by webhook
+ GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: false,
+ },
HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
Enabled: true,
},
@@ -102,6 +111,9 @@ func TestMonolithicDefault(t *testing.T) {
},
Ingestion: &MonolithicIngestionSpec{
OTLP: &MonolithicIngestionOTLPSpec{
+ GRPC: &MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: false,
+ },
HTTP: &MonolithicIngestionOTLPProtocolsHTTPSpec{
Enabled: true,
},
diff --git a/tests/e2e/monolithic-smoketest/01-assert.yaml b/tests/e2e/monolithic-smoketest/01-assert.yaml
index 2c50d42e4..8767efc3f 100644
--- a/tests/e2e/monolithic-smoketest/01-assert.yaml
+++ b/tests/e2e/monolithic-smoketest/01-assert.yaml
@@ -38,6 +38,10 @@ spec:
port: 4317
protocol: TCP
targetPort: otlp-grpc
+ - name: otlp-http
+ port: 4318
+ protocol: TCP
+ targetPort: otlp-http
- name: jaeger-grpc
port: 16685
protocol: TCP
From 1cf69764377b0f876a89344a91ebd070603328c4 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 25 Jan 2024 11:36:33 +0100
Subject: [PATCH 32/36] drop TLS struct (will reuse TLS struct from TempoStack
in follow-up PR)
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_types.go | 25 ----
apis/tempo/v1alpha1/zz_generated.deepcopy.go | 20 ---
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 21 ---
.../tempo-operator.clusterserviceversion.yaml | 2 +-
.../tempo.grafana.com_tempomonolithics.yaml | 21 ---
.../tempo.grafana.com_tempomonolithics.yaml | 21 ---
docs/operator/api.md | 121 ------------------
.../tempo.grafana.com_tempomonolithics.yaml | 4 -
9 files changed, 2 insertions(+), 235 deletions(-)
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 34e31a8f7..2c3c7357b 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -102,11 +102,6 @@ type MonolithicIngestionSpec struct {
//
// +kubebuilder:validation:Optional
OTLP *MonolithicIngestionOTLPSpec `json:"otlp,omitempty"`
-
- // TLS defines the TLS configuration for ingestion
- //
- // +kubebuilder:validation:Optional
- TLS *MonolithicIngestionTLSSpec `json:"tls,omitempty"`
}
// MonolithicIngestionOTLPSpec defines the settings for OTLP ingestion.
@@ -139,26 +134,6 @@ type MonolithicIngestionOTLPProtocolsHTTPSpec struct {
Enabled bool `json:"enabled"`
}
-// MonolithicIngestionTLSSpec defines the TLS settings for ingestion.
-type MonolithicIngestionTLSSpec struct {
- // Enabled defines if TLS is enabled for ingestion
- //
- // +kubebuilder:validation:Required
- Enabled bool `json:"enabled"`
-
- // CA defines the name of a secret containing the CA certificate
- //
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:MinLength=1
- CA string `json:"ca"`
-
- // Cert defines the name of a secret containing the TLS certificate and private key
- //
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:MinLength=1
- Cert string `json:"cert"`
-}
-
// MonolithicJaegerUISpec defines the settings for the Jaeger UI.
type MonolithicJaegerUISpec struct {
// Enabled defines if the Jaeger UI should be enabled
diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
index b74602d7f..261d6fb23 100644
--- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -461,11 +461,6 @@ func (in *MonolithicIngestionSpec) DeepCopyInto(out *MonolithicIngestionSpec) {
*out = new(MonolithicIngestionOTLPSpec)
(*in).DeepCopyInto(*out)
}
- if in.TLS != nil {
- in, out := &in.TLS, &out.TLS
- *out = new(MonolithicIngestionTLSSpec)
- **out = **in
- }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionSpec.
@@ -478,21 +473,6 @@ func (in *MonolithicIngestionSpec) DeepCopy() *MonolithicIngestionSpec {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MonolithicIngestionTLSSpec) DeepCopyInto(out *MonolithicIngestionTLSSpec) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicIngestionTLSSpec.
-func (in *MonolithicIngestionTLSSpec) DeepCopy() *MonolithicIngestionTLSSpec {
- if in == nil {
- return nil
- }
- out := new(MonolithicIngestionTLSSpec)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MonolithicJaegerUIIngressSpec) DeepCopyInto(out *MonolithicJaegerUIIngressSpec) {
*out = *in
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 22ce8c6a9..426234feb 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
- createdAt: "2024-01-18T14:39:12Z"
+ createdAt: "2024-01-25T10:35:19Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
index 9d35d0453..e43b04047 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -73,27 +73,6 @@ spec:
- enabled
type: object
type: object
- tls:
- description: TLS defines the TLS configuration for ingestion
- properties:
- ca:
- description: CA defines the name of a secret containing the
- CA certificate
- minLength: 1
- type: string
- cert:
- description: Cert defines the name of a secret containing
- the TLS certificate and private key
- minLength: 1
- type: string
- enabled:
- description: Enabled defines if TLS is enabled for ingestion
- type: boolean
- required:
- - ca
- - cert
- - enabled
- type: object
type: object
jaegerui:
description: JaegerUI defines the Jaeger UI configuration
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index e6c436619..fb4a6a1ff 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
- createdAt: "2024-01-18T14:39:10Z"
+ createdAt: "2024-01-25T10:35:18Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
index 9d35d0453..e43b04047 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml
@@ -73,27 +73,6 @@ spec:
- enabled
type: object
type: object
- tls:
- description: TLS defines the TLS configuration for ingestion
- properties:
- ca:
- description: CA defines the name of a secret containing the
- CA certificate
- minLength: 1
- type: string
- cert:
- description: Cert defines the name of a secret containing
- the TLS certificate and private key
- minLength: 1
- type: string
- enabled:
- description: Enabled defines if TLS is enabled for ingestion
- type: boolean
- required:
- - ca
- - cert
- - enabled
- type: object
type: object
jaegerui:
description: JaegerUI defines the Jaeger UI configuration
diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
index 75252b61d..f81b4b6c7 100644
--- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml
@@ -70,27 +70,6 @@ spec:
- enabled
type: object
type: object
- tls:
- description: TLS defines the TLS configuration for ingestion
- properties:
- ca:
- description: CA defines the name of a secret containing the
- CA certificate
- minLength: 1
- type: string
- cert:
- description: Cert defines the name of a secret containing
- the TLS certificate and private key
- minLength: 1
- type: string
- enabled:
- description: Enabled defines if TLS is enabled for ingestion
- type: boolean
- required:
- - ca
- - cert
- - enabled
- type: object
type: object
jaegerui:
description: JaegerUI defines the Jaeger UI configuration
diff --git a/docs/operator/api.md b/docs/operator/api.md
index f778a4dc5..ac8738806 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -1913,127 +1913,6 @@ MonolithicIngestionOTLPSpec
|
-
-
-
-
-tls
-
-
-
-
-
-MonolithicIngestionTLSSpec
-
-
-
-
-
- |
-
-
-
- TLS defines the TLS configuration for ingestion
-
- |
-
-
-
-
-
-## MonolithicIngestionTLSSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionTLSSpec }
-
-
-
-(Appears on:MonolithicIngestionSpec)
-
-
-
-
-
- MonolithicIngestionTLSSpec defines the TLS settings for ingestion.
-
-
-
-
-
-
-
-
-
-Field |
-
-Description |
-
-
-
-
-
-
-
-
-
-
-
-enabled
-
-
-
-bool
-
-
-
- |
-
-
-
- Enabled defines if TLS is enabled for ingestion
-
- |
-
-
-
-
-
-
-ca
-
-
-
-string
-
-
-
- |
-
-
-
- CA defines the name of a secret containing the CA certificate
-
- |
-
-
-
-
-
-
-cert
-
-
-
-string
-
-
-
- |
-
-
-
- Cert defines the name of a secret containing the TLS certificate and private key
-
- |
-
-
diff --git a/docs/spec/tempo.grafana.com_tempomonolithics.yaml b/docs/spec/tempo.grafana.com_tempomonolithics.yaml
index 0f6f4002b..f3c18340f 100644
--- a/docs/spec/tempo.grafana.com_tempomonolithics.yaml
+++ b/docs/spec/tempo.grafana.com_tempomonolithics.yaml
@@ -11,10 +11,6 @@ spec: # TempoMonolithicSpec defines the desir
enabled: true # Enabled defines if OTLP over gRPC is enabled
http: # HTTP defines the OTLP/HTTP configuration
enabled: false # Enabled defines if OTLP over HTTP is enabled
- tls: # TLS defines the TLS configuration for ingestion
- ca: "" # CA defines the name of a secret containing the CA certificate
- cert: "" # Cert defines the name of a secret containing the TLS certificate and private key
- enabled: false # Enabled defines if TLS is enabled for ingestion
jaegerui: # JaegerUI defines the Jaeger UI configuration
enabled: false # Enabled defines if the Jaeger UI should be enabled
ingress: # Ingress defines the ingress configuration for Jaeger UI
From 16b70304720c0a3d94170c643ce40e2e7c4cb4b6 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Thu, 25 Jan 2024 12:01:03 +0100
Subject: [PATCH 33/36] add comment to default function
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_webhook.go | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/apis/tempo/v1alpha1/tempomonolithic_webhook.go b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
index 8285556e9..e0d240986 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_webhook.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_webhook.go
@@ -16,7 +16,9 @@ func (r *TempoMonolithic) SetupWebhookWithManager(mgr ctrl.Manager) error {
Complete()
}
-// Default implements webhook.Defaulter so a webhook will be registered for the type.
+// Default sets all default values in a central place, instead of setting it at every place where the value is accessed.
+// NOTE: This function is called inside the Reconcile loop, NOT in the webhook.
+// We want to keep the CR as minimal as the user configures it, and not modify it in any way (except for upgrades).
func (r *TempoMonolithic) Default() {
if r.Spec.Storage == nil {
r.Spec.Storage = &MonolithicStorageSpec{}
From 822c01668e945e74c03e035a7e0d3b188d9730c4 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Fri, 26 Jan 2024 12:40:24 +0100
Subject: [PATCH 34/36] show diff using cmp.Diff() in logs when immutable field
is changed
Signed-off-by: Andreas Gerstmayr
---
go.mod | 2 +-
internal/manifests/mutate.go | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/go.mod b/go.mod
index c095e6ba7..2b926d8fa 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,7 @@ require (
github.com/ViaQ/logerr/v2 v2.1.0
github.com/go-logr/logr v1.4.1
github.com/go-logr/zapr v1.3.0
+ github.com/google/go-cmp v0.6.0
github.com/grafana-operator/grafana-operator/v5 v5.5.2
github.com/imdario/mergo v0.3.16
github.com/novln/docker-parser v1.0.0
@@ -53,7 +54,6 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
- github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 // indirect
github.com/google/uuid v1.3.1 // indirect
diff --git a/internal/manifests/mutate.go b/internal/manifests/mutate.go
index 691554e50..029a4f120 100644
--- a/internal/manifests/mutate.go
+++ b/internal/manifests/mutate.go
@@ -5,6 +5,7 @@ import (
"reflect"
"github.com/ViaQ/logerr/v2/kverrors"
+ "github.com/google/go-cmp/cmp"
grafanav1 "github.com/grafana-operator/grafana-operator/v5/api/v1beta1"
"github.com/imdario/mergo"
routev1 "github.com/openshift/api/route/v1"
@@ -26,7 +27,7 @@ type ImmutableErr struct {
}
func (m *ImmutableErr) Error() string {
- return fmt.Sprintf("update to immutable field %s is forbidden", m.field)
+ return fmt.Sprintf("update to immutable field %s is forbidden, diff: %s", m.field, cmp.Diff(m.existing, m.desired))
}
// MutateFuncFor returns a mutate function based on the
From bf76bef29b063f92db38fad79a4f11e51d2129f8 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Fri, 26 Jan 2024 13:11:54 +0100
Subject: [PATCH 35/36] re-use ExtraConfig from TempoStack
Signed-off-by: Andreas Gerstmayr
---
apis/tempo/v1alpha1/tempomonolithic_types.go | 10 +-
apis/tempo/v1alpha1/tempostack_types.go | 2 +
apis/tempo/v1alpha1/zz_generated.deepcopy.go | 18 +--
.../tempo-operator.clusterserviceversion.yaml | 11 +-
.../tempo.grafana.com_tempostacks.yaml | 2 +
.../tempo-operator.clusterserviceversion.yaml | 11 +-
.../tempo.grafana.com_tempostacks.yaml | 2 +
.../bases/tempo.grafana.com_tempostacks.yaml | 2 +
.../tempo-operator.clusterserviceversion.yaml | 9 +-
.../tempo-operator.clusterserviceversion.yaml | 9 +-
docs/operator/api.md | 66 +----------
docs/spec/tempo.grafana.com_tempostacks.yaml | 2 +-
internal/manifests/config/configmap.go | 4 +-
internal/manifests/config/extra.go | 5 +-
internal/manifests/config/extra_test.go | 6 +-
internal/manifests/monolithic/configmap.go | 34 +-----
.../manifests/monolithic/configmap_test.go | 110 ++++++++++++------
17 files changed, 140 insertions(+), 163 deletions(-)
diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go
index 2c3c7357b..bf89df673 100644
--- a/apis/tempo/v1alpha1/tempomonolithic_types.go
+++ b/apis/tempo/v1alpha1/tempomonolithic_types.go
@@ -1,7 +1,6 @@
package v1alpha1
import (
- apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -36,7 +35,7 @@ type TempoMonolithicSpec struct {
// ExtraConfig defines any extra (overlay) configuration for components
//
// +kubebuilder:validation:Optional
- ExtraConfig *MonolithicExtraConfigSpec `json:"extraConfig,omitempty"`
+ ExtraConfig *ExtraConfigSpec `json:"extraConfig,omitempty"`
}
// MonolithicStorageSpec defines the storage for the Tempo deployment.
@@ -205,13 +204,6 @@ type MonolithicObservabilityMetricsPrometheusRulesSpec struct {
Enabled bool `json:"enabled"`
}
-// MonolithicExtraConfigSpec defines extra configuration for this deployment.
-type MonolithicExtraConfigSpec struct {
- // Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
- // +kubebuilder:validation:Optional
- Tempo apiextensionsv1.JSON `json:"tempo,omitempty"`
-}
-
// TempoMonolithicStatus defines the observed state of TempoMonolithic.
type TempoMonolithicStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
diff --git a/apis/tempo/v1alpha1/tempostack_types.go b/apis/tempo/v1alpha1/tempostack_types.go
index 5e293ff06..d5c2a9d73 100644
--- a/apis/tempo/v1alpha1/tempostack_types.go
+++ b/apis/tempo/v1alpha1/tempostack_types.go
@@ -132,6 +132,8 @@ type TempoStackSpec struct {
// ExtraConfigSpec defines extra configurations for tempo that will be merged with the operator generated, configurations defined here
// has precedence and could override generated config.
type ExtraConfigSpec struct {
+ // Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
+ //
// +optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Tempo Extra Configurations"
Tempo apiextensionsv1.JSON `json:"tempo,omitempty"`
diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
index 261d6fb23..ea10afd40 100644
--- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go
@@ -382,22 +382,6 @@ func (in *MetricsConfigSpec) DeepCopy() *MetricsConfigSpec {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MonolithicExtraConfigSpec) DeepCopyInto(out *MonolithicExtraConfigSpec) {
- *out = *in
- in.Tempo.DeepCopyInto(&out.Tempo)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicExtraConfigSpec.
-func (in *MonolithicExtraConfigSpec) DeepCopy() *MonolithicExtraConfigSpec {
- if in == nil {
- return nil
- }
- out := new(MonolithicExtraConfigSpec)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MonolithicIngestionOTLPProtocolsGRPCSpec) DeepCopyInto(out *MonolithicIngestionOTLPProtocolsGRPCSpec) {
*out = *in
@@ -1165,7 +1149,7 @@ func (in *TempoMonolithicSpec) DeepCopyInto(out *TempoMonolithicSpec) {
}
if in.ExtraConfig != nil {
in, out := &in.ExtraConfig, &out.ExtraConfig
- *out = new(MonolithicExtraConfigSpec)
+ *out = new(ExtraConfigSpec)
(*in).DeepCopyInto(*out)
}
}
diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
index 426234feb..f839ea08d 100644
--- a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
- createdAt: "2024-01-25T10:35:19Z"
+ createdAt: "2024-01-26T12:10:07Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -75,6 +75,11 @@ spec:
displayName: Tempo Monolithic
kind: TempoMonolithic
name: tempomonolithics.tempo.grafana.com
+ specDescriptors:
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
+ path: extraConfig.tempo
version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
@@ -108,7 +113,9 @@ spec:
specDescriptors:
- displayName: Extra Configurations
path: extraConfig
- - displayName: Tempo Extra Configurations
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
path: extraConfig.tempo
- description: HashRing defines the spec for the distributed hash ring configuration.
displayName: Hash Ring
diff --git a/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml b/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml
index 5a309fae3..de8d6a55a 100644
--- a/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml
+++ b/bundle/community/manifests/tempo.grafana.com_tempostacks.yaml
@@ -59,6 +59,8 @@ spec:
defined here has precedence and could override generated config.
properties:
tempo:
+ description: Tempo defines any extra Tempo configuration, which
+ will be merged with the operator's generated Tempo configuration
x-kubernetes-preserve-unknown-fields: true
type: object
hashRing:
diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
index fb4a6a1ff..c449b0849 100644
--- a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml
@@ -56,7 +56,7 @@ metadata:
capabilities: Deep Insights
categories: Logging & Tracing,Monitoring
containerImage: ghcr.io/grafana/tempo-operator/tempo-operator:v0.7.0
- createdAt: "2024-01-25T10:35:18Z"
+ createdAt: "2024-01-26T12:10:06Z"
description: Create and manage deployments of Tempo, a high-scale distributed
tracing backend.
operatorframework.io/cluster-monitoring: "true"
@@ -75,6 +75,11 @@ spec:
displayName: Tempo Monolithic
kind: TempoMonolithic
name: tempomonolithics.tempo.grafana.com
+ specDescriptors:
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
+ path: extraConfig.tempo
version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
@@ -108,7 +113,9 @@ spec:
specDescriptors:
- displayName: Extra Configurations
path: extraConfig
- - displayName: Tempo Extra Configurations
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
path: extraConfig.tempo
- description: HashRing defines the spec for the distributed hash ring configuration.
displayName: Hash Ring
diff --git a/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml b/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml
index 5a309fae3..de8d6a55a 100644
--- a/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml
+++ b/bundle/openshift/manifests/tempo.grafana.com_tempostacks.yaml
@@ -59,6 +59,8 @@ spec:
defined here has precedence and could override generated config.
properties:
tempo:
+ description: Tempo defines any extra Tempo configuration, which
+ will be merged with the operator's generated Tempo configuration
x-kubernetes-preserve-unknown-fields: true
type: object
hashRing:
diff --git a/config/crd/bases/tempo.grafana.com_tempostacks.yaml b/config/crd/bases/tempo.grafana.com_tempostacks.yaml
index 21a86ff84..a59411931 100644
--- a/config/crd/bases/tempo.grafana.com_tempostacks.yaml
+++ b/config/crd/bases/tempo.grafana.com_tempostacks.yaml
@@ -56,6 +56,8 @@ spec:
defined here has precedence and could override generated config.
properties:
tempo:
+ description: Tempo defines any extra Tempo configuration, which
+ will be merged with the operator's generated Tempo configuration
x-kubernetes-preserve-unknown-fields: true
type: object
hashRing:
diff --git a/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml b/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
index 5e3ff8ea9..b97879b30 100644
--- a/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
+++ b/config/manifests/community/bases/tempo-operator.clusterserviceversion.yaml
@@ -22,6 +22,11 @@ spec:
displayName: Tempo Monolithic
kind: TempoMonolithic
name: tempomonolithics.tempo.grafana.com
+ specDescriptors:
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
+ path: extraConfig.tempo
version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
@@ -55,7 +60,9 @@ spec:
specDescriptors:
- displayName: Extra Configurations
path: extraConfig
- - displayName: Tempo Extra Configurations
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
path: extraConfig.tempo
- description: HashRing defines the spec for the distributed hash ring configuration.
displayName: Hash Ring
diff --git a/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml b/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
index 5e3ff8ea9..b97879b30 100644
--- a/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
+++ b/config/manifests/openshift/bases/tempo-operator.clusterserviceversion.yaml
@@ -22,6 +22,11 @@ spec:
displayName: Tempo Monolithic
kind: TempoMonolithic
name: tempomonolithics.tempo.grafana.com
+ specDescriptors:
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
+ path: extraConfig.tempo
version: v1alpha1
- description: TempoStack is the spec for Tempo deployments.
displayName: TempoStack
@@ -55,7 +60,9 @@ spec:
specDescriptors:
- displayName: Extra Configurations
path: extraConfig
- - displayName: Tempo Extra Configurations
+ - description: Tempo defines any extra Tempo configuration, which will be merged
+ with the operator's generated Tempo configuration
+ displayName: Tempo Extra Configurations
path: extraConfig.tempo
- description: HashRing defines the spec for the distributed hash ring configuration.
displayName: Hash Ring
diff --git a/docs/operator/api.md b/docs/operator/api.md
index ac8738806..abf7529a2 100644
--- a/docs/operator/api.md
+++ b/docs/operator/api.md
@@ -572,7 +572,7 @@ Feature Gates.ProjectConfig
-(Appears on:TempoStackSpec)
+(Appears on:TempoMonolithicSpec, TempoStackSpec)
@@ -621,6 +621,8 @@ k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON
(Optional)
+Tempo defines any extra Tempo configuration, which will be merged with the operator’s generated Tempo configuration
+
|
@@ -1609,64 +1611,6 @@ using an in-process OpenPolicyAgent Rego authorizer.
-## MonolithicExtraConfigSpec { #tempo-grafana-com-v1alpha1-MonolithicExtraConfigSpec }
-
-
-
-(Appears on:TempoMonolithicSpec)
-
-
-
-
-
- MonolithicExtraConfigSpec defines extra configuration for this deployment.
-
-
-
-
-
## MonolithicIngestionOTLPProtocolsGRPCSpec { #tempo-grafana-com-v1alpha1-MonolithicIngestionOTLPProtocolsGRPCSpec }
@@ -4944,9 +4888,9 @@ MonolithicObservabilitySpec
-
+
-MonolithicExtraConfigSpec
+ExtraConfigSpec
diff --git a/docs/spec/tempo.grafana.com_tempostacks.yaml b/docs/spec/tempo.grafana.com_tempostacks.yaml
index a2d94299b..cfbbe0631 100644
--- a/docs/spec/tempo.grafana.com_tempostacks.yaml
+++ b/docs/spec/tempo.grafana.com_tempostacks.yaml
@@ -4,7 +4,7 @@ metadata:
name: example
spec: # TempoStackSpec defines the desired state of TempoStack.
extraConfig: # ExtraConfigSpec defines extra configurations for tempo that will be merged with the operator generated, configurations defined here has precedence and could override generated config.
- tempo: {}
+ tempo: {} # Tempo defines any extra Tempo configuration, which will be merged with the operator's generated Tempo configuration
hashRing: # HashRing defines the spec for the distributed hash ring configuration.
memberlist: # MemberList configuration spec
enableIPv6: false # EnableIPv6 enables IPv6 support for the memberlist based hash ring.
diff --git a/internal/manifests/config/configmap.go b/internal/manifests/config/configmap.go
index 2e58c0107..1d9c75017 100644
--- a/internal/manifests/config/configmap.go
+++ b/internal/manifests/config/configmap.go
@@ -40,13 +40,13 @@ func BuildConfigMap(params manifestutils.Params) (*corev1.ConfigMap, string, err
if params.Tempo.Spec.ExtraConfig != nil {
// For we only support tempo for now.
- config, err = mergeExtraConfigWithConfig(params.Tempo.Spec.ExtraConfig.Tempo, config)
+ config, err = MergeExtraConfigWithConfig(params.Tempo.Spec.ExtraConfig.Tempo, config)
if err != nil {
return nil, "", err
}
// Is the same tempo config with certain TLS fields disabled.
- frontendConfig, err = mergeExtraConfigWithConfig(params.Tempo.Spec.ExtraConfig.Tempo, frontendConfig)
+ frontendConfig, err = MergeExtraConfigWithConfig(params.Tempo.Spec.ExtraConfig.Tempo, frontendConfig)
if err != nil {
return nil, "", err
}
diff --git a/internal/manifests/config/extra.go b/internal/manifests/config/extra.go
index 9a14d7272..f7b7d30cd 100644
--- a/internal/manifests/config/extra.go
+++ b/internal/manifests/config/extra.go
@@ -9,7 +9,8 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
-func mergeExtraConfigWithConfig(overridesJSON apiextensionsv1.JSON, templateResults []byte) ([]byte, error) {
+func MergeExtraConfigWithConfig(overridesJSON apiextensionsv1.JSON, templateResults []byte) ([]byte, error) {
+ // mergo.Merge requires that both variables have the same type
renderedTemplateMap := make(map[string]interface{})
overrides := make(map[string]interface{})
@@ -17,6 +18,7 @@ func mergeExtraConfigWithConfig(overridesJSON apiextensionsv1.JSON, templateResu
return templateResults, nil
}
+ // Unmarshal overlay of type []byte to map[string]interface{}
if err := json.Unmarshal(overridesJSON.Raw, &overrides); err != nil {
return nil, err
}
@@ -25,6 +27,7 @@ func mergeExtraConfigWithConfig(overridesJSON apiextensionsv1.JSON, templateResu
return nil, err
}
+ // Override generated config with extra config
if err := mergo.Merge(&renderedTemplateMap, overrides, mergo.WithOverride); err != nil {
return nil, err
}
diff --git a/internal/manifests/config/extra_test.go b/internal/manifests/config/extra_test.go
index 3a74b745d..f2d9e3800 100644
--- a/internal/manifests/config/extra_test.go
+++ b/internal/manifests/config/extra_test.go
@@ -55,7 +55,7 @@ server:
extraConfig := apiextensionsv1.JSON{Raw: raw}
- result, err := mergeExtraConfigWithConfig(extraConfig, []byte(input))
+ result, err := MergeExtraConfigWithConfig(extraConfig, []byte(input))
require.NoError(t, err)
require.YAMLEq(t, expCfg, string(result))
@@ -77,7 +77,7 @@ storage:
`
extraConfig := apiextensionsv1.JSON{}
- result, err := mergeExtraConfigWithConfig(extraConfig, []byte(input))
+ result, err := MergeExtraConfigWithConfig(extraConfig, []byte(input))
require.NoError(t, err)
require.YAMLEq(t, input, string(result))
}
@@ -100,6 +100,6 @@ storage:
Raw: []byte("{{{{}"),
}
- _, err := mergeExtraConfigWithConfig(extraConfig, []byte(input))
+ _, err := MergeExtraConfigWithConfig(extraConfig, []byte(input))
require.Error(t, err)
}
diff --git a/internal/manifests/monolithic/configmap.go b/internal/manifests/monolithic/configmap.go
index e104e5465..85f2c67bf 100644
--- a/internal/manifests/monolithic/configmap.go
+++ b/internal/manifests/monolithic/configmap.go
@@ -2,16 +2,15 @@ package monolithic
import (
"crypto/sha256"
- "encoding/json"
"fmt"
- "github.com/imdario/mergo"
"gopkg.in/yaml.v2"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/grafana/tempo-operator/apis/tempo/v1alpha1"
+ tempoStackConfig "github.com/grafana/tempo-operator/internal/manifests/config"
"github.com/grafana/tempo-operator/internal/manifests/manifestutils"
"github.com/grafana/tempo-operator/internal/manifests/naming"
)
@@ -121,39 +120,16 @@ func buildTempoConfig(opts Options) ([]byte, error) {
}
}
- if tempo.Spec.ExtraConfig == nil || len(tempo.Spec.ExtraConfig.Tempo.Raw) == 0 {
- return yaml.Marshal(config)
- } else {
- return overlayJson(config, tempo.Spec.ExtraConfig.Tempo.Raw)
- }
-}
-
-func overlayJson(config tempoConfig, overlay []byte) ([]byte, error) {
- // mergo.Merge requires that both variables have the same type
- generatedCfg := make(map[string]interface{})
- overlayCfg := make(map[string]interface{})
-
- // Convert tempoConfig{} to map[string]interface{}
generatedYaml, err := yaml.Marshal(config)
if err != nil {
return nil, err
}
- if err := yaml.Unmarshal(generatedYaml, &generatedCfg); err != nil {
- return nil, err
- }
- // Unmarshal overlay of type []byte to map[string]interface{}
- if err := json.Unmarshal(overlay, &overlayCfg); err != nil {
- return nil, err
- }
-
- // Override generated config with extra config
- err = mergo.Merge(&generatedCfg, overlayCfg, mergo.WithOverride)
- if err != nil {
- return nil, err
+ if tempo.Spec.ExtraConfig == nil || len(tempo.Spec.ExtraConfig.Tempo.Raw) == 0 {
+ return generatedYaml, nil
+ } else {
+ return tempoStackConfig.MergeExtraConfigWithConfig(tempo.Spec.ExtraConfig.Tempo, generatedYaml)
}
-
- return yaml.Marshal(generatedCfg)
}
func buildTempoQueryConfig() ([]byte, error) {
diff --git a/internal/manifests/monolithic/configmap_test.go b/internal/manifests/monolithic/configmap_test.go
index ec24d1c17..34b22cf5f 100644
--- a/internal/manifests/monolithic/configmap_test.go
+++ b/internal/manifests/monolithic/configmap_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
configv1alpha1 "github.com/grafana/tempo-operator/apis/config/v1alpha1"
@@ -49,32 +50,18 @@ func TestBuildConfigMap(t *testing.T) {
}
func TestBuildConfig(t *testing.T) {
- opts := Options{
- CtrlConfig: configv1alpha1.ProjectConfig{
- DefaultImages: configv1alpha1.ImagesSpec{
- Tempo: "docker.io/grafana/tempo:x.y.z",
- },
- },
- Tempo: v1alpha1.TempoMonolithic{
- ObjectMeta: metav1.ObjectMeta{
- Name: "sample",
- Namespace: "default",
- },
- Spec: v1alpha1.TempoMonolithicSpec{},
- },
- }
-
tests := []struct {
- name string
- storage *v1alpha1.MonolithicStorageSpec
- ingestion *v1alpha1.MonolithicIngestionSpec
- expected string
+ name string
+ spec v1alpha1.TempoMonolithicSpec
+ expected string
}{
{
name: "memory storage",
- storage: &v1alpha1.MonolithicStorageSpec{
- Traces: v1alpha1.MonolithicTracesStorageSpec{
- Backend: "memory",
+ spec: v1alpha1.TempoMonolithicSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
+ },
},
},
expected: `
@@ -87,26 +74,66 @@ storage:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
+distributor:
+ receivers:
+ otlp:
+ protocols:
+ grpc:
+ http:
usage_report:
reporting_enabled: false
`,
},
{
name: "PV storage with OTLP/gRPC and OTLP/HTTP",
- storage: &v1alpha1.MonolithicStorageSpec{
- Traces: v1alpha1.MonolithicTracesStorageSpec{
- Backend: "pv",
+ spec: v1alpha1.TempoMonolithicSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "pv",
+ },
},
- },
- ingestion: &v1alpha1.MonolithicIngestionSpec{
- OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
- GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
- Enabled: true,
+ Ingestion: &v1alpha1.MonolithicIngestionSpec{
+ OTLP: &v1alpha1.MonolithicIngestionOTLPSpec{
+ GRPC: &v1alpha1.MonolithicIngestionOTLPProtocolsGRPCSpec{
+ Enabled: true,
+ },
+ HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
+ Enabled: true,
+ },
},
- HTTP: &v1alpha1.MonolithicIngestionOTLPProtocolsHTTPSpec{
- Enabled: true,
+ },
+ },
+ expected: `
+server:
+ http_listen_port: 3200
+storage:
+ trace:
+ backend: local
+ wal:
+ path: /var/tempo/wal
+ local:
+ path: /var/tempo/blocks
+distributor:
+ receivers:
+ otlp:
+ protocols:
+ grpc:
+ http:
+usage_report:
+ reporting_enabled: false
+`,
+ },
+ {
+ name: "extra config",
+ spec: v1alpha1.TempoMonolithicSpec{
+ Storage: &v1alpha1.MonolithicStorageSpec{
+ Traces: v1alpha1.MonolithicTracesStorageSpec{
+ Backend: "memory",
},
},
+ ExtraConfig: &v1alpha1.ExtraConfigSpec{
+ Tempo: apiextensionsv1.JSON{Raw: []byte(`{"storage": {"trace": {"wal": {"overlay_setting": "abc"}}}}`)},
+ },
},
expected: `
server:
@@ -116,6 +143,7 @@ storage:
backend: local
wal:
path: /var/tempo/wal
+ overlay_setting: abc
local:
path: /var/tempo/blocks
distributor:
@@ -132,8 +160,22 @@ usage_report:
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- opts.Tempo.Spec.Storage = test.storage
- opts.Tempo.Spec.Ingestion = test.ingestion
+ opts := Options{
+ CtrlConfig: configv1alpha1.ProjectConfig{
+ DefaultImages: configv1alpha1.ImagesSpec{
+ Tempo: "docker.io/grafana/tempo:x.y.z",
+ },
+ },
+ Tempo: v1alpha1.TempoMonolithic{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "sample",
+ Namespace: "default",
+ },
+ Spec: test.spec,
+ },
+ }
+ opts.Tempo.Default()
+
cfg, err := buildTempoConfig(opts)
require.NoError(t, err)
require.YAMLEq(t, test.expected, string(cfg))
From c5eba0d6a92a2933305c9d74e8825ec8a18a0b07 Mon Sep 17 00:00:00 2001
From: Andreas Gerstmayr
Date: Fri, 26 Jan 2024 13:19:44 +0100
Subject: [PATCH 36/36] add comment on exported function
Signed-off-by: Andreas Gerstmayr
---
internal/manifests/config/extra.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/internal/manifests/config/extra.go b/internal/manifests/config/extra.go
index f7b7d30cd..f80c25c0f 100644
--- a/internal/manifests/config/extra.go
+++ b/internal/manifests/config/extra.go
@@ -9,6 +9,7 @@ import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
)
+// MergeExtraConfigWithConfig overlays configuration from overridesJSON onto templateResults.
func MergeExtraConfigWithConfig(overridesJSON apiextensionsv1.JSON, templateResults []byte) ([]byte, error) {
// mergo.Merge requires that both variables have the same type
renderedTemplateMap := make(map[string]interface{})
| | | | |