From 67baec34a7fc76faf982b634538c0c2d89c0854e Mon Sep 17 00:00:00 2001 From: Christina Xu Date: Tue, 14 Jan 2025 13:39:52 -0500 Subject: [PATCH] Update deployment --- .../v1alpha1/guardrailsorchestrator_types.go | 9 ++-- config/base/params.env | 2 +- ...pendatahub.io_guardrailsorchestrators.yaml | 10 +++- config/overlays/odh/params.env | 2 +- config/overlays/rhoai/params.env | 2 +- controllers/gorch/configmap.go | 29 +++++++++++ controllers/gorch/deployment.go | 9 ++-- .../guardrailsorchestrator_controller.go | 15 ++++++ .../guardrailsorchestrator_controller_test.go | 11 +++++ .../gorch/templates/configmap.tmpl.yaml | 35 +++++++++++++ .../gorch/templates/deployment.tmpl.yaml | 49 ++++++++++++------- 11 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 controllers/gorch/templates/configmap.tmpl.yaml diff --git a/api/gorch/v1alpha1/guardrailsorchestrator_types.go b/api/gorch/v1alpha1/guardrailsorchestrator_types.go index eeb5c4e2..ed78e59c 100644 --- a/api/gorch/v1alpha1/guardrailsorchestrator_types.go +++ b/api/gorch/v1alpha1/guardrailsorchestrator_types.go @@ -44,11 +44,13 @@ type GeneratorSpec struct { } type ChunkerSpec struct { - Provider string `json:"provider"` - Service ServiceSpec `json:"service"` + ChunkerName string `json:"chunkerName"` + Provider string `json:"provider"` + Service ServiceSpec `json:"service"` } type DetectorSpec struct { + Name string `json:"name"` Type string `json:"type"` Service ServiceSpec `json:"service"` ChunkerName string `json:"chunkerName"` @@ -62,6 +64,7 @@ type GuardrailsOrchestratorSpec struct { // Number of replicas Replicas int32 `json:"replicas"` + // CongigMapName string `json:"configMapName"` // Generator configuration Generator GeneratorSpec `json:"generator"` // Chunker configuration @@ -107,7 +110,7 @@ type GuardrailsOrchestratorCondition struct { Type string `json:"type"` Status metav1.ConditionStatus `json:"status"` // +optional - Reason string `json:"reason,omitmempty"` + Reason string `json:"reason,omitempty"` // +optional Message string `json:"message,omitempty"` // +optional diff --git a/config/base/params.env b/config/base/params.env index 14795475..a497fd4a 100644 --- a/config/base/params.env +++ b/config/base/params.env @@ -9,4 +9,4 @@ lmes-image-pull-policy=Always lmes-max-batch-size=24 lmes-default-batch-size=8 lmes-detect-device=true -guardrails-orchestrator-image=quay.io/trustyai/ta-guardrails-orchestrator:latest +guardrails-orchestrator-image=quay.io/rh-ee-mmisiura/fms-orchestr8-nlp:0.7.0 diff --git a/config/crd/bases/trustyai.opendatahub.io_guardrailsorchestrators.yaml b/config/crd/bases/trustyai.opendatahub.io_guardrailsorchestrators.yaml index 64e489c8..9e2ce81d 100644 --- a/config/crd/bases/trustyai.opendatahub.io_guardrailsorchestrators.yaml +++ b/config/crd/bases/trustyai.opendatahub.io_guardrailsorchestrators.yaml @@ -44,6 +44,8 @@ spec: description: Chunker configuration items: properties: + chunkerName: + type: string provider: type: string service: @@ -73,6 +75,7 @@ spec: - port type: object required: + - chunkerName - provider - service type: object @@ -85,6 +88,8 @@ spec: type: string defaultThreshold: type: string + name: + type: string service: properties: hostname: @@ -116,12 +121,15 @@ spec: required: - chunkerName - defaultThreshold + - name - service - type type: object type: array generator: - description: Generator configuration + description: |- + CongigMapName string `json:"configMapName"` + Generator configuration properties: provider: type: string diff --git a/config/overlays/odh/params.env b/config/overlays/odh/params.env index 14795475..a497fd4a 100644 --- a/config/overlays/odh/params.env +++ b/config/overlays/odh/params.env @@ -9,4 +9,4 @@ lmes-image-pull-policy=Always lmes-max-batch-size=24 lmes-default-batch-size=8 lmes-detect-device=true -guardrails-orchestrator-image=quay.io/trustyai/ta-guardrails-orchestrator:latest +guardrails-orchestrator-image=quay.io/rh-ee-mmisiura/fms-orchestr8-nlp:0.7.0 diff --git a/config/overlays/rhoai/params.env b/config/overlays/rhoai/params.env index 00febf5a..c1fe74e0 100644 --- a/config/overlays/rhoai/params.env +++ b/config/overlays/rhoai/params.env @@ -9,4 +9,4 @@ lmes-image-pull-policy=Always lmes-max-batch-size=24 lmes-default-batch-size=8 lmes-detect-device=true -guardrails-orchestrator-image=quay.io/trustyai/ta-guardrails-orchestrator:latest +guardrails-orchestrator-image=quay.io/rh-ee-mmisiura/fms-orchestr8-nlp:0.7.0 diff --git a/controllers/gorch/configmap.go b/controllers/gorch/configmap.go index e2581bf1..a9a350a8 100644 --- a/controllers/gorch/configmap.go +++ b/controllers/gorch/configmap.go @@ -3,13 +3,42 @@ package gorch import ( "context" "fmt" + "reflect" + gorchv1alpha1 "github.com/trustyai-explainability/trustyai-service-operator/api/gorch/v1alpha1" "github.com/trustyai-explainability/trustyai-service-operator/controllers/constants" + templateParser "github.com/trustyai-explainability/trustyai-service-operator/controllers/gorch/templates" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" ) +const configMapTemplatePath = "configmap.tmpl.yaml" + +type configMapConfig struct { + Orchestrator *gorchv1alpha1.GuardrailsOrchestrator + // ContainerImage string + // Version string +} + +func (r *GuardrailsOrchestratorReconciler) createConfigMap(ctx context.Context, orchestrator *gorchv1alpha1.GuardrailsOrchestrator) *corev1.ConfigMap { + configMapConfig := configMapConfig{ + Orchestrator: orchestrator, + } + + var configMap *corev1.ConfigMap + configMap, err := templateParser.ParseResource[corev1.ConfigMap](configMapTemplatePath, configMapConfig, reflect.TypeOf(&corev1.ConfigMap{})) + if err != nil { + log.FromContext(ctx).Error(err, "Failed to parse configmap template") + } + if err := controllerutil.SetControllerReference(orchestrator, configMap, r.Scheme); err != nil { + log.FromContext(ctx).Error(err, "Failed to set controller reference for configmap") + } + return configMap +} + func (r *GuardrailsOrchestratorReconciler) getImageFromConfigMap(ctx context.Context, configMapKey string, defaultContainerImage string) (string, error) { if r.Namespace != "" { configMap := &corev1.ConfigMap{} diff --git a/controllers/gorch/deployment.go b/controllers/gorch/deployment.go index 7a2e5b02..aa49a31c 100644 --- a/controllers/gorch/deployment.go +++ b/controllers/gorch/deployment.go @@ -14,17 +14,17 @@ import ( const deploymentTemplatePath = "deployment.tmpl.yaml" type DeploymentConfig struct { - Name string - Namespace string + Orchestrator *gorchv1alpha1.GuardrailsOrchestrator ContainerImage string Version string } +// TO-DO: Move configmap args to volumes + func (r *GuardrailsOrchestratorReconciler) createDeployment(ctx context.Context, orchestrator *gorchv1alpha1.GuardrailsOrchestrator) *appsv1.Deployment { containerImage, err := r.getImageFromConfigMap(ctx, configMapKey, defaultContainerImage) deploymentConfig := DeploymentConfig{ - Name: orchestratorName, - Namespace: orchestrator.Namespace, + Orchestrator: orchestrator, ContainerImage: containerImage, Version: Version, } @@ -32,6 +32,7 @@ func (r *GuardrailsOrchestratorReconciler) createDeployment(ctx context.Context, log.FromContext(ctx).Error(err, "Error getting container image from ConfigMap. Using the default image value of "+defaultContainerImage) } var deployment *appsv1.Deployment + deployment, err = templateParser.ParseResource[appsv1.Deployment](deploymentTemplatePath, deploymentConfig, reflect.TypeOf(&appsv1.Deployment{})) if err != nil { log.FromContext(ctx).Error(err, "Failed to parse deployment template") diff --git a/controllers/gorch/guardrailsorchestrator_controller.go b/controllers/gorch/guardrailsorchestrator_controller.go index 51612580..22f8a464 100644 --- a/controllers/gorch/guardrailsorchestrator_controller.go +++ b/controllers/gorch/guardrailsorchestrator_controller.go @@ -147,6 +147,21 @@ func (r *GuardrailsOrchestratorReconciler) Reconcile(ctx context.Context, req ct return ctrl.Result{}, nil } + existingConfigMap := &corev1.ConfigMap{} + err = r.Get(ctx, types.NamespacedName{Name: orchestrator.Name + "-config", Namespace: orchestrator.Namespace}, existingConfigMap) + if err != nil && errors.IsNotFound(err) { + configMap := r.createConfigMap(ctx, orchestrator) + log.Info("Creating a new ConfigMap", "ConfigMap.Namespace", configMap.Namespace, "ConfigMap.Name", configMap.Name) + err = r.Create(ctx, configMap) + if err != nil { + log.Error(err, "Failed to create new ConfigMap", "ConfigMap.Namespace", configMap.Namespace, "ConfigMap.Name", configMap.Name) + return ctrl.Result{}, err + } + } else if err != nil { + log.Error(err, "Failed to get ConfigMap") + return ctrl.Result{}, err + } + existingServiceAccount := &corev1.ServiceAccount{} err = r.Get(ctx, types.NamespacedName{Name: orchestrator.Name, Namespace: orchestrator.Namespace}, existingServiceAccount) if err != nil && errors.IsNotFound(err) { diff --git a/controllers/gorch/guardrailsorchestrator_controller_test.go b/controllers/gorch/guardrailsorchestrator_controller_test.go index 9350d937..d9cae6d0 100644 --- a/controllers/gorch/guardrailsorchestrator_controller_test.go +++ b/controllers/gorch/guardrailsorchestrator_controller_test.go @@ -110,6 +110,14 @@ func testCreateDeleteGuardrailsOrchestrator(namespaceName string) { By("Checking if resources were successfully created in the reconcilation") Eventually(func() error { + configMap := &corev1.ConfigMap{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName + "-config", Namespace: namespaceName}, configMap); err != nil { + return err + } + Expect(configMap.Name).Should(Equal(orchestratorName + "-config")) + Expect(configMap.Namespace).Should(Equal(namespaceName)) + Expect(configMap.Data["config.yaml"]).ShouldNot(BeEmpty()) + serviceAccount := &corev1.ServiceAccount{} if err := k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName + "-serviceaccount", Namespace: namespaceName}, serviceAccount); err != nil { return err @@ -123,7 +131,10 @@ func testCreateDeleteGuardrailsOrchestrator(namespaceName string) { Expect(deployment.Namespace).Should(Equal(namespaceName)) Expect(deployment.Name).Should(Equal(orchestratorName)) Expect(deployment.Labels["app"]).Should(Equal(orchestratorName)) + Expect(deployment.Spec.Template.Spec.Volumes[0].Name).Should(Equal(orchestratorName + "-config")) + Expect(deployment.Spec.Template.Spec.Volumes[0].ConfigMap.Name).Should(Equal(orchestratorName + "-config")) Expect(deployment.Spec.Template.Spec.Containers[0].Image).Should(Equal(defaultContainerImage)) + Expect(deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].Name).Should(Equal(orchestratorName + "-config")) service := &corev1.Service{} if err := k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName + "-service", Namespace: namespaceName}, service); err != nil { diff --git a/controllers/gorch/templates/configmap.tmpl.yaml b/controllers/gorch/templates/configmap.tmpl.yaml new file mode 100644 index 00000000..be92d155 --- /dev/null +++ b/controllers/gorch/templates/configmap.tmpl.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app: + component: fms-orchestr8-nlp + deploy-name: fms-orchestr8-nlp + name: {{.Orchestrator.Name}}-config + namespace: {{.Orchestrator.Namespace}} +data: + config.yaml: | + generation: + provider: {{.Orchestrator.Spec.Generator.Provider}} + service: + hostname: {{.Orchestrator.Spec.Generator.Service.Hostname}} + port: {{.Orchestrator.Spec.Generator.Service.Port}} + {{- range .Orchestrator.Spec.Detectors }} + detectors: + {{.Name}}: + type: {{.Type}} + service: + hostname: {{.Service.Hostname}} + port: {{.Service.Port}} + chunker_id: {{.ChunkerName}} + default_threshold: {{.DefaultThreshold}} + {{- end }} + {{ if .Orchestrator.Spec.Chunkers}} + {{- range .Orchestrator.Spec.Chunkers }} + chunkers: + {{.ChunkerName}}: + service: + hostname: {{.Service.Hostname}} + port: {{.Service.Port}} + {{- end }} + {{- end }} diff --git a/controllers/gorch/templates/deployment.tmpl.yaml b/controllers/gorch/templates/deployment.tmpl.yaml index 1f7796e2..ecea7821 100644 --- a/controllers/gorch/templates/deployment.tmpl.yaml +++ b/controllers/gorch/templates/deployment.tmpl.yaml @@ -1,44 +1,50 @@ kind: Deployment apiVersion: apps/v1 metadata: - name: {{.Name}} - namespace: {{.Namespace}} + name: {{.Orchestrator.Name}} + namespace: {{.Orchestrator.Namespace}} annotations: sidecar.istio.io/inject: "true" labels: - app: {{.Name}} - component: {{.Name}} - deploy-name: {{.Name}} - app.kubernetes.io/instance: {{.Name}} - app.kubernetes.io/name: {{.Name}} + app: {{.Orchestrator.Name}} + component: {{.Orchestrator.Name}} + deploy-name: {{.Orchestrator.Name}} + app.kubernetes.io/instance: {{.Orchestrator.Name}} + app.kubernetes.io/name: {{.Orchestrator.Name}} app.kubernetes.io/part-of: trustyai app.kubernetes.io/version: {{.Version}} spec: replicas: 1 selector: matchLabels: - app: {{.Name}} - component: {{.Name}} - deploy-name: {{.Name}} - app.kubernetes.io/instance: {{.Name}} - app.kubernetes.io/name: {{.Name}} + app: {{.Orchestrator.Name}} + component: {{.Orchestrator.Name}} + deploy-name: {{.Orchestrator.Name}} + app.kubernetes.io/instance: {{.Orchestrator.Name}} + app.kubernetes.io/name: {{.Orchestrator.Name}} app.kubernetes.io/part-of: trustyai + app.kubernetes.io/version: {{.Version}} template: metadata: labels: - app: {{.Name}} - component: {{.Name}} - deploy-name: {{.Name}} - app.kubernetes.io/instance: {{.Name}} - app.kubernetes.io/name: {{.Name}} + app: {{.Orchestrator.Name}} + component: {{.Orchestrator.Name}} + deploy-name: {{.Orchestrator.Name}} + app.kubernetes.io/instance: {{.Orchestrator.Name}} + app.kubernetes.io/name: {{.Orchestrator.Name}} app.kubernetes.io/part-of: trustyai app.kubernetes.io/version: {{.Version}} annotations: sidecar.istio.io/inject: "true" spec: - serviceAccountName: {{.Name}}-serviceaccount + volumes: + - name: {{.Orchestrator.Name}}-config + configMap: + name: {{.Orchestrator.Name}}-config + defualtMode: 420 + serviceAccountName: {{.Orchestrator.Name}}-serviceaccount containers: - - name: {{.Name}} + - name: {{.Orchestrator.Name}} image: {{.ContainerImage}} env: - name: ORCHESTRATOR_CONFIG @@ -49,6 +55,11 @@ spec: value: 'full' - name: RUST_LOG value: 'fms_guardrails_orchestr8=trace,tower_grpc=debug' + volumeMounts: + - name: {{.Orchestrator.Name}}-config + readOnly: true + mountPath: /config + subPath: config.yaml ports: - name: http containerPort: 8033