Skip to content

Commit 6a188c0

Browse files
Add env vars to configure OpenTelemetry metrics/tracing
1 parent 9b66494 commit 6a188c0

6 files changed

+267
-0
lines changed

api/gorch/v1alpha1/guardrailsorchestrator_types.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,37 @@ type GuardrailsOrchestratorSpec struct {
3434
Replicas int32 `json:"replicas"`
3535
// Name of configmap containing generator,detector,and chunker arguments
3636
OrchestratorConfig *string `json:"orchestratorConfig"`
37+
// Name of the configmap containg vLLM gateway arguments
3738
// +optional
3839
VLLMGatewayConfig *string `json:"vllmGatewayConfig,omitempty"`
40+
// List of orchestrator enviroment variables for configuring the OTLP exporter
41+
// +optional
42+
OtelExporter OtelExporter `json:"otelExporter,omitempty"`
43+
}
44+
45+
// OtelExporter defines the environment variables for configuring the OTLP exporter.
46+
type OtelExporter struct {
47+
// Sets the protocol for all the OTLP endpoints
48+
// +optional
49+
Protocol string `json:"protocol,omitempty"`
50+
// Overrides the protocol for traces
51+
// +optional
52+
TracesProtocol string `json:"tracesProtocol,omitempty"`
53+
// Overrides the protocol for traces
54+
// +optional
55+
MetricsProtocol string `json:"metricsProtocol,omitempty"`
56+
// Sets the OTLP endpoint
57+
// +optional
58+
OTLPEndpoint string `json:"otlpEndpoint,omitempty"`
59+
// Overrides the OTLP endpoint for metrics
60+
// +optional
61+
MetricsEndpoint string `json:"metricsEndpoint,omitempty"`
62+
// Overrides the OTLP endpoint for traces
63+
// +optional
64+
TracesEndpoint string `json:"tracesEndpoint,omitempty"`
65+
// Specifies which data types to export
66+
// +optional
67+
OTLPExport string `json:"otlpExport,omitempty"`
3968
}
4069

4170
type ConditionType string

api/gorch/v1alpha1/zz_generated.deepcopy.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/trustyai.opendatahub.io_guardrailsorchestrators.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,38 @@ spec:
4444
description: Name of configmap containing generator,detector,and chunker
4545
arguments
4646
type: string
47+
otelExporter:
48+
description: List of orchestrator enviroment variables for configuring
49+
the OTLP exporter
50+
properties:
51+
metricsEndpoint:
52+
description: Overrides the OTLP endpoint for metrics
53+
type: string
54+
metricsProtocol:
55+
description: Overrides the protocol for traces
56+
type: string
57+
otlpEndpoint:
58+
description: Sets the OTLP endpoint
59+
type: string
60+
otlpExport:
61+
description: Specifies which data types to export
62+
type: string
63+
protocol:
64+
description: Sets the protocol for all the OTLP endpoints
65+
type: string
66+
tracesEndpoint:
67+
description: Overrides the OTLP endpoint for traces
68+
type: string
69+
tracesProtocol:
70+
description: Overrides the protocol for traces
71+
type: string
72+
type: object
4773
replicas:
4874
description: Number of replicas
4975
format: int32
5076
type: integer
5177
vllmGatewayConfig:
78+
description: ' Name of the configmap containg vLLM gateway arguments'
5279
type: string
5380
required:
5481
- orchestratorConfig

controllers/gorch/guardrailsorchestrator_controller_test.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ func createGuardrailsOrchestratorSidecar(ctx context.Context, orchestratorConfig
7777
return err
7878
}
7979

80+
func createGuardrailsOrchestratorOtelExporter(ctx context.Context, orchestratorConfigMap string) error {
81+
typedNamespacedName := types.NamespacedName{Name: orchestratorName, Namespace: namespaceName}
82+
otelExporter := gorchv1alpha1.OtelExporter{
83+
Protocol: "grpc",
84+
OTLPEndpoint: "localhost:4317",
85+
OTLPExport: "traces",
86+
}
87+
err := k8sClient.Get(ctx, typedNamespacedName, &gorchv1alpha1.GuardrailsOrchestrator{})
88+
if err != nil && errors.IsNotFound(err) {
89+
gorch := &gorchv1alpha1.GuardrailsOrchestrator{
90+
ObjectMeta: metav1.ObjectMeta{
91+
Name: typedNamespacedName.Name,
92+
Namespace: typedNamespacedName.Namespace,
93+
},
94+
Spec: gorchv1alpha1.GuardrailsOrchestratorSpec{
95+
Replicas: 1,
96+
OrchestratorConfig: &orchestratorConfigMap,
97+
OtelExporter: otelExporter,
98+
},
99+
}
100+
err = k8sClient.Create(ctx, gorch)
101+
}
102+
return err
103+
}
104+
80105
func deleteGuardrailsOrchestrator(ctx context.Context, namespace string) error {
81106
typedNamespacedName := types.NamespacedName{Name: orchestratorName, Namespace: namespace}
82107
err := k8sClient.Get(ctx, typedNamespacedName, &gorchv1alpha1.GuardrailsOrchestrator{})
@@ -336,9 +361,134 @@ func testCreateDeleteGuardrailsOrchestratorSidecar(namespaceName string) {
336361
})
337362
}
338363

364+
func testCreateDeleteGuardrailsOrchestratorOtelExporter(namespaceName string) {
365+
It("Should sucessfully reconcile creating a custom resource for the GuardrailsOrchestrator", func() {
366+
By("Creating an Orchestrator configmap")
367+
configMap := &corev1.ConfigMap{
368+
TypeMeta: metav1.TypeMeta{
369+
Kind: "ConfigMap",
370+
APIVersion: "v1",
371+
},
372+
ObjectMeta: metav1.ObjectMeta{
373+
Name: orchestratorName + "-config",
374+
Namespace: namespaceName,
375+
},
376+
}
377+
err := k8sClient.Create(ctx, configMap)
378+
Expect(err).ToNot(HaveOccurred())
379+
380+
By("Creating a custom resource for the GuardrailsOrchestrator")
381+
ctx := context.Background()
382+
typedNamespacedName := types.NamespacedName{Name: orchestratorName, Namespace: namespaceName}
383+
err = createGuardrailsOrchestratorOtelExporter(ctx, configMap.Name)
384+
Expect(err).ToNot(HaveOccurred())
385+
386+
By("Checking if the custom resource was successfully created")
387+
err = k8sClient.Get(ctx, typedNamespacedName, &gorchv1alpha1.GuardrailsOrchestrator{})
388+
Expect(err).ToNot(HaveOccurred())
389+
390+
By("Creating the TrustyAI configmap with sidecar images")
391+
configMap = &corev1.ConfigMap{
392+
TypeMeta: metav1.TypeMeta{
393+
Kind: "ConfigMap",
394+
APIVersion: "v1",
395+
},
396+
ObjectMeta: metav1.ObjectMeta{
397+
Name: constants.ConfigMap,
398+
Namespace: namespaceName,
399+
},
400+
Data: map[string]string{
401+
orchestratorImageKey: "quay.io/trustyai/ta-guardrails-orchestrator:latest",
402+
},
403+
}
404+
err = k8sClient.Create(ctx, configMap)
405+
Expect(err).ToNot(HaveOccurred())
406+
407+
By("Reconciling the custom resource that was created")
408+
reconciler := &GuardrailsOrchestratorReconciler{
409+
Client: k8sClient,
410+
Scheme: k8sClient.Scheme(),
411+
}
412+
413+
_, err = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typedNamespacedName})
414+
Expect(err).ToNot(HaveOccurred())
415+
416+
By("Checking if resources were successfully created in the reconcilation")
417+
Eventually(func() error {
418+
configMap := &corev1.ConfigMap{}
419+
if err := k8sClient.Get(ctx, types.NamespacedName{Name: constants.ConfigMap, Namespace: namespaceName}, configMap); err != nil {
420+
return err
421+
}
422+
Expect(configMap.Namespace).Should(Equal(namespaceName))
423+
Expect(configMap.Name).Should(Equal(constants.ConfigMap))
424+
425+
serviceAccount := &corev1.ServiceAccount{}
426+
if err := k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName + "-serviceaccount", Namespace: namespaceName}, serviceAccount); err != nil {
427+
return err
428+
}
429+
430+
deployment := &appsv1.Deployment{}
431+
if err = k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName, Namespace: namespaceName}, deployment); err != nil {
432+
return err
433+
}
434+
var container *corev1.Container
435+
var envVar *corev1.EnvVar
436+
Expect(*deployment.Spec.Replicas).Should(Equal(int32(1)))
437+
Expect(deployment.Namespace).Should(Equal(namespaceName))
438+
Expect(deployment.Name).Should(Equal(orchestratorName))
439+
Expect(deployment.Labels["app"]).Should(Equal(orchestratorName))
440+
Expect(deployment.Spec.Template.Spec.Volumes[0].Name).Should(Equal(orchestratorName + "-config"))
441+
container = getContainers(orchestratorName, deployment.Spec.Template.Spec.Containers)
442+
Expect(container.Image).Should(Equal("quay.io/trustyai/ta-guardrails-orchestrator:latest"))
443+
Expect(container.VolumeMounts[0].Name).Should(Equal(orchestratorName + "-config"))
444+
envVar = getEnvVar("OTEL_EXPORTER_OTLP_PROTOCOL", container.Env)
445+
Expect(envVar).ShouldNot(BeNil())
446+
Expect(envVar.Value).To(Equal("grpc"))
447+
envVar = getEnvVar("OTEL_EXPORTER_OTLP_ENDPOINT", container.Env)
448+
Expect(envVar).ShouldNot(BeNil())
449+
Expect(envVar.Value).To(Equal("localhost:4317"))
450+
envVar = getEnvVar("OTLP_EXPORT", container.Env)
451+
Expect(envVar).ShouldNot(BeNil())
452+
Expect(envVar.Value).To(Equal("traces"))
453+
454+
service := &corev1.Service{}
455+
if err := k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName + "-service", Namespace: namespaceName}, service); err != nil {
456+
return err
457+
}
458+
Expect(service.Namespace).Should(Equal(namespaceName))
459+
460+
route := &routev1.Route{}
461+
if err := routev1.AddToScheme(scheme.Scheme); err != nil {
462+
return err
463+
}
464+
if err := k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName + "-route", Namespace: namespaceName}, route); err != nil {
465+
return err
466+
}
467+
return nil
468+
}, time.Second*10, time.Millisecond*10).Should(Succeed())
469+
470+
By("Deleting the custom resource for the GuardrailsOrchestrator")
471+
err = deleteGuardrailsOrchestrator(ctx, namespaceName)
472+
Expect(err).ToNot(HaveOccurred())
473+
474+
By("Deleting the orchestrator configmap")
475+
err = k8sClient.Delete(ctx, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: orchestratorName + "-config", Namespace: namespaceName}})
476+
Expect(err).ToNot(HaveOccurred())
477+
478+
By("Deleting the TrustyAI configmap")
479+
err = k8sClient.Delete(ctx, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: constants.ConfigMap, Namespace: namespaceName}})
480+
Expect(err).ToNot(HaveOccurred())
481+
482+
By("Reconciling the custom resource that was deleted")
483+
_, err = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typedNamespacedName})
484+
Expect(err).ToNot(HaveOccurred())
485+
})
486+
}
487+
339488
var _ = Describe("GuardrailsOrchestrator Controller", func() {
340489
Context("GuardrailsOrchestrator Controller Test", func() {
341490
testCreateDeleteGuardrailsOrchestrator(namespaceName)
342491
testCreateDeleteGuardrailsOrchestratorSidecar(namespaceName)
492+
testCreateDeleteGuardrailsOrchestratorOtelExporter(namespaceName)
343493
})
344494
})

controllers/gorch/suite_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,23 @@ var cancel context.CancelFunc
4949

5050
const namespaceName = "test"
5151

52+
func getContainers(containerName string, containers []corev1.Container) *corev1.Container {
53+
for _, container := range containers {
54+
if container.Name == containerName {
55+
return &container
56+
}
57+
}
58+
return nil
59+
}
60+
func getEnvVar(envVarName string, envVars []corev1.EnvVar) *corev1.EnvVar {
61+
for _, envVar := range envVars {
62+
if envVar.Name == envVarName {
63+
return &envVar
64+
}
65+
}
66+
return nil
67+
}
68+
5269
func TestControllers(t *testing.T) {
5370
RegisterFailHandler(Fail)
5471

controllers/gorch/templates/deployment.tmpl.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,34 @@ spec:
5858
value: 'full'
5959
- name: RUST_LOG
6060
value: 'info'
61+
{{if .Orchestrator.Spec.OtelExporter.Protocol}}
62+
- name: OTEL_EXPORTER_OTLP_PROTOCOL
63+
value: {{.Orchestrator.Spec.OtelExporter.Protocol}}
64+
{{end}}
65+
{{if .Orchestrator.Spec.OtelExporter.TracesProtocol}}
66+
- name: OTEL_EXPORTER_OTLP_TRACES_PROTOCOL
67+
value: {{.Orchestrator.Spec.OtelExporter.TracesProtocol}}
68+
{{end}}
69+
{{if .Orchestrator.Spec.OtelExporter.MetricsProtocol}}
70+
- name: OTEL_EXPORTER_OTLP_METRICS_PROTOCOL
71+
value: {{.Orchestrator.Spec.OtelExporter.MetricsProtocol}}
72+
{{end}}
73+
{{if .Orchestrator.Spec.OtelExporter.OTLPEndpoint}}
74+
- name: OTEL_EXPORTER_OTLP_ENDPOINT
75+
value: {{.Orchestrator.Spec.OtelExporter.OTLPEndpoint}}
76+
{{end}}
77+
{{if .Orchestrator.Spec.OtelExporter.TracesEndpoint}}
78+
- name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
79+
value: {{.Orchestrator.Spec.OtelExporter.TracesEndpoint}}
80+
{{end}}
81+
{{if .Orchestrator.Spec.OtelExporter.MetricsEndpoint}}
82+
- name: OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
83+
value: {{.Orchestrator.Spec.OtelExporter.MetricsEndpoint}}
84+
{{end}}
85+
{{if .Orchestrator.Spec.OtelExporter.OTLPExport}}
86+
- name: OTLP_EXPORT
87+
value: {{.Orchestrator.Spec.OtelExporter.OTLPExport}}
88+
{{end}}
6189
volumeMounts:
6290
- name: {{.Orchestrator.Name}}-config
6391
readOnly: true

0 commit comments

Comments
 (0)