Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
*.so
*.dylib
bin/
.idea/"
.idea/

# Local scan / experiment artifacts
leaktk-scan-*.log

main

# Test binary, built with `go test -c`
Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ build: manifests generate fmt vet ## Build manager binary.
dev-setup: manifests kustomize install ## Setup RBAC and resources for local development (idempotent, safe to run multiple times)
@echo "📦 Setting up local development environment..."
@$(KUBECTL) create namespace openshift-lightspeed --dry-run=client -o yaml | $(KUBECTL) apply -f - 2>/dev/null || true
@$(KUBECTL) apply -f bundle/manifests/lightspeed-operator-metrics-reader_v1_serviceaccount.yaml 2>/dev/null || true
@$(KUBECTL) apply -n openshift-lightspeed -f bundle/manifests/lightspeed-operator-metrics-reader_v1_serviceaccount.yaml 2>/dev/null || true
@$(KUBECTL) apply -n openshift-lightspeed -f config/dev/metrics-reader-token.yaml 2>/dev/null || true
@$(KUBECTL) apply -f bundle/manifests/lightspeed-operator-ols-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml 2>/dev/null || true
@$(KUBECTL) apply -f bundle/manifests/lightspeed-operator-ols-metrics-reader_rbac.authorization.k8s.io_v1_clusterrolebinding.yaml 2>/dev/null || true
@$(KUBECTL) apply -k config/user-access/ 2>/dev/null || true
Expand All @@ -246,7 +247,8 @@ dev-teardown: uninstall ## Teardown local development environment (removes RBAC,
@echo "🧹 Cleaning up local development environment..."
@$(KUBECTL) delete -f bundle/manifests/lightspeed-operator-ols-metrics-reader_rbac.authorization.k8s.io_v1_clusterrolebinding.yaml --ignore-not-found=true 2>/dev/null || true
@$(KUBECTL) delete -f bundle/manifests/lightspeed-operator-ols-metrics-reader_rbac.authorization.k8s.io_v1_clusterrole.yaml --ignore-not-found=true 2>/dev/null || true
@$(KUBECTL) delete -f bundle/manifests/lightspeed-operator-metrics-reader_v1_serviceaccount.yaml --ignore-not-found=true 2>/dev/null || true
@$(KUBECTL) delete -n openshift-lightspeed -f config/dev/metrics-reader-token.yaml --ignore-not-found=true 2>/dev/null || true
@$(KUBECTL) delete -n openshift-lightspeed -f bundle/manifests/lightspeed-operator-metrics-reader_v1_serviceaccount.yaml --ignore-not-found=true 2>/dev/null || true
@$(KUBECTL) delete -k config/user-access/ --ignore-not-found=true 2>/dev/null || true
@$(KUBECTL) delete namespace openshift-lightspeed --ignore-not-found=true 2>/dev/null || true
@echo "✅ Development environment cleaned up."
Expand Down
27 changes: 20 additions & 7 deletions api/v1alpha1/olsconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,18 +218,22 @@ type OLSSpec struct {
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Proxy Settings",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"}
// +kubebuilder:validation:Optional
ProxyConfig *ProxyConfig `json:"proxyConfig,omitempty"`
// RAG databases
// BYOK RAG databases (bring-your-own container images with FAISS vector indexes).
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="RAG Databases",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"}
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="BYOK RAG Databases",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"}
RAG []RAGSpec `json:"rag,omitempty"`
// Solr hybrid RAG (portal-rag /hybrid-search). When set, RHOKP sidecar and solr_hybrid are configured; local FAISS indexes remain for readiness until removed. Ignored when byokRAGOnly is true.
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Solr Hybrid RAG",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"}
SolrHybrid *SolrHybridSettings `json:"solrHybrid,omitempty"`
// LLM Token Quota Configuration
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="LLM Token Quota Configuration"
QuotaHandlersConfig *QuotaHandlersConfig `json:"quotaHandlersConfig,omitempty"`
// Persistent Storage Configuration
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Persistent Storage Configuration",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"}
Storage *Storage `json:"storage,omitempty"`
// Only use BYOK RAG sources, ignore the OpenShift documentation RAG
// Only use BYOK RAG sources, ignore the OpenShift documentation RAG and Solr hybrid RAG
// +kubebuilder:validation:Optional
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Only use BYOK RAG sources",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"}
ByokRAGOnly bool `json:"byokRAGOnly,omitempty"`
Expand Down Expand Up @@ -277,23 +281,32 @@ type MCPKubeServerConfiguration struct {
Timeout int `json:"timeout,omitempty"`
}

// RAGSpec defines how to retrieve RAG databases.
// RAGSpec defines a BYOK RAG database (container image and index path).
type RAGSpec struct {
// The path to the RAG database inside of the container image
// The path to the BYOK RAG database inside of the container image
// +kubebuilder:default="/rag/vector_db"
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Index Path in the Image"
IndexPath string `json:"indexPath,omitempty"`
// The Index ID of the RAG database. Only needed if there are multiple indices in the database.
// The Index ID of the BYOK RAG database. Only needed if there are multiple indices in the database.
// +kubebuilder:default=""
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Index ID"
IndexID string `json:"indexID,omitempty"`
// The URL of the container image to use as a RAG source
// The URL of the container image to use as a BYOK RAG source
// +kubebuilder:validation:Required
// +required
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Image"
Image string `json:"image"`
}

// SolrHybridSettings enables Solr hybrid RAG (portal-rag /hybrid-search) using the operator RHOKP sidecar.
// Retrieval tuning and Solr URL are set in the OLS config file by the operator, not on this CR.
type SolrHybridSettings struct {
// When true, merge Solr hybrid hits into the prompt as direct RAG context.
// When false, expose documentation search via tool only. Omitted is treated as false by the operator.
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Solr Direct RAG",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"}
SolrDirectRAG *bool `json:"solrDirectRag,omitempty"`
}

// QuotaHandlersConfig defines the token quota configuration
type QuotaHandlersConfig struct {
// Token quota limiters
Expand Down
99 changes: 42 additions & 57 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ var (
"openshift-mcp-server-image": utils.OpenShiftMCPServerImageDefault,
"dataverse-exporter-image": utils.DataverseExporterImageDefault,
"ocp-rag-image": utils.OcpRagImageDefault,
"rhokp-image": utils.RHOOKPImageDefault,
}
)

Expand All @@ -119,7 +120,7 @@ func init() {

// overrideImages overrides the default images with the images provided by the user.
// If an image is not provided, the default is used.
func overrideImages(serviceImage string, consoleImage string, consoleImage_pf5 string, consoleImage_419 string, postgresImage string, openshiftMCPServerImage string, dataverseExporterImage string, ocpRagImage string) map[string]string {
func overrideImages(serviceImage string, consoleImage string, consoleImage_pf5 string, consoleImage_419 string, postgresImage string, openshiftMCPServerImage string, dataverseExporterImage string, ocpRagImage string, rhokpImage string) map[string]string {
res := defaultImages
if serviceImage != "" {
res["lightspeed-service"] = serviceImage
Expand All @@ -145,6 +146,9 @@ func overrideImages(serviceImage string, consoleImage string, consoleImage_pf5 s
if ocpRagImage != "" {
res["ocp-rag-image"] = ocpRagImage
}
if rhokpImage != "" {
res["rhokp-image"] = rhokpImage
}
return res
}

Expand Down Expand Up @@ -179,6 +183,7 @@ func main() {
var openshiftMCPServerImage string
var dataverseExporterImage string
var ocpRagImage string
var rhokpImage string
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
Expand All @@ -198,6 +203,7 @@ func main() {
flag.StringVar(&openshiftMCPServerImage, "openshift-mcp-server-image", utils.OpenShiftMCPServerImageDefault, "The image of the OpenShift MCP server container.")
flag.StringVar(&dataverseExporterImage, "dataverse-exporter-image", utils.DataverseExporterImageDefault, "The image of the dataverse exporter container.")
flag.StringVar(&ocpRagImage, "ocp-rag-image", utils.OcpRagImageDefault, "The image with the OCP RAG databases.")
flag.StringVar(&rhokpImage, "rhokp-image", utils.RHOOKPImageDefault, "The RH Offline Knowledge Portal (Solr) sidecar image for Solr hybrid RAG.")
opts := zap.Options{
Development: true,
}
Expand All @@ -210,7 +216,7 @@ func main() {
namespace = getWatchNamespace()
}

imagesMap := overrideImages(serviceImage, consoleImage, consoleImage_pf5, consoleImage_419, postgresImage, openshiftMCPServerImage, dataverseExporterImage, ocpRagImage)
imagesMap := overrideImages(serviceImage, consoleImage, consoleImage_pf5, consoleImage_419, postgresImage, openshiftMCPServerImage, dataverseExporterImage, ocpRagImage, rhokpImage)
setupLog.Info("Images setting loaded", "images", listImages())

setupLog.Info("Starting the operator", "metricsAddr", metricsAddr, "probeAddr", probeAddr, "certDir", certDir, "certName", certName, "keyName", keyName, "namespace", namespace)
Expand Down Expand Up @@ -424,6 +430,7 @@ func main() {
LightspeedServicePostgresImage: imagesMap["postgres-image"],
OpenShiftMCPServerImage: imagesMap["openshift-mcp-server-image"],
DataverseExporterImage: imagesMap["dataverse-exporter-image"],
RHOOKPImage: imagesMap["rhokp-image"],
Namespace: namespace,
PrometheusAvailable: prometheusAvailable,
},
Expand Down
30 changes: 22 additions & 8 deletions config/crd/bases/ols.openshift.io_olsconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ spec:
x-kubernetes-map-type: atomic
byokRAGOnly:
description: Only use BYOK RAG sources, ignore the OpenShift documentation
RAG
RAG and Solr hybrid RAG
type: boolean
conversationCache:
description: Conversation cache settings
Expand Down Expand Up @@ -4450,28 +4450,42 @@ spec:
type: array
type: object
rag:
description: RAG databases
description: BYOK RAG databases (bring-your-own container images
with FAISS vector indexes).
items:
description: RAGSpec defines how to retrieve RAG databases.
description: RAGSpec defines a BYOK RAG database (container
image and index path).
properties:
image:
description: The URL of the container image to use as a
RAG source
BYOK RAG source
type: string
indexID:
default: ""
description: The Index ID of the RAG database. Only needed
if there are multiple indices in the database.
description: The Index ID of the BYOK RAG database. Only
needed if there are multiple indices in the database.
type: string
indexPath:
default: /rag/vector_db
description: The path to the RAG database inside of the
container image
description: The path to the BYOK RAG database inside of
the container image
type: string
required:
- image
type: object
type: array
solrHybrid:
description: Solr hybrid RAG (portal-rag /hybrid-search). When
set, RHOKP sidecar and solr_hybrid are configured; local FAISS
indexes remain for readiness until removed. Ignored when byokRAGOnly
is true.
properties:
solrDirectRag:
description: |-
When true, merge Solr hybrid hits into the prompt as direct RAG context.
When false, expose documentation search via tool only. Omitted is treated as false by the operator.
type: boolean
type: object
storage:
description: Persistent Storage Configuration
properties:
Expand Down
3 changes: 3 additions & 0 deletions config/default/deployment-patch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
- op: add
path: /spec/template/spec/containers/0/args/-
value: --ocp-rag-image=__REPLACE_LIGHTSPEED_OCP_RAG__
- op: add
path: /spec/template/spec/containers/0/args/-
value: --rhokp-image=__REPLACE_RHOKP__
- op: replace
path: /spec/template/spec/containers/0/image
value: __REPLACE_LIGHTSPEED_OPERATOR__
Loading