Skip to content

Commit 80f52bb

Browse files
Add reconciliation logic to update deployments
1 parent d99befa commit 80f52bb

2 files changed

Lines changed: 126 additions & 3 deletions

File tree

controllers/gorch/guardrailsorchestrator_controller.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ package gorch
1919
import (
2020
"context"
2121
"fmt"
22+
"strconv"
23+
"time"
24+
2225
"github.com/go-logr/logr"
2326
kservev1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1"
2427
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -28,8 +31,6 @@ import (
2831
"sigs.k8s.io/controller-runtime/pkg/builder"
2932
"sigs.k8s.io/controller-runtime/pkg/handler"
3033
"sigs.k8s.io/controller-runtime/pkg/predicate"
31-
"strconv"
32-
"time"
3334

3435
gorchv1alpha1 "github.com/trustyai-explainability/trustyai-service-operator/api/gorch/v1alpha1"
3536
appsv1 "k8s.io/api/apps/v1"
@@ -323,6 +324,41 @@ func (r *GuardrailsOrchestratorReconciler) Reconcile(ctx context.Context, req ct
323324
} else if err != nil {
324325
r.handleReconciliationError(ctx, log, orchestrator, err, utils.ReconcileFailed, "Failed to get Deployment")
325326
return ctrl.Result{}, err
327+
} else {
328+
// Deployment exists, check if it needs to be updated
329+
newDeployment, err := r.createDeployment(ctx, orchestrator)
330+
if err != nil {
331+
r.handleReconciliationError(ctx, log, orchestrator, err, utils.ReconcileFailed, "Failed to create updated Deployment spec")
332+
return ctrl.Result{}, err
333+
}
334+
335+
// add TLS mounts to the new deployment spec
336+
err = r.addTLSMounts(ctx, orchestrator, newDeployment, tlsMounts)
337+
if err != nil {
338+
if errors.IsNotFound(err) {
339+
log.Info("Could not find required TLS serving secrets, will try again.")
340+
return ctrl.Result{}, nil
341+
}
342+
r.handleReconciliationError(ctx, log, orchestrator, err, utils.ReconcileFailed, "Failed to add TLS Mounts")
343+
return ctrl.Result{}, err
344+
}
345+
346+
// Preserve existing annotations and add configmap hashes
347+
annotations := existingDeployment.Spec.Template.Annotations
348+
if annotations == nil {
349+
annotations = map[string]string{}
350+
}
351+
r.setConfigMapHashAnnotations(ctx, orchestrator, annotations)
352+
newDeployment.Spec.Template.Annotations = annotations
353+
354+
// Patch the deployment if there are changes
355+
if patchDeployment(existingDeployment, newDeployment) {
356+
log.Info("Updating Deployment", "Deployment.Namespace", existingDeployment.Namespace, "Deployment.Name", existingDeployment.Name)
357+
if updateErr := r.Update(ctx, existingDeployment); updateErr != nil {
358+
r.handleReconciliationError(ctx, log, orchestrator, updateErr, utils.ReconcileFailed, "Failed to update Deployment")
359+
return ctrl.Result{}, updateErr
360+
}
361+
}
326362
}
327363

328364
// monitor the orchestrator or gateway config for changes

controllers/gorch/guardrailsorchestrator_controller_test.go

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ func createGuardrailsOrchestrator(ctx context.Context, orchestratorConfigMap str
4747
Namespace: typedNamespacedName.Namespace,
4848
},
4949
Spec: gorchv1alpha1.GuardrailsOrchestratorSpec{
50-
Replicas: 1,
5150
OrchestratorConfig: &orchestratorConfigMap,
5251
},
5352
}
@@ -505,6 +504,93 @@ func testCreateGuardrailsOrchestratorWithCustomReplicas(namespaceName string) {
505504
})
506505
}
507506

507+
func testCreateGuardrailsOrchestratorWithScaledUpReplicas(namespaceName string) {
508+
It("Should successfully scale up the deployment from 1 to 3 replicas", func() {
509+
By("Creating a custom resource for the GuardrailsOrchestrator with 1 replica")
510+
ctx := context.Background()
511+
typedNamespacedName := types.NamespacedName{Name: orchestratorName, Namespace: namespaceName}
512+
513+
orchConfig := &corev1.ConfigMap{
514+
TypeMeta: metav1.TypeMeta{
515+
Kind: "ConfigMap",
516+
APIVersion: "v1",
517+
},
518+
ObjectMeta: metav1.ObjectMeta{
519+
Name: orchestratorName + "-config",
520+
Namespace: namespaceName,
521+
},
522+
}
523+
err := k8sClient.Create(ctx, orchConfig)
524+
if err != nil && !errors.IsAlreadyExists(err) {
525+
Expect(err).ToNot(HaveOccurred())
526+
}
527+
528+
err = createGuardrailsOrchestratorWithReplicas(ctx, orchestratorName+"-config", 1)
529+
Expect(err).ToNot(HaveOccurred())
530+
531+
By("Checking if the custom resource was successfully created")
532+
err = k8sClient.Get(ctx, typedNamespacedName, &gorchv1alpha1.GuardrailsOrchestrator{})
533+
Expect(err).ToNot(HaveOccurred())
534+
535+
By("Reconciling the custom resource that was created")
536+
reconciler := &GuardrailsOrchestratorReconciler{
537+
Client: k8sClient,
538+
Scheme: k8sClient.Scheme(),
539+
Namespace: namespaceName,
540+
}
541+
542+
_, err = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typedNamespacedName})
543+
Expect(err).ToNot(HaveOccurred())
544+
545+
By("Checking if the deployment was created with 1 replica")
546+
Eventually(func() error {
547+
deployment := &appsv1.Deployment{}
548+
if err = k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName, Namespace: namespaceName}, deployment); err != nil {
549+
return err
550+
}
551+
Expect(*deployment.Spec.Replicas).Should(Equal(int32(1)))
552+
return nil
553+
}, time.Second*10, time.Millisecond*10).Should(Succeed())
554+
555+
By("Updating the GuardrailsOrchestrator to 3 replicas")
556+
orchestrator := &gorchv1alpha1.GuardrailsOrchestrator{}
557+
err = k8sClient.Get(ctx, typedNamespacedName, orchestrator)
558+
Expect(err).ToNot(HaveOccurred())
559+
560+
orchestrator.Spec.Replicas = 3
561+
err = k8sClient.Update(ctx, orchestrator)
562+
Expect(err).ToNot(HaveOccurred())
563+
564+
By("Reconciling the updated custom resource")
565+
_, err = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typedNamespacedName})
566+
Expect(err).ToNot(HaveOccurred())
567+
568+
By("Checking if the deployment was scaled up to 3 replicas")
569+
Eventually(func() error {
570+
deployment := &appsv1.Deployment{}
571+
if err = k8sClient.Get(ctx, types.NamespacedName{Name: orchestratorName, Namespace: namespaceName}, deployment); err != nil {
572+
return err
573+
}
574+
Expect(*deployment.Spec.Replicas).Should(Equal(int32(3)))
575+
Expect(deployment.Namespace).Should(Equal(namespaceName))
576+
Expect(deployment.Name).Should(Equal(orchestratorName))
577+
return nil
578+
}, time.Second*10, time.Millisecond*10).Should(Succeed())
579+
580+
By("Deleting the custom resource for the GuardrailsOrchestrator")
581+
err = deleteGuardrailsOrchestrator(ctx, orchestratorName, namespaceName)
582+
Expect(err).ToNot(HaveOccurred())
583+
584+
By("Deleting the orchestrator configmap")
585+
err = k8sClient.Delete(ctx, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: orchestratorName + "-config", Namespace: namespaceName}})
586+
Expect(err).ToNot(HaveOccurred())
587+
588+
By("Reconciling the custom resource that was deleted")
589+
_, err = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typedNamespacedName})
590+
Expect(err).ToNot(HaveOccurred())
591+
})
592+
}
593+
508594
func testCreateTwoGuardrailsOrchestratorsInSameNamespace(namespaceName string) {
509595
It("Should successfully reconcile two custom resources for the GuardrailsOrchestrator in the same namespace", func() {
510596
By("Creating the first custom resource for the GuardrailsOrchestrator")
@@ -897,6 +983,7 @@ var _ = Describe("GuardrailsOrchestrator Controller", func() {
897983
testCreateDeleteGuardrailsOrchestratorSidecar(namespaceName)
898984
testCreateDeleteGuardrailsOrchestratorOtelExporter(namespaceName)
899985
testCreateGuardrailsOrchestratorWithCustomReplicas(namespaceName)
986+
testCreateGuardrailsOrchestratorWithScaledUpReplicas(namespaceName)
900987
testCreateTwoGuardrailsOrchestratorsInSameNamespace(namespaceName)
901988
testCreateTwoGuardrailsOrchestratorsInDifferentNamespaces(namespaceName, secondNamespaceName)
902989
})

0 commit comments

Comments
 (0)