Skip to content

Commit 12a8154

Browse files
committed
OKP: Filter by product version
Update the default OKP chunk_filter_query to include version-specific filters for both OpenStack and OpenShift. For OCP version detection, the code reuses the DetectOCPVersion() and for OpenStack a new detectOpenStackVersion() was introduced. The way the OpenStack version is determined is by mapping the OCP versions accordingly to RHOSO. For example, OCP <= 4.21 maps to OpenStack 18.0. In the future, once RHOSO 19.0 is out, we just need to add a new map entry for it. If no entry is mapped the code log a message and safely return a default version for RHOSO (right now, 18.0). The dev.okpChunkFilterQuery override continues to bypass detection entirely. Kuttl tests pin the query via that override to keep assertions deterministic across cluster environments. Signed-off-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
1 parent 410da6f commit 12a8154

9 files changed

Lines changed: 111 additions & 29 deletions

File tree

api/v1beta1/openstacklightspeed_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const (
5555
//
5656
// Supported fields:
5757
// - featureFlags: list of experimental feature flags to enable (e.g. ["okp"])
58-
// - okpChunkFilterQuery: Solr filter query for OKP searches (default: "product:(*openstack* OR *openshift*)")
58+
// - okpChunkFilterQuery: Solr filter query for OKP searches (default: version-aware query combining detected OpenStack and OCP versions)
5959
// - okpRagOnly: when true, only OKP is used as a RAG source (default: false)
6060
type DevSpec struct {
6161
FeatureFlags []string `json:"featureFlags,omitempty"`

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ require (
2020
// must be consistent within modules and service operators
2121
replace github.com/openshift/api => github.com/openshift/api v0.0.0-20250711200046-c86d80652a9e
2222

23+
require github.com/Masterminds/semver/v3 v3.4.0
24+
2325
require (
2426
cel.dev/expr v0.24.0 // indirect
25-
github.com/Masterminds/semver/v3 v3.4.0 // indirect
2627
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
2728
github.com/beorn7/perks v1.0.1 // indirect
2829
github.com/blang/semver/v4 v4.0.0 // indirect

internal/controller/common.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,24 @@ func isOKPEnabled(instance *apiv1beta1.OpenStackLightspeed) bool {
148148
return slices.Contains(config.FeatureFlags, "okp")
149149
}
150150

151-
// getOKPChunkFilterQuery returns the chunk filter query from the dev config, or the default.
152-
func getOKPChunkFilterQuery(instance *apiv1beta1.OpenStackLightspeed) string {
151+
// getOKPChunkFilterQuery returns the chunk filter query from the dev config, or a version-aware default.
152+
func getOKPChunkFilterQuery(ctx context.Context, h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) string {
153153
config, _ := parseDevConfig(instance)
154154
if config.OKPChunkFilterQuery != "" {
155155
return config.OKPChunkFilterQuery
156156
}
157-
return OKPDefaultChunkFilterQuery
157+
158+
logger := h.GetLogger()
159+
160+
ocpVersion, err := DetectOCPVersion(ctx, h)
161+
if err != nil {
162+
logger.Error(err, "Failed to detect OCP version, using default", "default", OKPDefaultOCPVersion)
163+
ocpVersion = OKPDefaultOCPVersion
164+
}
165+
166+
osVersion := detectRHOSOVersion(ocpVersion, logger)
167+
168+
return fmt.Sprintf("((product:*openstack* AND product_version:%s) OR (product:*openshift* AND product_version:%s))", osVersion, ocpVersion)
158169
}
159170

160171
// getDeployment retrieves deployment from the cluster

internal/controller/constants.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,15 @@ const (
120120
ServiceIDRHOSO = "rhos-lightspeed"
121121

122122
// OKP (Offline Knowledge Portal)
123-
OKPContainerName = "okp"
124-
OKPContainerPort = int32(8080)
125-
OKPDeploymentName = "lightspeed-okp-server"
126-
OKPServiceName = "lightspeed-okp-server"
127-
OKPServicePort = int32(8080)
128-
OKPAccessKeySecretKey = "access_key"
129-
OKPDefaultChunkFilterQuery = "product:(*openstack* OR *openshift*)"
130-
ExternalProvidersDir = "/app-root/providers.d"
123+
OKPContainerName = "okp"
124+
OKPContainerPort = int32(8080)
125+
OKPDeploymentName = "lightspeed-okp-server"
126+
OKPServiceName = "lightspeed-okp-server"
127+
OKPServicePort = int32(8080)
128+
OKPAccessKeySecretKey = "access_key"
129+
OKPDefaultOCPVersion = "4.21"
130+
OKPDefaultRHOSOVersion = "18.0"
131+
ExternalProvidersDir = "/app-root/providers.d"
131132

132133
// Console Plugin
133134
ConsoleUIConfigMapName = "lightspeed-console-plugin"

internal/controller/lcore_config.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package controller
1818

1919
import (
20+
"context"
2021
_ "embed"
2122
"fmt"
2223

@@ -203,25 +204,26 @@ ingress_connection_timeout: 30
203204
}
204205
}
205206

206-
func buildOKPConfig(instance *apiv1beta1.OpenStackLightspeed) map[string]interface{} {
207+
func buildOKPConfig(instance *apiv1beta1.OpenStackLightspeed, chunkFilterQuery string) map[string]interface{} {
207208
offline := true
208209
if instance.Spec.OKP != nil && instance.Spec.OKP.Offline != nil {
209210
offline = *instance.Spec.OKP.Offline
210211
}
211212

212-
okpConfig := map[string]interface{}{
213-
"rhokp_url": "${env.RH_SERVER_OKP}",
214-
"offline": offline,
213+
return map[string]interface{}{
214+
"rhokp_url": "${env.RH_SERVER_OKP}",
215+
"offline": offline,
216+
"chunk_filter_query": chunkFilterQuery,
215217
}
216-
okpConfig["chunk_filter_query"] = getOKPChunkFilterQuery(instance)
217-
return okpConfig
218218
}
219219

220220
// buildLCoreConfigYAML assembles the complete Lightspeed Core Service configuration and converts to YAML.
221221
// NOTE: MCP servers, quota handlers, and tools approval features are disabled for OpenStack Lightspeed.
222-
func buildLCoreConfigYAML(h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) (string, error) {
222+
func buildLCoreConfigYAML(ctx context.Context, h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) (string, error) {
223+
okpEnabled := isOKPEnabled(instance)
224+
223225
ragInline := []interface{}{}
224-
if isOKPEnabled(instance) {
226+
if okpEnabled {
225227
ragInline = append(ragInline, "okp")
226228
}
227229
ragConfig := map[string]interface{}{
@@ -243,8 +245,8 @@ func buildLCoreConfigYAML(h *common_helper.Helper, instance *apiv1beta1.OpenStac
243245
"rag": ragConfig,
244246
}
245247

246-
if isOKPEnabled(instance) {
247-
config["okp"] = buildOKPConfig(instance)
248+
if okpEnabled {
249+
config["okp"] = buildOKPConfig(instance, getOKPChunkFilterQuery(ctx, h, instance))
248250
}
249251

250252
// Convert to YAML

internal/controller/lcore_reconciler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func reconcileLcoreConfigMap(h *common_helper.Helper, ctx context.Context, insta
217217
logger := h.GetLogger()
218218

219219
// Build the YAML data
220-
yamlData, err := buildLCoreConfigYAML(h, instance)
220+
yamlData, err := buildLCoreConfigYAML(ctx, h, instance)
221221
if err != nil {
222222
return fmt.Errorf("%w: %v", ErrGenerateAPIConfigmap, err)
223223
}

internal/controller/llama_stack_config.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,16 +254,16 @@ func buildLlamaStackVectorDB(_ *common_helper.Helper, _ *apiv1beta1.OpenStackLig
254254
}
255255
}
256256

257-
func buildLlamaStackVectorIO(h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed) []interface{} {
257+
func buildLlamaStackVectorIO(h *common_helper.Helper, instance *apiv1beta1.OpenStackLightspeed, chunkFilterQuery string) []interface{} {
258258
providers := buildLlamaStackVectorDB(h, instance)
259259
if isOKPEnabled(instance) {
260-
providers = append(providers, buildOKPVectorIOProvider(instance))
260+
providers = append(providers, buildOKPVectorIOProvider(chunkFilterQuery))
261261
}
262262
return providers
263263
}
264264

265-
func buildOKPVectorIOProvider(instance *apiv1beta1.OpenStackLightspeed) map[string]interface{} {
266-
chunkFilterQuery := "is_chunk:true AND " + getOKPChunkFilterQuery(instance)
265+
func buildOKPVectorIOProvider(chunkFilterQuery string) map[string]interface{} {
266+
chunkFilterQuery = "is_chunk:true AND " + chunkFilterQuery
267267

268268
return map[string]interface{}{
269269
"provider_id": "okp_solr",
@@ -426,8 +426,10 @@ func buildLlamaStackYAML(h *common_helper.Helper, ctx context.Context, instance
426426
return "", fmt.Errorf("failed to build inference providers: %w", err)
427427
}
428428

429+
okpChunkFilterQuery := ""
429430
if isOKPEnabled(instance) {
430431
config["external_providers_dir"] = ExternalProvidersDir
432+
okpChunkFilterQuery = getOKPChunkFilterQuery(ctx, h, instance)
431433
}
432434

433435
// Build providers map - only include providers for enabled APIs
@@ -437,7 +439,7 @@ func buildLlamaStackYAML(h *common_helper.Helper, ctx context.Context, instance
437439
"inference": inferenceProviders,
438440
"safety": buildLlamaStackSafety(h, instance),
439441
"tool_runtime": buildLlamaStackToolRuntime(h, instance),
440-
"vector_io": buildLlamaStackVectorIO(h, instance),
442+
"vector_io": buildLlamaStackVectorIO(h, instance, okpChunkFilterQuery),
441443
}
442444

443445
// Add top-level fields
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
Copyright 2025.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controller
18+
19+
import (
20+
"github.com/Masterminds/semver/v3"
21+
"github.com/go-logr/logr"
22+
)
23+
24+
// ocpVersionBound maps an OCP version upper bound to a RHOSO version.
25+
type ocpVersionBound struct {
26+
maxOCPVersion string
27+
rhosoVersion string
28+
}
29+
30+
// ocpToRHOSOVersionMap maps OCP version upper bounds to RHOSO versions.
31+
// Entries must be in ascending order of maxOCPVersion.
32+
// Versions above the highest bound fall back to OKPDefaultRHOSOVersion.
33+
// Add a new entry here when a new RHOSO version's content becomes available in the knowledge base.
34+
var ocpToRHOSOVersionMap = []ocpVersionBound{
35+
{"4.21", "18.0"},
36+
// When RHOSO 19.0 content is available, add: {"4.XX", "19.0"}
37+
}
38+
39+
// detectRHOSOVersion returns the RHOSO version corresponding to the given OCP version.
40+
// Falls back to OKPDefaultRHOSOVersion if the version cannot be parsed or is above all defined bounds.
41+
func detectRHOSOVersion(ocpVersion string, logger logr.Logger) string {
42+
detected, err := semver.NewVersion(ocpVersion)
43+
if err != nil {
44+
logger.Info("Failed to parse OCP version, using default RHOSO version",
45+
"ocpVersion", ocpVersion, "default", OKPDefaultRHOSOVersion)
46+
return OKPDefaultRHOSOVersion
47+
}
48+
49+
for _, entry := range ocpToRHOSOVersionMap {
50+
bound, err := semver.NewVersion(entry.maxOCPVersion)
51+
if err != nil {
52+
logger.Info("Invalid bound in RHOSO version map, using default",
53+
"bound", entry.maxOCPVersion, "default", OKPDefaultRHOSOVersion)
54+
return OKPDefaultRHOSOVersion
55+
}
56+
if detected.Compare(bound) <= 0 {
57+
return entry.rhosoVersion
58+
}
59+
}
60+
61+
logger.Info("OCP version above all known bounds, using default RHOSO version",
62+
"ocpVersion", ocpVersion, "default", OKPDefaultRHOSOVersion)
63+
return OKPDefaultRHOSOVersion
64+
}

test/kuttl/tests/okp-configuration/02-create-okp-resources.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ spec:
2121
dev:
2222
featureFlags:
2323
- okp
24+
okpChunkFilterQuery: "product:(*openstack* OR *openshift*)"

0 commit comments

Comments
 (0)