@@ -18,25 +18,16 @@ package controller
1818
1919import (
2020 "context"
21- "crypto/sha256"
2221 "encoding/json"
2322 "fmt"
24- "io"
2523 "math/rand"
2624 "strconv"
27- "strings"
28- "time"
2925
30- "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
3126 apiv1beta1 "github.com/openstack-lightspeed/operator/api/v1beta1"
32- batchv1 "k8s.io/api/batch/v1"
33- "k8s.io/client-go/kubernetes"
34- ctrl "sigs.k8s.io/controller-runtime"
3527 "sigs.k8s.io/controller-runtime/pkg/client"
3628 "sigs.k8s.io/controller-runtime/pkg/client/config"
3729
3830 common_helper "github.com/openstack-k8s-operators/lib-common/modules/common/helper"
39- corev1 "k8s.io/api/core/v1"
4031 k8s_errors "k8s.io/apimachinery/pkg/api/errors"
4132 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4233 uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -139,7 +130,6 @@ func PatchOLSConfig(
139130 helper * common_helper.Helper ,
140131 instance * apiv1beta1.OpenStackLightspeed ,
141132 olsConfig * uns.Unstructured ,
142- indexID string ,
143133) error {
144134 // Patch the Providers section
145135 providersPatch := []interface {}{
@@ -165,10 +155,12 @@ func PatchOLSConfig(
165155 }
166156
167157 // Patch the RAG section
158+ // NOTE(lucasagomes): We don't need indexID here because the tag on our RAG images
159+ // already matches the indexID that the Vector DB used when it was built. OLS leverages
160+ // that to set the right index.
168161 openstackRAG := []interface {}{
169162 map [string ]interface {}{
170163 "image" : instance .Spec .RAGImage ,
171- "indexID" : indexID ,
172164 "indexPath" : OpenStackLightspeedVectorDBPath ,
173165 },
174166 }
@@ -261,161 +253,6 @@ func IsOLSConfigReady(ctx context.Context, helper *common_helper.Helper) (bool,
261253 return true , nil
262254}
263255
264- // ResolveIndexID - returns index ID for the data stored in the vector DB container image. The discovery of the
265- // index ID is done through spawning a pod with the rag-content image and looking at the INDEX_NAME env variable value.
266- func ResolveIndexID (
267- ctx context.Context ,
268- helper * common_helper.Helper ,
269- instance * apiv1beta1.OpenStackLightspeed ,
270- ) (string , ctrl.Result , error ) {
271- err := createOLSJob (ctx , helper , instance )
272- if err != nil {
273- return "" , ctrl.Result {}, err
274- }
275-
276- podList := & corev1.PodList {}
277- labelSelector := client.MatchingLabels {"app" : OpenStackLightspeedJobName }
278- if err := helper .GetClient ().List (ctx , podList , client .InNamespace (instance .Namespace ), labelSelector ); err != nil {
279- return "" , ctrl.Result {}, err
280- }
281-
282- var OLSPod * corev1.Pod
283- for _ , pod := range podList .Items {
284- if pod .Spec .Containers [0 ].Image == instance .Spec .RAGImage {
285- OLSPod = & pod
286- break
287- }
288- }
289- if OLSPod == nil {
290- return requeueWaitingPod (helper , instance )
291- }
292-
293- switch OLSPod .Status .Phase {
294- case corev1 .PodSucceeded :
295- indexName , err := extractEnvFromPodLogs (ctx , OLSPod , "INDEX_NAME" )
296- if err != nil && k8s_errors .IsNotFound (err ) {
297- return requeueWaitingPod (helper , instance )
298- }
299- return indexName , ctrl.Result {}, err
300- case corev1 .PodFailed :
301- return "" , ctrl.Result {}, fmt .Errorf ("failed to start OpenStack Lightpseed RAG pod" )
302- default :
303- return requeueWaitingPod (helper , instance )
304- }
305- }
306-
307- // extractEnvFromPodLogs - discovers an environment variable value from the pod logs. The pod must be started using
308- // createOLSJob.
309- func extractEnvFromPodLogs (ctx context.Context , pod * corev1.Pod , envVarName string ) (string , error ) {
310- cfg , err := config .GetConfig ()
311- if err != nil {
312- return "" , err
313- }
314-
315- k8sClient , err := kubernetes .NewForConfig (cfg )
316- if err != nil {
317- return "" , err
318- }
319-
320- req := k8sClient .CoreV1 ().Pods (pod .Namespace ).GetLogs (pod .Name , & corev1.PodLogOptions {})
321- podLogs , err := req .Stream (ctx )
322- if err != nil {
323- return "" , err
324- }
325- defer func () {
326- _ = podLogs .Close ()
327- }()
328-
329- buf := new (strings.Builder )
330- _ , err = io .Copy (buf , podLogs )
331- if err != nil {
332- return "" , fmt .Errorf ("error in copying logs: %w" , err )
333- }
334-
335- logs := buf .String ()
336- for _ , envLine := range strings .Split (logs , "\n " ) {
337- parts := strings .Split (envLine , "=" )
338- if len (parts ) != 2 {
339- continue
340- }
341-
342- if parts [0 ] == envVarName {
343- return parts [1 ], nil
344- }
345- }
346-
347- return "" , fmt .Errorf ("env var not discovered: %s" , envVarName )
348- }
349-
350- // createOLSJob - starts OLS pod with entrypoint that lists environment variables after the start of the pod. It used
351- // to discover INDEX_NAME value.
352- func createOLSJob (
353- ctx context.Context ,
354- helper * common_helper.Helper ,
355- instance * apiv1beta1.OpenStackLightspeed ,
356- ) error {
357- imageHash := sha256 .Sum256 ([]byte (instance .Spec .RAGImage ))
358- imageHashStr := fmt .Sprintf ("%x" , imageHash )
359- imageHashStr = imageHashStr [len (imageHashStr )- 9 :]
360- imageName := fmt .Sprintf ("%s-%s" , OpenStackLightspeedJobName , imageHashStr )
361-
362- ttlSecondsAfterFinished := int32 (600 ) // 10 mins
363- activeDeadlineSeconds := int64 (1200 ) // 20 mins
364- OLSPod := & batchv1.Job {
365- ObjectMeta : metav1.ObjectMeta {
366- Name : imageName ,
367- Namespace : instance .Namespace ,
368- Labels : map [string ]string {
369- "app" : OpenStackLightspeedJobName ,
370- },
371- },
372- Spec : batchv1.JobSpec {
373- TTLSecondsAfterFinished : & ttlSecondsAfterFinished ,
374- ActiveDeadlineSeconds : & activeDeadlineSeconds ,
375- Template : corev1.PodTemplateSpec {
376- ObjectMeta : metav1.ObjectMeta {
377- Labels : map [string ]string {
378- "app" : OpenStackLightspeedJobName ,
379- },
380- },
381- Spec : corev1.PodSpec {
382- Containers : []corev1.Container {
383- {
384- Name : "rag-content" ,
385- Image : instance .Spec .RAGImage ,
386- Command : []string {"/bin/sh" , "-c" },
387- Args : []string {"env" },
388- },
389- },
390- RestartPolicy : corev1 .RestartPolicyNever ,
391- },
392- },
393- },
394- }
395-
396- if err := controllerutil .SetControllerReference (instance , OLSPod , helper .GetScheme ()); err != nil {
397- return err
398- }
399-
400- err := helper .GetClient ().Create (ctx , OLSPod )
401- if err != nil && ! k8s_errors .IsAlreadyExists (err ) {
402- return err
403- }
404-
405- return nil
406- }
407-
408- func requeueWaitingPod (helper * common_helper.Helper , instance * apiv1beta1.OpenStackLightspeed ) (string , ctrl.Result , error ) {
409- instance .Status .Conditions .Set (condition .FalseCondition (
410- apiv1beta1 .OpenStackLightspeedReadyCondition ,
411- condition .RequestedReason ,
412- condition .SeverityInfo ,
413- apiv1beta1 .OpenStackLightspeedWaitingVectorDBMessage ,
414- ))
415- helper .GetLogger ().Info (apiv1beta1 .OpenStackLightspeedReadyMessage )
416- return "" , ctrl.Result {RequeueAfter : 5 * time .Second }, nil
417- }
418-
419256// IsOwnedBy returns true if 'object' is owned by 'owner' based on OwnerReference UID.
420257func IsOwnedBy (object metav1.Object , owner metav1.Object ) bool {
421258 for _ , ref := range object .GetOwnerReferences () {
0 commit comments