diff --git a/apis/tempo/v1alpha1/tempomonolithic_defaults.go b/apis/tempo/v1alpha1/tempomonolithic_defaults.go index 7f4ca0973..824823b03 100644 --- a/apis/tempo/v1alpha1/tempomonolithic_defaults.go +++ b/apis/tempo/v1alpha1/tempomonolithic_defaults.go @@ -46,4 +46,10 @@ func (r *TempoMonolithic) Default() { Enabled: true, } } + + if r.Spec.JaegerUI != nil && r.Spec.JaegerUI.Enabled && + r.Spec.JaegerUI.Route != nil && r.Spec.JaegerUI.Route.Enabled && + r.Spec.JaegerUI.Route.Termination == "" { + r.Spec.JaegerUI.Route.Termination = "edge" + } } diff --git a/apis/tempo/v1alpha1/tempomonolithic_types.go b/apis/tempo/v1alpha1/tempomonolithic_types.go index bf89df673..9a5563c5f 100644 --- a/apis/tempo/v1alpha1/tempomonolithic_types.go +++ b/apis/tempo/v1alpha1/tempomonolithic_types.go @@ -157,6 +157,23 @@ type MonolithicJaegerUIIngressSpec struct { // // +kubebuilder:validation:Required Enabled bool `json:"enabled"` + + // Annotations defines the annotations of the Ingress object. + // + // +kubebuilder:validation:Optional + Annotations map[string]string `json:"annotations,omitempty"` + + // Host defines the hostname of the Ingress object. + // + // +kubebuilder:validation:Optional + Host string `json:"host,omitempty"` + + // IngressClassName is the name of an IngressClass cluster resource. Ingress + // controller implementations use this field to know whether they should be + // serving this Ingress resource. + // + // +kubebuilder:validation:Optional + IngressClassName *string `json:"ingressClassName,omitempty"` } // MonolithicJaegerUIRouteSpec defines the settings for the Jaeger UI route. @@ -165,6 +182,22 @@ type MonolithicJaegerUIRouteSpec struct { // // +kubebuilder:validation:Required Enabled bool `json:"enabled"` + + // Annotations defines the annotations of the Route object. + // + // +kubebuilder:validation:Optional + Annotations map[string]string `json:"annotations,omitempty"` + + // Host defines the hostname of the Route object. + // + // +kubebuilder:validation:Optional + Host string `json:"host,omitempty"` + + // Termination specifies the termination type. Default: edge. + // + // +kubebuilder:validation:Optional + // +kubebuilder:default=edge + Termination TLSRouteTerminationType `json:"termination,omitempty"` } // MonolithicObservabilitySpec defines the observability settings of the Tempo deployment. diff --git a/apis/tempo/v1alpha1/zz_generated.deepcopy.go b/apis/tempo/v1alpha1/zz_generated.deepcopy.go index 2ffc63737..47fd244ec 100644 --- a/apis/tempo/v1alpha1/zz_generated.deepcopy.go +++ b/apis/tempo/v1alpha1/zz_generated.deepcopy.go @@ -444,6 +444,18 @@ func (in *MonolithicIngestionSpec) DeepCopy() *MonolithicIngestionSpec { // 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 + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.IngressClassName != nil { + in, out := &in.IngressClassName, &out.IngressClassName + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicJaegerUIIngressSpec. @@ -459,6 +471,13 @@ func (in *MonolithicJaegerUIIngressSpec) DeepCopy() *MonolithicJaegerUIIngressSp // 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 + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonolithicJaegerUIRouteSpec. @@ -477,12 +496,12 @@ func (in *MonolithicJaegerUISpec) DeepCopyInto(out *MonolithicJaegerUISpec) { if in.Ingress != nil { in, out := &in.Ingress, &out.Ingress *out = new(MonolithicJaegerUIIngressSpec) - **out = **in + (*in).DeepCopyInto(*out) } if in.Route != nil { in, out := &in.Route, &out.Route *out = new(MonolithicJaegerUIRouteSpec) - **out = **in + (*in).DeepCopyInto(*out) } } diff --git a/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/community/manifests/tempo-operator.clusterserviceversion.yaml index f839ea08d..458ca0c48 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-26T12:10:07Z" + createdAt: "2024-01-26T16:53: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 e43b04047..fc3224560 100644 --- a/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml +++ b/bundle/community/manifests/tempo.grafana.com_tempomonolithics.yaml @@ -84,10 +84,25 @@ spec: description: Ingress defines the ingress configuration for Jaeger UI properties: + annotations: + additionalProperties: + type: string + description: Annotations defines the annotations of the Ingress + object. + type: object enabled: description: Enabled defines if an Ingress object should be created for Jaeger UI type: boolean + host: + description: Host defines the hostname of the Ingress object. + type: string + ingressClassName: + description: IngressClassName is the name of an IngressClass + cluster resource. Ingress controller implementations use + this field to know whether they should be serving this Ingress + resource. + type: string required: - enabled type: object @@ -95,10 +110,29 @@ spec: description: Route defines the route configuration for Jaeger UI properties: + annotations: + additionalProperties: + type: string + description: Annotations defines the annotations of the Route + object. + type: object enabled: description: Enabled defines if a Route object should be created for Jaeger UI type: boolean + host: + description: Host defines the hostname of the Route object. + type: string + termination: + default: edge + description: 'Termination specifies the termination type. + Default: edge.' + enum: + - insecure + - edge + - passthrough + - reencrypt + type: string required: - enabled type: object diff --git a/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/tempo-operator.clusterserviceversion.yaml index c449b0849..299a7c956 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-26T12:10:06Z" + createdAt: "2024-01-26T16:53:17Z" 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 e43b04047..fc3224560 100644 --- a/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml +++ b/bundle/openshift/manifests/tempo.grafana.com_tempomonolithics.yaml @@ -84,10 +84,25 @@ spec: description: Ingress defines the ingress configuration for Jaeger UI properties: + annotations: + additionalProperties: + type: string + description: Annotations defines the annotations of the Ingress + object. + type: object enabled: description: Enabled defines if an Ingress object should be created for Jaeger UI type: boolean + host: + description: Host defines the hostname of the Ingress object. + type: string + ingressClassName: + description: IngressClassName is the name of an IngressClass + cluster resource. Ingress controller implementations use + this field to know whether they should be serving this Ingress + resource. + type: string required: - enabled type: object @@ -95,10 +110,29 @@ spec: description: Route defines the route configuration for Jaeger UI properties: + annotations: + additionalProperties: + type: string + description: Annotations defines the annotations of the Route + object. + type: object enabled: description: Enabled defines if a Route object should be created for Jaeger UI type: boolean + host: + description: Host defines the hostname of the Route object. + type: string + termination: + default: edge + description: 'Termination specifies the termination type. + Default: edge.' + enum: + - insecure + - edge + - passthrough + - reencrypt + type: string required: - enabled type: object diff --git a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml index f81b4b6c7..9509a3385 100644 --- a/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml +++ b/config/crd/bases/tempo.grafana.com_tempomonolithics.yaml @@ -81,10 +81,25 @@ spec: description: Ingress defines the ingress configuration for Jaeger UI properties: + annotations: + additionalProperties: + type: string + description: Annotations defines the annotations of the Ingress + object. + type: object enabled: description: Enabled defines if an Ingress object should be created for Jaeger UI type: boolean + host: + description: Host defines the hostname of the Ingress object. + type: string + ingressClassName: + description: IngressClassName is the name of an IngressClass + cluster resource. Ingress controller implementations use + this field to know whether they should be serving this Ingress + resource. + type: string required: - enabled type: object @@ -92,10 +107,29 @@ spec: description: Route defines the route configuration for Jaeger UI properties: + annotations: + additionalProperties: + type: string + description: Annotations defines the annotations of the Route + object. + type: object enabled: description: Enabled defines if a Route object should be created for Jaeger UI type: boolean + host: + description: Host defines the hostname of the Route object. + type: string + termination: + default: edge + description: 'Termination specifies the termination type. + Default: edge.' + enum: + - insecure + - edge + - passthrough + - reencrypt + type: string required: - enabled type: object diff --git a/controllers/tempo/tempomonolithic_controller.go b/controllers/tempo/tempomonolithic_controller.go index 0e3492d1d..9b85c50f5 100644 --- a/controllers/tempo/tempomonolithic_controller.go +++ b/controllers/tempo/tempomonolithic_controller.go @@ -150,11 +150,16 @@ func (r *TempoMonolithicReconciler) getOwnedObjects(ctx context.Context, tempo v // SetupWithManager sets up the controller with the Manager. func (r *TempoMonolithicReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). + builder := ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.TempoMonolithic{}). Owns(&corev1.ConfigMap{}). Owns(&corev1.Service{}). Owns(&appsv1.StatefulSet{}). - Owns(&networkingv1.Ingress{}). - Complete(r) + Owns(&networkingv1.Ingress{}) + + if r.CtrlConfig.Gates.OpenShift.OpenShiftRoute { + builder = builder.Owns(&routev1.Route{}) + } + + return builder.Complete(r) } diff --git a/docs/operator/api.md b/docs/operator/api.md index 1e6b8fc4f..cbd4fd797 100644 --- a/docs/operator/api.md +++ b/docs/operator/api.md @@ -1861,6 +1861,71 @@ bool +
annotations
Annotations defines the annotations of the Ingress object.
+ +host
Host defines the hostname of the Ingress object.
+ +ingressClassName
IngressClassName is the name of an IngressClass cluster resource. Ingress +controller implementations use this field to know whether they should be +serving this Ingress resource.
+ +annotations
Annotations defines the annotations of the Route object.
+ +host
Host defines the hostname of the Route object.
+ +termination
Termination specifies the termination type. Default: edge.
+ +-(Appears on:RouteSpec) +(Appears on:MonolithicJaegerUIRouteSpec, RouteSpec)
diff --git a/docs/spec/tempo.grafana.com_tempomonolithics.yaml b/docs/spec/tempo.grafana.com_tempomonolithics.yaml index f3c18340f..8b491400c 100644 --- a/docs/spec/tempo.grafana.com_tempomonolithics.yaml +++ b/docs/spec/tempo.grafana.com_tempomonolithics.yaml @@ -14,9 +14,17 @@ spec: # TempoMonolithicSpec defines the desir 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 + annotations: # Annotations defines the annotations of the Ingress object. + "key": "" enabled: false # Enabled defines if an Ingress object should be created for Jaeger UI + host: "" # Host defines the hostname of the Ingress object. + ingressClassName: "" # IngressClassName is the name of an IngressClass cluster resource. Ingress controller implementations use this field to know whether they should be serving this Ingress resource. route: # Route defines the route configuration for Jaeger UI + annotations: # Annotations defines the annotations of the Route object. + "key": "" enabled: false # Enabled defines if a Route object should be created for Jaeger UI + host: "" # Host defines the hostname of the Route object. + termination: "edge" # Termination specifies the termination type. Default: edge. 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 diff --git a/internal/manifests/monolithic/build.go b/internal/manifests/monolithic/build.go index 4a2662772..8d3fd0f79 100644 --- a/internal/manifests/monolithic/build.go +++ b/internal/manifests/monolithic/build.go @@ -24,5 +24,11 @@ func BuildAll(opts Options) ([]client.Object, error) { service := BuildTempoService(opts) manifests = append(manifests, service) + ingresses, err := BuildTempoIngress(opts) + if err != nil { + return nil, err + } + manifests = append(manifests, ingresses...) + return manifests, nil } diff --git a/internal/manifests/monolithic/ingress.go b/internal/manifests/monolithic/ingress.go new file mode 100644 index 000000000..6455ef024 --- /dev/null +++ b/internal/manifests/monolithic/ingress.go @@ -0,0 +1,132 @@ +package monolithic + +import ( + "fmt" + + routev1 "github.com/openshift/api/route/v1" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/grafana/tempo-operator/apis/tempo/v1alpha1" + "github.com/grafana/tempo-operator/internal/manifests/manifestutils" + "github.com/grafana/tempo-operator/internal/manifests/naming" +) + +// BuildTempoIngress creates the ingress for a monolithic deployment. +func BuildTempoIngress(opts Options) ([]client.Object, error) { + var manifests []client.Object + tempo := opts.Tempo + + if tempo.Spec.JaegerUI != nil && tempo.Spec.JaegerUI.Enabled { + if tempo.Spec.JaegerUI.Ingress != nil && tempo.Spec.JaegerUI.Ingress.Enabled { + manifests = append(manifests, buildJaegerUIIngress(opts)) + } + if tempo.Spec.JaegerUI.Route != nil && tempo.Spec.JaegerUI.Route.Enabled { + route, err := buildJaegerUIRoute(opts) + if err != nil { + return nil, err + } + manifests = append(manifests, route) + } + } + + return manifests, nil +} + +func buildJaegerUIIngress(opts Options) *networkingv1.Ingress { + tempo := opts.Tempo + labels := Labels(tempo.Name) + ingress := &networkingv1.Ingress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: networkingv1.SchemeGroupVersion.String(), + Kind: "Ingress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: naming.Name("jaegerui", tempo.Name), + Namespace: tempo.Namespace, + Labels: labels, + Annotations: tempo.Spec.JaegerUI.Ingress.Annotations, + }, + Spec: networkingv1.IngressSpec{ + IngressClassName: tempo.Spec.JaegerUI.Ingress.IngressClassName, + }, + } + + backend := networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: naming.Name("", tempo.Name), + Port: networkingv1.ServiceBackendPort{ + Name: manifestutils.JaegerUIPortName, + }, + }, + } + + if tempo.Spec.JaegerUI.Ingress.Host == "" { + ingress.Spec.DefaultBackend = &backend + } else { + ingress.Spec.Rules = []networkingv1.IngressRule{ + { + Host: tempo.Spec.JaegerUI.Ingress.Host, + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/", + PathType: ptr.To(networkingv1.PathTypePrefix), + Backend: backend, + }, + }, + }, + }, + }, + } + } + + return ingress +} + +func buildJaegerUIRoute(opts Options) (*routev1.Route, error) { + tempo := opts.Tempo + labels := Labels(tempo.Name) + + var tlsCfg *routev1.TLSConfig + switch tempo.Spec.JaegerUI.Route.Termination { + case v1alpha1.TLSRouteTerminationTypeInsecure: + // NOTE: insecure, no tls cfg. + case v1alpha1.TLSRouteTerminationTypeEdge: + tlsCfg = &routev1.TLSConfig{Termination: routev1.TLSTerminationEdge} + case v1alpha1.TLSRouteTerminationTypePassthrough: + tlsCfg = &routev1.TLSConfig{Termination: routev1.TLSTerminationPassthrough} + case v1alpha1.TLSRouteTerminationTypeReencrypt: + tlsCfg = &routev1.TLSConfig{Termination: routev1.TLSTerminationReencrypt} + default: // NOTE: if unsupported, end here. + return nil, fmt.Errorf("unsupported tls termination '%s' specified for route", tempo.Spec.JaegerUI.Route.Termination) + } + + return &routev1.Route{ + TypeMeta: metav1.TypeMeta{ + APIVersion: networkingv1.SchemeGroupVersion.String(), + Kind: "Ingress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: naming.Name("jaegerui", tempo.Name), + Namespace: tempo.Namespace, + Labels: labels, + Annotations: tempo.Spec.JaegerUI.Route.Annotations, + }, + Spec: routev1.RouteSpec{ + Host: tempo.Spec.JaegerUI.Route.Host, + To: routev1.RouteTargetReference{ + Kind: "Service", + Name: naming.Name("", tempo.Name), + }, + Port: &routev1.RoutePort{ + TargetPort: intstr.FromString(manifestutils.JaegerUIPortName), + }, + TLS: tlsCfg, + }, + }, nil +} diff --git a/internal/manifests/monolithic/ingress_test.go b/internal/manifests/monolithic/ingress_test.go new file mode 100644 index 000000000..eaaae8789 --- /dev/null +++ b/internal/manifests/monolithic/ingress_test.go @@ -0,0 +1,193 @@ +package monolithic + +import ( + "errors" + "testing" + + routev1 "github.com/openshift/api/route/v1" + "github.com/stretchr/testify/require" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/grafana/tempo-operator/apis/tempo/v1alpha1" +) + +func TestBuildTempoIngress(t *testing.T) { + opts := Options{ + Tempo: v1alpha1.TempoMonolithic{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sample", + Namespace: "default", + }, + }, + } + labels := Labels("sample") + + tests := []struct { + name string + input v1alpha1.TempoMonolithicSpec + expected []client.Object + expectedErr error + }{ + { + name: "no jaeger ui", + input: v1alpha1.TempoMonolithicSpec{}, + expected: nil, + }, + { + name: "jaeger ui, but no ingress", + input: v1alpha1.TempoMonolithicSpec{ + JaegerUI: &v1alpha1.MonolithicJaegerUISpec{ + Enabled: true, + }, + }, + expected: nil, + }, + { + name: "ingress", + input: v1alpha1.TempoMonolithicSpec{ + JaegerUI: &v1alpha1.MonolithicJaegerUISpec{ + Enabled: true, + Ingress: &v1alpha1.MonolithicJaegerUIIngressSpec{ + Enabled: true, + }, + }, + }, + expected: []client.Object{ + &networkingv1.Ingress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "networking.k8s.io/v1", + Kind: "Ingress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tempo-sample-jaegerui", + Namespace: "default", + Labels: labels, + }, + Spec: networkingv1.IngressSpec{ + DefaultBackend: &networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "tempo-sample", + Port: networkingv1.ServiceBackendPort{ + Name: "jaeger-ui", + }, + }, + }, + }, + }, + }, + }, + { + name: "ingress with host", + input: v1alpha1.TempoMonolithicSpec{ + JaegerUI: &v1alpha1.MonolithicJaegerUISpec{ + Enabled: true, + Ingress: &v1alpha1.MonolithicJaegerUIIngressSpec{ + Enabled: true, + Host: "abc", + }, + }, + }, + expected: []client.Object{ + &networkingv1.Ingress{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "networking.k8s.io/v1", + Kind: "Ingress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tempo-sample-jaegerui", + Namespace: "default", + Labels: labels, + }, + Spec: networkingv1.IngressSpec{ + Rules: []networkingv1.IngressRule{ + { + Host: "abc", + IngressRuleValue: networkingv1.IngressRuleValue{ + HTTP: &networkingv1.HTTPIngressRuleValue{ + Paths: []networkingv1.HTTPIngressPath{ + { + Path: "/", + PathType: ptr.To(networkingv1.PathTypePrefix), + Backend: networkingv1.IngressBackend{ + Service: &networkingv1.IngressServiceBackend{ + Name: "tempo-sample", + Port: networkingv1.ServiceBackendPort{ + Name: "jaeger-ui", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "route", + input: v1alpha1.TempoMonolithicSpec{ + JaegerUI: &v1alpha1.MonolithicJaegerUISpec{ + Enabled: true, + Route: &v1alpha1.MonolithicJaegerUIRouteSpec{ + Enabled: true, + Termination: "edge", + }, + }, + }, + expected: []client.Object{ + &routev1.Route{ + TypeMeta: metav1.TypeMeta{ + APIVersion: networkingv1.SchemeGroupVersion.String(), + Kind: "Ingress", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "tempo-sample-jaegerui", + Namespace: "default", + Labels: labels, + }, + Spec: routev1.RouteSpec{ + Host: "", + To: routev1.RouteTargetReference{ + Kind: "Service", + Name: "tempo-sample", + }, + Port: &routev1.RoutePort{ + TargetPort: intstr.FromString("jaeger-ui"), + }, + TLS: &routev1.TLSConfig{Termination: routev1.TLSTerminationEdge}, + }, + }, + }, + }, + { + name: "route with invalid tls", + input: v1alpha1.TempoMonolithicSpec{ + JaegerUI: &v1alpha1.MonolithicJaegerUISpec{ + Enabled: true, + Route: &v1alpha1.MonolithicJaegerUIRouteSpec{ + Enabled: true, + Termination: "invalid", + }, + }, + }, + expected: nil, + expectedErr: errors.New("unsupported tls termination 'invalid' specified for route"), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + opts.Tempo.Spec = test.input + ingresses, err := BuildTempoIngress(opts) + require.Equal(t, test.expectedErr, err) + require.Equal(t, test.expected, ingresses) + }) + } +}