Skip to content

Commit 1701755

Browse files
committed
Leverage the autodiscovery indexID feature
This patch leverage the autodiscovery indexID feature from OLS. Prior to this patch, our code started a temporary container to extract the indexID value from an env variable, this is no longer needed for OLS and the code can be removed. Now, OLS levarages the rag of the RAG images as the indexID for the vector database. Since our images already matches the tag with the IndexID that was used during build time, we no longer need to set it in OLSConfig. Signed-off-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
1 parent 9bb8439 commit 1701755

2 files changed

Lines changed: 4 additions & 182 deletions

File tree

internal/controller/funcs.go

Lines changed: 3 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,16 @@ package controller
1818

1919
import (
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.
420257
func IsOwnedBy(object metav1.Object, owner metav1.Object) bool {
421258
for _, ref := range object.GetOwnerReferences() {

internal/controller/openstacklightspeed_controller.go

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -189,21 +189,6 @@ func (r *OpenStackLightspeedReconciler) Reconcile(ctx context.Context, req ctrl.
189189
apiv1beta1.OpenShiftLightspeedOperatorReady,
190190
)
191191

192-
// TODO(lpiwowar): Remove ResolveIndexID once OpenShift Lightspeed supports auto discovery of the indexID directly
193-
// from the vector db image.
194-
indexID, result, err := ResolveIndexID(ctx, helper, instance)
195-
if err != nil {
196-
instance.Status.Conditions.Set(condition.FalseCondition(
197-
apiv1beta1.OpenStackLightspeedReadyCondition,
198-
condition.ErrorReason,
199-
condition.SeverityWarning,
200-
condition.DeploymentReadyErrorMessage,
201-
err.Error()))
202-
return result, err
203-
} else if (result != ctrl.Result{}) {
204-
return result, nil
205-
}
206-
207192
// NOTE: We cannot consume the OLSConfig definition directly from the OLS operator's code due to
208193
// a conflict in Go versions. When this comment was written, the min. required Go version for
209194
// openstack-operator was 1.21 whereas OLS operator required at least Go version 1.23. Once the
@@ -232,7 +217,7 @@ func (r *OpenStackLightspeedReconciler) Reconcile(ctx context.Context, req ctrl.
232217
return fmt.Errorf("OLSConfig is managed by different OpenStackLightspeed instance")
233218
}
234219

235-
err = PatchOLSConfig(helper, instance, &olsConfig, indexID)
220+
err = PatchOLSConfig(helper, instance, &olsConfig)
236221
if err != nil {
237222
return err
238223
}

0 commit comments

Comments
 (0)