Skip to content

Commit 3959fad

Browse files
committed
Enable OKP support
This commit adds the first step in supporting OKP for OpenStack Lightspeed. Two new configuration sections were added: "okp" and "dev". The "okp" section holds configurations that are more final to the deployment where the "dev" is an easy to way for developers to test the feature while tests/developing it. The options available in "okp" section are: - offline: Whether OKP should be in "offline" mode or not. - accessKey: The OKP access key to decrypt the paid content in the image The options available in the "dev" section are: - feature_flags: This is a list of features that operator wants to expose to be enabled. The value "okp" in the list will deploy OKP. - okp_chunk_filter_query: This is where we can tweak the OKP filter to filter by product, version etc... Signed-off-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
1 parent d776272 commit 3959fad

32 files changed

Lines changed: 1017 additions & 13 deletions

api/v1beta1/openstacklightspeed_types.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
2222
"k8s.io/apimachinery/pkg/api/resource"
2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+
"k8s.io/apimachinery/pkg/runtime"
2425
)
2526

2627
const (
@@ -45,10 +46,36 @@ const (
4546
// ConsoleContainerImagePF5 is the fall-back console image for PatternFly 5 (OCP < 4.19)
4647
ConsoleContainerImagePF5 = "registry.redhat.io/openshift-lightspeed/lightspeed-console-plugin-pf5-rhel9:1.0.12"
4748

49+
// OKPContainerImage is the fall-back container image for OKP (Offline Knowledge Portal)
50+
OKPContainerImage = "registry.redhat.io/offline-knowledge-portal/rhokp-rhel9:latest"
51+
4852
// MaxTokensForResponseDefault is the default maximum number of tokens that should be used for response
4953
MaxTokensForResponseDefault = 2048
5054
)
5155

56+
// DevSpec is the internal structure for the Dev field. Not exposed in the CRD.
57+
// May change at any time without backward compatibility.
58+
type DevSpec struct {
59+
FeatureFlags []string `json:"featureFlags,omitempty"`
60+
OKPChunkFilterQuery string `json:"okpChunkFilterQuery,omitempty"`
61+
}
62+
63+
// OKPSpec defines configuration for the Offline Knowledge Portal (OKP).
64+
type OKPSpec struct {
65+
// +kubebuilder:validation:Optional
66+
// +kubebuilder:default=true
67+
// Offline controls how source URLs are resolved.
68+
// When true, uses parent_id (offline/Mimir-style).
69+
// When false, uses reference_url (online).
70+
Offline *bool `json:"offline,omitempty"`
71+
72+
// +kubebuilder:validation:Optional
73+
// AccessKey is the name of the Secret containing the access key for the OKP server.
74+
// The secret must contain a key named "access_key".
75+
// An access key can be obtained from https://access.redhat.com/offline/access
76+
AccessKey string `json:"accessKey,omitempty"`
77+
}
78+
5279
// DatabaseSpec defines configuration for persistent PostgreSQL storage.
5380
type DatabaseSpec struct {
5481
// +kubebuilder:validation:Optional
@@ -84,6 +111,16 @@ type OpenStackLightspeedSpec struct {
84111
// When omitted, an emptyDir volume is used (data is lost on pod reschedule).
85112
// When set, a PersistentVolumeClaim is created and mounted.
86113
Database *DatabaseSpec `json:"database,omitempty"`
114+
115+
// +kubebuilder:validation:Optional
116+
// OKP configures the Offline Knowledge Portal (OKP) RAG source.
117+
OKP *OKPSpec `json:"okp,omitempty"`
118+
119+
// +kubebuilder:validation:Optional
120+
// +kubebuilder:pruning:PreserveUnknownFields
121+
// Dev contains developer/experimental configuration.
122+
// This section is not part of the stable API and may change at any time without backward compatibility.
123+
Dev runtime.RawExtension `json:"dev,omitempty"`
87124
}
88125

89126
// LoggingConfig defines logging configuration for OpenStackLightspeed components
@@ -242,6 +279,7 @@ type OpenStackLightspeedDefaults struct {
242279
PostgresImageURL string
243280
ConsoleImageURL string
244281
ConsoleImagePF5URL string
282+
OKPImageURL string
245283
MaxTokensForResponse int
246284
}
247285

@@ -263,6 +301,8 @@ func SetupDefaults() {
263301
"RELATED_IMAGE_CONSOLE_IMAGE_URL_DEFAULT", ConsoleContainerImage),
264302
ConsoleImagePF5URL: util.GetEnvVar(
265303
"RELATED_IMAGE_CONSOLE_PF5_IMAGE_URL_DEFAULT", ConsoleContainerImagePF5),
304+
OKPImageURL: util.GetEnvVar(
305+
"RELATED_IMAGE_OKP_IMAGE_URL_DEFAULT", OKPContainerImage),
266306
MaxTokensForResponse: MaxTokensForResponseDefault,
267307
}
268308

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 47 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bundle/manifests/lightspeed.openstack.org_openstacklightspeeds.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ spec:
6969
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
7070
x-kubernetes-int-or-string: true
7171
type: object
72+
dev:
73+
description: |-
74+
Dev contains developer/experimental configuration.
75+
This section is not part of the stable API and may change at any time without backward compatibility.
76+
type: object
77+
x-kubernetes-preserve-unknown-fields: true
7278
enableOCPRAG:
7379
default: false
7480
description: Enables automatic OCP documentation based on cluster
@@ -155,6 +161,24 @@ spec:
155161
Allows forcing a specific OCP version instead of auto-detection.
156162
Format should be like "4.15", "4.16", etc.
157163
type: string
164+
okp:
165+
description: OKP configures the Offline Knowledge Portal (OKP) RAG
166+
source.
167+
properties:
168+
accessKey:
169+
description: |-
170+
AccessKey is the name of the Secret containing the access key for the OKP server.
171+
The secret must contain a key named "access_key".
172+
An access key can be obtained from https://access.redhat.com/offline/access
173+
type: string
174+
offline:
175+
default: true
176+
description: |-
177+
Offline controls how source URLs are resolved.
178+
When true, uses parent_id (offline/Mimir-style).
179+
When false, uses reference_url (online).
180+
type: boolean
181+
type: object
158182
ragImage:
159183
description: ContainerImage for the OpenStack Lightspeed RAG container
160184
(will be set to environmental default if empty)

bundle/manifests/openstack-lightspeed-operator.clusterserviceversion.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ metadata:
2525
]
2626
capabilities: Basic Install
2727
categories: AI/Machine Learning
28-
createdAt: "2026-05-28T16:28:23Z"
28+
createdAt: "2026-06-11T09:06:59Z"
2929
description: AI-powered virtual assistant for Red Hat OpenStack Services on OpenShift
3030
features.operators.openshift.io/cnf: "false"
3131
features.operators.openshift.io/cni: "false"
@@ -299,6 +299,8 @@ spec:
299299
value: quay.io/lightspeed-core/lightspeed-to-dataverse-exporter:latest
300300
- name: RELATED_IMAGE_POSTGRES_IMAGE_URL_DEFAULT
301301
value: registry.redhat.io/rhel9/postgresql-16:latest
302+
- name: RELATED_IMAGE_OKP_IMAGE_URL_DEFAULT
303+
value: registry.redhat.io/offline-knowledge-portal/rhokp-rhel9:latest
302304
image: quay.io/openstack-lightspeed/operator:latest
303305
livenessProbe:
304306
httpGet:
@@ -366,6 +368,7 @@ spec:
366368
- ""
367369
resources:
368370
- configmaps
371+
- services
369372
verbs:
370373
- create
371374
- delete
@@ -378,7 +381,6 @@ spec:
378381
- ""
379382
resources:
380383
- persistentvolumeclaims
381-
- services
382384
verbs:
383385
- create
384386
- get
@@ -415,6 +417,7 @@ spec:
415417
- deployments
416418
verbs:
417419
- create
420+
- delete
418421
- get
419422
- list
420423
- patch
@@ -479,4 +482,6 @@ spec:
479482
name: exporter-image-url-default
480483
- image: registry.redhat.io/rhel9/postgresql-16:latest
481484
name: postgres-image-url-default
485+
- image: registry.redhat.io/offline-knowledge-portal/rhokp-rhel9:latest
486+
name: okp-image-url-default
482487
version: 0.0.1

config/crd/bases/lightspeed.openstack.org_openstacklightspeeds.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ spec:
6969
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
7070
x-kubernetes-int-or-string: true
7171
type: object
72+
dev:
73+
description: |-
74+
Dev contains developer/experimental configuration.
75+
This section is not part of the stable API and may change at any time without backward compatibility.
76+
type: object
77+
x-kubernetes-preserve-unknown-fields: true
7278
enableOCPRAG:
7379
default: false
7480
description: Enables automatic OCP documentation based on cluster
@@ -155,6 +161,24 @@ spec:
155161
Allows forcing a specific OCP version instead of auto-detection.
156162
Format should be like "4.15", "4.16", etc.
157163
type: string
164+
okp:
165+
description: OKP configures the Offline Knowledge Portal (OKP) RAG
166+
source.
167+
properties:
168+
accessKey:
169+
description: |-
170+
AccessKey is the name of the Secret containing the access key for the OKP server.
171+
The secret must contain a key named "access_key".
172+
An access key can be obtained from https://access.redhat.com/offline/access
173+
type: string
174+
offline:
175+
default: true
176+
description: |-
177+
Offline controls how source URLs are resolved.
178+
When true, uses parent_id (offline/Mimir-style).
179+
When false, uses reference_url (online).
180+
type: boolean
181+
type: object
158182
ragImage:
159183
description: ContainerImage for the OpenStack Lightspeed RAG container
160184
(will be set to environmental default if empty)

config/manager/manager.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ spec:
8181
value: quay.io/lightspeed-core/lightspeed-to-dataverse-exporter:latest
8282
- name: RELATED_IMAGE_POSTGRES_IMAGE_URL_DEFAULT
8383
value: registry.redhat.io/rhel9/postgresql-16:latest
84+
- name: RELATED_IMAGE_OKP_IMAGE_URL_DEFAULT
85+
value: registry.redhat.io/offline-knowledge-portal/rhokp-rhel9:latest
8486
securityContext:
8587
allowPrivilegeEscalation: false
8688
capabilities:

config/rbac/role.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ rules:
100100
- ""
101101
resources:
102102
- configmaps
103+
- services
103104
verbs:
104105
- create
105106
- delete
@@ -112,7 +113,6 @@ rules:
112113
- ""
113114
resources:
114115
- persistentvolumeclaims
115-
- services
116116
verbs:
117117
- create
118118
- get
@@ -149,6 +149,7 @@ rules:
149149
- deployments
150150
verbs:
151151
- create
152+
- delete
152153
- get
153154
- list
154155
- patch

config/samples/api_v1beta1_openstacklightspeed.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ spec:
1515
# database:
1616
# size: "5Gi"
1717
# class: "my-storage-class"
18+
# Uncomment to enable OKP (Offline Knowledge Portal) as an Inline RAG source:
19+
# okp:
20+
# accessKey: okp-access-key-secret
21+
# dev:
22+
# featureFlags:
23+
# - okp
24+
# okpChunkFilterQuery: "product:(*openstack* OR *openshift*)"

hack/env.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export RELATED_IMAGE_POSTGRES_IMAGE_URL_DEFAULT="registry.redhat.io/rhel9/postgr
66
# the automated pipeline for building OGX-compatible vector database images
77
# is ready.
88
export RELATED_IMAGE_OPENSTACK_LIGHTSPEED_IMAGE_URL_DEFAULT="quay.io/openstack-lightspeed/rag-content:alpha-ogx-os-docs-2025.2"
9+
export RELATED_IMAGE_OKP_IMAGE_URL_DEFAULT="registry.redhat.io/offline-knowledge-portal/rhokp-rhel9:latest"
910
export WATCH_NAMESPACE="openstack-lightspeed"

internal/controller/common.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ package controller
1919
import (
2020
"context"
2121
_ "embed"
22+
"encoding/json"
2223
"errors"
2324
"fmt"
25+
"slices"
2426
"strings"
2527

2628
common_helper "github.com/openstack-k8s-operators/lib-common/modules/common/helper"
29+
apiv1beta1 "github.com/openstack-lightspeed/operator/api/v1beta1"
2730
appsv1 "k8s.io/api/apps/v1"
2831
corev1 "k8s.io/api/core/v1"
2932
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
@@ -126,6 +129,43 @@ func isDeploymentReady(deploy *appsv1.Deployment) bool {
126129
deploy.Status.Replicas == replicas
127130
}
128131

132+
// generateOKPSelectorLabels returns selector labels for OKP components.
133+
func generateOKPSelectorLabels() map[string]string {
134+
return map[string]string{
135+
"app.kubernetes.io/component": "okp-server",
136+
"app.kubernetes.io/managed-by": "openstack-lightspeed-operator",
137+
"app.kubernetes.io/name": "openstack-lightspeed-okp-server",
138+
"app.kubernetes.io/part-of": "openstack-lightspeed",
139+
}
140+
}
141+
142+
// parseDevConfig unmarshals the Dev RawExtension into a DevSpec.
143+
// Returns a zero-value DevSpec and an error on malformed input.
144+
func parseDevConfig(instance *apiv1beta1.OpenStackLightspeed) (apiv1beta1.DevSpec, error) {
145+
var config apiv1beta1.DevSpec
146+
if len(instance.Spec.Dev.Raw) > 0 {
147+
if err := json.Unmarshal(instance.Spec.Dev.Raw, &config); err != nil {
148+
return config, err
149+
}
150+
}
151+
return config, nil
152+
}
153+
154+
// isOKPEnabled returns true if the "okp" feature flag is present in the dev config.
155+
func isOKPEnabled(instance *apiv1beta1.OpenStackLightspeed) bool {
156+
config, _ := parseDevConfig(instance)
157+
return slices.Contains(config.FeatureFlags, "okp")
158+
}
159+
160+
// getOKPChunkFilterQuery returns the chunk filter query from the dev config, or the default.
161+
func getOKPChunkFilterQuery(instance *apiv1beta1.OpenStackLightspeed) string {
162+
config, _ := parseDevConfig(instance)
163+
if config.OKPChunkFilterQuery != "" {
164+
return config.OKPChunkFilterQuery
165+
}
166+
return OKPDefaultChunkFilterQuery
167+
}
168+
129169
// getDeployment retrieves deployment from the cluster
130170
func getDeployment(ctx context.Context, h *common_helper.Helper, name string, namespace string) (*appsv1.Deployment, error) {
131171
deployment := &appsv1.Deployment{}

0 commit comments

Comments
 (0)