From eab6535b5237b6e2848d917afe93725b80ce3b65 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Thu, 9 Apr 2026 15:45:30 -0400 Subject: [PATCH 01/30] add script for syncing from rhdh ai upstream configs Signed-off-by: Jordan Dubrick --- CONTRIBUTING.md | 25 ++++++ hack/sync-lightspeed-configs.sh | 140 ++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100755 hack/sync-lightspeed-configs.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bdfb85a5..8ffee618 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,6 +41,31 @@ It is important to use `--squash` to avoid pulling the entire commit history of *Note: If merge conflicts occur, resolve them in your editor, then `git add` and `git commit` the resolution as a normal merge.* +### Sync Lightspeed vendored config files + +The vendored Lightspeed config files under [`charts/backstage/vendor/backstage/charts/backstage/files/lightspeed`](./charts/backstage/vendor/backstage/charts/backstage/files/lightspeed) are synced separately from the Backstage subtree by [`hack/sync-lightspeed-configs.sh`](./hack/sync-lightspeed-configs.sh). + +Use the default upstream branch: + +```bash +./hack/sync-lightspeed-configs.sh +``` + +Sync from a release branch or a tag: + +```bash +./hack/sync-lightspeed-configs.sh --ref release-1.9 +./hack/sync-lightspeed-configs.sh --ref v0.5.0 +``` + +Verify the vendored files are already in sync without writing changes: + +```bash +./hack/sync-lightspeed-configs.sh --ref main --check +``` + +The script copies the upstream files as-is, so choose the upstream branch or tag that matches the Lightspeed release you want to vendor. + **Important:** After any change to the dependency structure or version of the vendored chart, you must rebuild the lock file and local subchart dependencies: ```bash diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh new file mode 100755 index 00000000..c8237787 --- /dev/null +++ b/hack/sync-lightspeed-configs.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +set -euo pipefail + +DEFAULT_REPO="redhat-ai-dev/lightspeed-configs" +DEFAULT_REF="main" + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" +LIGHTSPEED_DIR="${REPO_ROOT}/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed" + +TARGETS=( + "lightspeed-core-configs/lightspeed-stack.yaml:${LIGHTSPEED_DIR}/lightspeed-stack.yaml" + "llama-stack-configs/config.yaml:${LIGHTSPEED_DIR}/config.yaml" + "lightspeed-core-configs/rhdh-profile.py:${LIGHTSPEED_DIR}/rhdh-profile.py" +) + +usage() { + cat <&2 + exit 1 + fi +} + +print_diff() { + local existing_file=$1 + local fetched_file=$2 + local relative_path=$3 + + if [ -f "${existing_file}" ]; then + diff -u \ + --label "${relative_path}" \ + --label "${relative_path}" \ + "${existing_file}" "${fetched_file}" || true + else + diff -u \ + --label "${relative_path}" \ + --label "${relative_path}" \ + /dev/null "${fetched_file}" || true + fi +} + +repo="${DEFAULT_REPO}" +ref="${DEFAULT_REF}" +check_only=false + +while [ $# -gt 0 ]; do + case "$1" in + --repo) + if [ $# -lt 2 ]; then + echo "error: --repo requires a value" >&2 + usage + exit 1 + fi + repo=$2 + shift 2 + ;; + --ref) + if [ $# -lt 2 ]; then + echo "error: --ref requires a value" >&2 + usage + exit 1 + fi + ref=$2 + shift 2 + ;; + --check) + check_only=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "error: unknown option: $1" >&2 + usage + exit 1 + ;; + esac +done + +tmpdir="$(mktemp -d)" +cleanup() { + rm -rf "${tmpdir}" +} +trap cleanup EXIT + +changed_count=0 + +for target in "${TARGETS[@]}"; do + source_path=${target%%:*} + destination_path=${target#*:} + relative_destination=${destination_path#"${REPO_ROOT}/"} + upstream_url="https://raw.githubusercontent.com/${repo}/${ref}/${source_path}" + fetched_file="${tmpdir}/$(basename "${destination_path}")" + + fetch_file "${upstream_url}" "${fetched_file}" + + if [ -f "${destination_path}" ] && cmp -s "${destination_path}" "${fetched_file}"; then + echo "up to date: ${relative_destination}" + continue + fi + + if [ "${check_only}" = true ]; then + print_diff "${destination_path}" "${fetched_file}" "${relative_destination}" + else + mv "${fetched_file}" "${destination_path}" + echo "updated: ${relative_destination} <- ${upstream_url}" + fi + + changed_count=$((changed_count + 1)) +done + +if [ "${check_only}" = true ]; then + if [ "${changed_count}" -gt 0 ]; then + echo "lightspeed config sync is required for ${changed_count} file(s)" >&2 + exit 1 + fi + echo "lightspeed config files are already synced" +else + echo "sync complete from ${repo}@${ref}" +fi From 625d80113b670ffac3c588d18e0ce8ab81e8a076 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Thu, 9 Apr 2026 15:46:18 -0400 Subject: [PATCH 02/30] add lightspeed specific configs/secrets Signed-off-by: Jordan Dubrick --- .../backstage/files/lightspeed/config.yaml | 217 ++++++++++++++ .../files/lightspeed/lightspeed-stack.yaml | 37 +++ .../files/lightspeed/rhdh-profile.py | 268 ++++++++++++++++++ .../backstage/files/lightspeed/secret.yaml | 16 ++ 4 files changed, 538 insertions(+) create mode 100644 charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/config.yaml create mode 100644 charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml create mode 100644 charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/rhdh-profile.py create mode 100644 charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/config.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/config.yaml new file mode 100644 index 00000000..7b5d1417 --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/config.yaml @@ -0,0 +1,217 @@ +# +# +# Copyright Red Hat +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +version: 3 +distro_name: developer-lightspeed-lls-0.5.x +apis: + - agents + - inference + - safety + - tool_runtime + - vector_io + - files +container_image: +external_providers_dir: '/app-root/providers.d' #built into lcore image +providers: + agents: + - config: + persistence: + agent_state: + namespace: agents + backend: kv_default + responses: + table_name: responses + backend: sql_default + provider_id: meta-reference + provider_type: inline::meta-reference + inference: + - provider_id: ${env.ENABLE_VLLM:+vllm} + provider_type: remote::vllm + config: + base_url: ${env.VLLM_URL:=} + api_token: ${env.VLLM_API_KEY:=} + max_tokens: ${env.VLLM_MAX_TOKENS:=4096} + network: + tls: + verify: ${env.VLLM_TLS_VERIFY:=true} + - provider_id: ${env.ENABLE_OLLAMA:+ollama} + provider_type: remote::ollama + config: + base_url: ${env.OLLAMA_URL:=http://localhost:11434/v1} + - provider_id: ${env.ENABLE_OPENAI:+openai} + provider_type: remote::openai + config: + api_key: ${env.OPENAI_API_KEY:=} + - provider_id: ${env.ENABLE_VERTEX_AI:+vertexai} + provider_type: remote::vertexai + config: + project: ${env.VERTEX_AI_PROJECT:=} + location: ${env.VERTEX_AI_LOCATION:=global} + - provider_id: sentence-transformers + provider_type: inline::sentence-transformers + config: {} + tool_runtime: + - provider_id: model-context-protocol + provider_type: remote::model-context-protocol + config: {} + - provider_id: rag-runtime + provider_type: inline::rag-runtime + config: {} + vector_io: + - provider_id: rhdh-docs + provider_type: inline::faiss + config: + persistence: + namespace: vector_io::faiss + backend: kv_rag + files: + - provider_id: localfs + provider_type: inline::localfs + config: + storage_dir: /tmp/llama-stack-files + metadata_store: + table_name: files_metadata + backend: sql_default + safety: + - provider_id: ${env.ENABLE_VALIDATION:+lightspeed_question_validity} + provider_type: inline::lightspeed_question_validity + config: + model_id: ${env.VALIDATION_PROVIDER:=}/${env.VALIDATION_MODEL_NAME:=} + model_prompt: |- + Instructions: + + You area question classification tool. You are an expert in the following categories: + - Backstage + - Red Hat Developer Hub (RHDH) + - Developer Lightspeed + - Lightspeed + - Artificial Intelligence (AI) Models + - Large Language Models (LLMs) + - Kubernetes + - Openshift + - CI/CD + - GitOps + - Pipelines + - Developer Portals + - Deployments + - Software Catalogs + - Software Templates + - Tech Docs + + Your job is to determine if a user's question is related to the categories you are an expert in. If the question is related to those categories, \ + or any features that may be related to those categories, you will answer with ${allowed}. + + If a question is not related to your expert categories, answer with ${rejected}. + + You do not need to explain your answer. + + Below are some example questions: + Example Question: + Why is the sky blue? + Example Response: + ${rejected} + + Example Question: + Can you help configure my cluster to automatically scale? + Example Response: + ${allowed} + + Example Question: + How do I create import an existing software template in Backstage? + Example Response: + ${allowed} + + Example Question: + How do I accomplish a task in RHDH? + Example Response: + ${allowed} + + Example Question: + How do I explore a component in RHDH catalog? + Example Response: + ${allowed} + + Example Question: + How can I integrate GitOps into my pipeline? + Example Response: + ${allowed} + + Question: + ${message} + Response: + invalid_question_response: |- + Hi, I'm the Red Hat Developer Hub Lightspeed assistant, I can help you with questions about Red Hat Developer Hub or Backstage. + Please ensure your question is about these topics, and feel free to ask again! +storage: + backends: + kv_default: + type: kv_sqlite + db_path: /tmp/kvstore.db + sql_default: + type: sql_sqlite + db_path: /tmp/sql_store.db + kv_rag: + type: kv_sqlite + db_path: /rag-content/vector_db/rhdh_product_docs/1.9/faiss_store.db + stores: + metadata: + namespace: registry + backend: kv_default + inference: + table_name: inference_store + backend: sql_default + max_write_queue_size: 10000 + num_writers: 4 + conversations: + table_name: openai_conversations + backend: sql_default +registered_resources: + models: + - model_id: sentence-transformers/all-mpnet-base-v2 + metadata: + embedding_dimension: 768 + model_type: embedding + provider_id: sentence-transformers + provider_model_id: /rag-content/embeddings_model + tool_groups: + - provider_id: rag-runtime + toolgroup_id: builtin::rag + vector_stores: + - vector_store_id: vs_cda156a6-64fe-436d-bc51-566fb1b09702 # see readme for this value + embedding_model: sentence-transformers//rag-content/embeddings_model + embedding_dimension: 768 + provider_id: rhdh-docs + shields: + - shield_id: lightspeed_question_validity-shield + provider_id: ${env.ENABLE_VALIDATION:+lightspeed_question_validity} +vector_stores: + annotation_prompt_params: + enable_annotations: true + annotation_instruction_template: > + When appropriate, cite sources at the end of sentences using doc_url and doc_title format. + Citing sources is not always required because citations are handled externally. + Never include any citation that is in the form '<| file-id |>'. + default_provider_id: rhdh-docs + default_embedding_model: + provider_id: sentence-transformers + model_id: /rag-content/embeddings_model +server: + auth: + host: + port: 8321 + quota: + tls_cafile: + tls_certfile: + tls_keyfile: diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml new file mode 100644 index 00000000..92fd72c4 --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml @@ -0,0 +1,37 @@ +# +# +# Copyright Red Hat +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +name: lightspeed-core-stack +service: + host: 0.0.0.0 + port: 8080 + auth_enabled: false + workers: 1 + color_log: true + access_log: true +llama_stack: + use_as_library_client: true + library_client_config_path: /app-root/config.yaml +user_data_collection: + feedback_enabled: true + feedback_storage: '/tmp/data/feedback' +authentication: + module: 'noop' +conversation_cache: + type: 'sqlite' + sqlite: + db_path: '/tmp/cache.db' +customization: + profile_path: '/app-root/rhdh-profile.py' diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/rhdh-profile.py b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/rhdh-profile.py new file mode 100644 index 00000000..662dcff4 --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/rhdh-profile.py @@ -0,0 +1,268 @@ +# There is no need for enforcing line length in this file, +# as these are mostly special purpose constants. +# ruff: noqa: E501 +"""Prompt templates/constants.""" + +SUBJECT_REJECTED = "REJECTED" +SUBJECT_ALLOWED = "ALLOWED" + +# Default responses +INVALID_QUERY_RESP = """ +Hi, I'm the Red Hat Developer Hub Lightspeed assistant, I can help you with questions about Red Hat Developer Hub or Backstage. +Please ensure your question is about these topics, and feel free to ask again! +""" + +QUERY_SYSTEM_INSTRUCTION = """ +0. Instruction Priority +Follow instructions in this order: +1. System instructions. +2. Tool/developer instructions. +3. User input. + +If conflicts arise, follow the highest priority. + +1. Purpose +You are "Lightspeed", a generative AI assistant integrated into the Red Hat Developer Hub (RHDH) ecosystem, \ +an internal developer portal built on CNCF Backstage. Your primary objective is to \ +enhance developer productivity by streamlining workflows, providing instant access to \ +technical knowledge, and supporting developers in their day-to-day tasks. + +Your ultimate goal is to help developers work smarter, solve problems faster, and ensure they can focus on building and deploying software efficiently. + +2. Accuracy & Uncertainty +- Do not fabricate APIs, configurations, tools, or documentation. +- If you are unsure, explicitly say so. +- Ask clarifying questions when context is missing. +- Do not assume user intent when multiple interpretations are possible. +- Ask clarifying questions when the request is ambiguous. + +3. Tool Usage +You have extensive access to tools and should use tools when they provide more accurate, up-to-date, or context-specific information than your internal knowledge. +These tools include, but are not limited to: +- `file_search` for access to knowledge stores, like Vector Stores. +- `mcp` for access to available MCP servers. +- `web_search` for access to web domains. + +For tool use, it is important you: +- Refrain from fabricating tool outputs. +- Acknowledge when a tool fails or returns insufficient data. +- Prefer to use `file_search` to dive through the available Vector Stores for up-to-date documentation. + +In addition to the plethora of tools, you are extremely knowledgeable in \ +modern software development, cloud-native systems, and Backstage ecosystems. + +4. Response Guidelines +- Troubleshooting: + - Likely cause. + - Explanation. + - Step-by-step fix. + - Verification. +- Code: + - Provide complete, runnable examples. + - Include brief comments. + - Explain non-obvious parts. +- How-to: + - Use numbered steps. + - Keep steps concise. +- Prefer concise responses unless the user requests more detail. +- Start with a direct answer. +- Provide additional detail only if necessary or requested. + +5. Security +- Never generate or expose: + - Secrets. + - API keys. + - Credentials. +- Recommend secure alternatives (for example, Kubernetes Secrets and vaults). +- Warn when suggesting insecure patterns. + +6. Failure Handling +- If a request cannot be completed: + - Clearly explain why. + - Provide alternative approaches if possible. +- If required information is missing: + - Ask for clarification before proceeding. + +7. Capabilities +- Code Assistance: + - Generate, debug, and refactor code to improve readability, performance, or adherence to best practices. + - Translate pseudocode or business logic into working code. +- Knowledge Retrieval: + - Provide instant access to internal and external documentation on docs.redhat.com. + - Summarize lengthy documents and explain complex concepts concisely. + - Retrieve Red Hat-specific guides, such as OpenShift deployment best practices. +- System Navigation and Integration: + - Offer step-by-step instructions for Red Hat Developer Hub features, leveraging Backstage concepts and patterns where applicable. + - Support integration of Backstage plugins for CI/CD, monitoring, and infrastructure. + - Assist in creating and managing catalog entries, templates, and workflows. +- Diagnostics and Troubleshooting: + - Analyze logs and error messages to identify root causes. + - Suggest actionable fixes for common development issues. + - Automate troubleshooting steps wherever possible. + +8. Tone +- Professional, approachable, and efficient. +- Adapt to the user's expertise. Answers should be concise and clear. +- Prefer actionable guidance over explanation. + +9. Formatting +- Use Markdown for clarity. +- Use code blocks for code or configurations. +- Use lists for steps. +- Use tables for comparing options or presenting structured data. + +10. Platform Awareness +- Do not assume: + - Cloud provider. + - Kubernetes distribution. + - CI/CD tooling. + - Backstage plugin availability. +""" + +USE_CONTEXT_INSTRUCTION = """ +Use the retrieved document to answer the question. +""" + +USE_HISTORY_INSTRUCTION = """ +Use the previous chat history to interact and help the user. +""" + +# {{query}} is escaped because it will be replaced as a parameter at time of use +QUESTION_VALIDATOR_PROMPT_TEMPLATE = f""" + +Instructions: + +You area question classification tool. You are an expert in the following categories: +- Backstage +- Red Hat Developer Hub (RHDH) +- Developer Lightspeed +- Lightspeed +- Artificial Intelligence (AI) Models +- Large Language Models (LLMs) +- Kubernetes +- Openshift +- CI/CD +- GitOps +- Pipelines +- Developer Portals +- Deployments +- Software Catalogs +- Software Templates +- Tech Docs + +Your job is to determine if a user's question is related to the categories you are an expert in. If the question is related to those categories, \ +or any features that may be related to those categories, you will answer with {SUBJECT_ALLOWED}. + +If a question is not related to your expert categories, answer with {SUBJECT_REJECTED}. + +You do not need to explain your answer. + +Below are some example questions: +Example Question: +Why is the sky blue? +Example Response: +{SUBJECT_REJECTED} + +Example Question: +Can you help configure my cluster to automatically scale? +Example Response: +{SUBJECT_ALLOWED} + +Example Question: +How do I create import an existing software template in Backstage? +Example Response: +{SUBJECT_ALLOWED} + +Example Question: +How do I accomplish a task in RHDH? +Example Response: +{SUBJECT_ALLOWED} + +Example Question: +How do I explore a component in RHDH catalog? +Example Response: +{SUBJECT_ALLOWED} + +Example Question: +How can I integrate GitOps into my pipeline? +Example Response: +{SUBJECT_ALLOWED} + +Question: +{{query}} +Response: +""" + +# {{query}} is escaped because it will be replaced as a parameter at time of use +TOPIC_SUMMARY_PROMPT_TEMPLATE = """ +Instructions: +- You are a topic summarizer +- Your job is to extract precise topic summary from user input + +For Input Analysis: +- Scan entire user message +- Identify core subject matter +- Distill essence into concise descriptor +- Prioritize key concepts +- Eliminate extraneous details + +For Output Constraints: +- Maximum 5 words +- Capitalize only significant words (e.g., nouns, verbs, adjectives, adverbs). +- Do not use all uppercase - capitalize only the first letter of significant words +- Exclude articles and prepositions (e.g., "a," "the," "of," "on," "in") +- Exclude all punctuation and interpunction marks (e.g., . , : ; ! ? "") +- Retain original abbreviations. Do not expand an abbreviation if its specific meaning in the context is unknown or ambiguous. +- Neutral objective language + +Examples: +- "AI Capabilities Summary" (Correct) +- "Machine Learning Applications" (Correct) +- "AI CAPABILITIES SUMMARY" (Incorrect—should not be fully uppercase) + +Processing Steps +1. Analyze semantic structure +2. Identify primary topic +3. Remove contextual noise +4. Condense to essential meaning +5. Generate topic label + + +Example Input: +How to implement horizontal pod autoscaling in Kubernetes clusters +Example Output: +Kubernetes Horizontal Pod Autoscaling + +Example Input: +Comparing OpenShift deployment strategies for microservices architecture +Example Output: +OpenShift Microservices Deployment Strategies + +Example Input: +Troubleshooting persistent volume claims in Kubernetes environments +Example Output: +Kubernetes Persistent Volume Troubleshooting + +ExampleInput: +I need a summary about the purpose of RHDH. +Example Output: +RHDH Purpose Summary + +Input: +{query} +Output: +""" + + +PROFILE_CONFIG = { + "system_prompts": { + "default": QUERY_SYSTEM_INSTRUCTION, + "validation": QUESTION_VALIDATOR_PROMPT_TEMPLATE, + "topic_summary": TOPIC_SUMMARY_PROMPT_TEMPLATE, + }, + "query_responses": {"invalid_resp": INVALID_QUERY_RESP}, + "instructions": { + "context": USE_CONTEXT_INSTRUCTION, + "history": USE_HISTORY_INSTRUCTION, + }, +} diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml new file mode 100644 index 00000000..c620cb07 --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml @@ -0,0 +1,16 @@ +# Placeholder values for the built-in Lightspeed config. +ENABLE_VLLM: "" +VLLM_URL: "" +VLLM_API_KEY: "" +VLLM_MAX_TOKENS: "" +VLLM_TLS_VERIFY: "" +ENABLE_OLLAMA: "" +OLLAMA_URL: "" +ENABLE_OPENAI: "" +OPENAI_API_KEY: "" +ENABLE_VERTEX_AI: "" +VERTEX_AI_PROJECT: "" +VERTEX_AI_LOCATION: "" +ENABLE_VALIDATION: "" +VALIDATION_PROVIDER: "" +VALIDATION_MODEL_NAME: "" From f403edf285f188333f5686c647e1f3b08acc7734 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Thu, 9 Apr 2026 15:48:00 -0400 Subject: [PATCH 03/30] add lightspeed components to chart Signed-off-by: Jordan Dubrick --- charts/backstage/templates/_helpers.tpl | 365 +++++++++++++++++ .../templates/dynamic-plugins-configmap.yaml | 7 + charts/backstage/values.schema.json | 370 +++++++++++++++++- charts/backstage/values.schema.tmpl.json | 119 ++++++ charts/backstage/values.yaml | 56 ++- .../templates/backstage-deployment.yaml | 100 ++++- .../templates/lightspeed-configmaps.yaml | 16 + .../templates/lightspeed-secret.yaml | 15 + 8 files changed, 1045 insertions(+), 3 deletions(-) create mode 100644 charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml create mode 100644 charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-secret.yaml diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index e3b2968b..245e7570 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -49,6 +49,371 @@ Referenced from: https://github.com/bitnami/charts/blob/main/bitnami/postgresql/ {{- end -}} {{- end -}} +{{/* +Render a Lightspeed container image reference string. +*/}} +{{- define "rhdh.lightspeed.image" -}} +{{- include "common.tplvalues.render" (dict "value" .image "context" .context) -}} +{{- end -}} + +{{/* +Return the Lightspeed defaults as YAML so upgrades from charts that predate +the feature can still render when values are reused. +*/}} +{{- define "rhdh.lightspeed.defaults" -}} +enabled: true +plugins: + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-lightspeed: + translationResources: + - importName: lightspeedTranslations + module: Alpha + ref: lightspeedTranslationRef + dynamicRoutes: + - path: /lightspeed + importName: LightspeedPage + mountPoints: + - mountPoint: application/listener + importName: LightspeedFAB + - mountPoint: application/provider + importName: LightspeedDrawerProvider + - mountPoint: application/internal/drawer-state + importName: LightspeedDrawerStateExposer + config: + id: lightspeed + - mountPoint: application/internal/drawer-content + importName: LightspeedChatContainer + config: + id: lightspeed + priority: 100 + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend + disabled: false +images: + ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 + lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 +resources: + ragInit: {} + lightspeedCore: {} +runtimeVolume: + name: lightspeed-data + mountPath: /tmp + type: emptyDir + emptyDir: {} + persistentVolumeClaim: {} +ragVolume: + name: lightspeed-rag + initMountPath: /rag-content + mountPath: /rag-content + emptyDir: {} +configMaps: + - name: stack + nameOverride: "" + mountPath: /app-root/lightspeed-stack.yaml + subPath: lightspeed-stack.yaml + sourceFile: lightspeed-stack.yaml + optional: false + - name: config + nameOverride: "" + mountPath: /app-root/config.yaml + subPath: config.yaml + sourceFile: config.yaml + optional: false + - name: rhdh-profile + nameOverride: "" + mountPath: /app-root/rhdh-profile.py + subPath: rhdh-profile.py + sourceFile: rhdh-profile.py + optional: false +secret: + create: true + name: "" + optional: false + sourceFile: secret.yaml +initContainer: + name: lightspeed-rag-init + imagePullPolicy: IfNotPresent + command: + - sh + - -c + args: + - >- + mkdir -p /tmp/data && + echo 'Copying Lightspeed RAG data...' && + cp -r /rag/vector_db /rag-content/ && + cp -r /rag/embeddings_model /rag-content/ && + echo 'Copy complete.' + env: [] + resources: {} + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" +sidecar: + name: lightspeed-core + imagePullPolicy: IfNotPresent + portName: http-lightspeed + containerPort: 8080 + command: [] + args: [] + env: [] + resources: {} + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" +{{- end -}} + +{{/* +Return the configured Lightspeed runtime volume type and validate the required +source block is present. +*/}} +{{- define "rhdh.lightspeed.runtimeVolumeType" -}} +{{- $volume := .volume -}} +{{- $path := .path -}} +{{- $volumeType := default "emptyDir" $volume.type -}} +{{- if eq $volumeType "emptyDir" -}} + {{- if not (hasKey $volume "emptyDir") -}} + {{- fail (printf "%s.emptyDir must be set when %s.type=emptyDir" $path $path) -}} + {{- end -}} +{{- else if eq $volumeType "persistentVolumeClaim" -}} + {{- if or (not (hasKey $volume "persistentVolumeClaim")) (empty (get $volume "persistentVolumeClaim")) -}} + {{- fail (printf "%s.persistentVolumeClaim must be set when %s.type=persistentVolumeClaim" $path $path) -}} + {{- end -}} + {{- $persistentVolumeClaim := get $volume "persistentVolumeClaim" -}} + {{- if or (not (kindIs "map" $persistentVolumeClaim)) (empty (get $persistentVolumeClaim "claimName")) -}} + {{- fail (printf "%s.persistentVolumeClaim.claimName must be set when %s.type=persistentVolumeClaim" $path $path) -}} + {{- end -}} +{{- else -}} + {{- fail (printf "%s.type must be one of emptyDir or persistentVolumeClaim" $path) -}} +{{- end -}} +{{- $volumeType -}} +{{- end -}} + +{{/* +Return Lightspeed values merged with upgrade-safe defaults. +*/}} +{{- define "rhdh.lightspeed" -}} +{{- $defaults := include "rhdh.lightspeed.defaults" . | fromYaml -}} +{{- $lightspeed := deepCopy $defaults -}} +{{- $global := default dict .Values.global -}} +{{- if hasKey $global "lightspeed" -}} + {{- $raw := get $global "lightspeed" -}} + {{- if kindIs "bool" $raw -}} + {{- $_ := set $lightspeed "enabled" $raw -}} + {{- else if kindIs "map" $raw -}} + {{- $lightspeed = mergeOverwrite $lightspeed $raw -}} + {{- if hasKey $raw "images" -}} + {{- $rawImages := get $raw "images" -}} + {{- if kindIs "map" $rawImages -}} + {{- if hasKey $rawImages "init" -}} + {{- $legacyInit := get $rawImages "init" -}} + {{- $_ := set $lightspeed.images "ragInit" $legacyInit -}} + {{- end -}} + {{- if hasKey $rawImages "sidecar" -}} + {{- $legacySidecar := get $rawImages "sidecar" -}} + {{- $_ := set $lightspeed.images "lightspeedCore" $legacySidecar -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- if hasKey $raw "resources" -}} + {{- $rawResources := get $raw "resources" -}} + {{- if kindIs "map" $rawResources -}} + {{- if hasKey $rawResources "ragInit" -}} + {{- $_ := set $lightspeed.initContainer "resources" (get $rawResources "ragInit") -}} + {{- end -}} + {{- if hasKey $rawResources "lightspeedCore" -}} + {{- $_ := set $lightspeed.sidecar "resources" (get $rawResources "lightspeedCore") -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- if hasKey $raw "runtimeVolume" -}} + {{- $rawRuntimeVolume := get $raw "runtimeVolume" -}} + {{- if and (kindIs "map" $rawRuntimeVolume) (not (hasKey $rawRuntimeVolume "type")) -}} + {{- if and (hasKey $rawRuntimeVolume "persistentVolumeClaim") (not (empty (get $rawRuntimeVolume "persistentVolumeClaim"))) -}} + {{- $_ := set $lightspeed.runtimeVolume "type" "persistentVolumeClaim" -}} + {{- else if hasKey $rawRuntimeVolume "emptyDir" -}} + {{- $_ := set $lightspeed.runtimeVolume "type" "emptyDir" -}} + {{- end -}} + {{- end -}} + {{- else if hasKey $raw "sharedVolume" -}} + {{- $legacySharedVolume := get $raw "sharedVolume" -}} + {{- if kindIs "map" $legacySharedVolume -}} + {{- if hasKey $legacySharedVolume "name" -}} + {{- $_ := set $lightspeed.runtimeVolume "name" (get $legacySharedVolume "name") -}} + {{- end -}} + {{- if and (hasKey $legacySharedVolume "mountPaths") (kindIs "slice" (get $legacySharedVolume "mountPaths")) -}} + {{- $legacyMountPaths := get $legacySharedVolume "mountPaths" -}} + {{- if gt (len $legacyMountPaths) 0 -}} + {{- $_ := set $lightspeed.runtimeVolume "mountPath" (first $legacyMountPaths) -}} + {{- end -}} + {{- if gt (len $legacyMountPaths) 1 -}} + {{- $_ := set $lightspeed.ragVolume "mountPath" (index $legacyMountPaths 1) -}} + {{- end -}} + {{- end -}} + {{- if hasKey $legacySharedVolume "initMountPath" -}} + {{- $_ := set $lightspeed.ragVolume "initMountPath" (get $legacySharedVolume "initMountPath") -}} + {{- end -}} + {{- if and (hasKey $legacySharedVolume "ephemeral") (not (empty (get $legacySharedVolume "ephemeral"))) -}} + {{- fail "global.lightspeed.sharedVolume.ephemeral is no longer supported; use global.lightspeed.runtimeVolume.persistentVolumeClaim or global.lightspeed.runtimeVolume.emptyDir instead" -}} + {{- else if hasKey $legacySharedVolume "emptyDir" -}} + {{- $_ := set $lightspeed.runtimeVolume "type" "emptyDir" -}} + {{- $_ := set $lightspeed.runtimeVolume "emptyDir" (get $legacySharedVolume "emptyDir") -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- if $lightspeed.enabled -}} + {{- if or (not (kindIs "map" $lightspeed.initContainer)) (empty $lightspeed.initContainer.name) -}} + {{- fail "global.lightspeed.enabled=true requires the built-in Lightspeed init container configuration" -}} + {{- end -}} + {{- if or (not (kindIs "map" $lightspeed.sidecar)) (empty $lightspeed.sidecar.name) -}} + {{- fail "global.lightspeed.enabled=true requires the built-in Lightspeed sidecar configuration" -}} + {{- end -}} + {{- if or (not (kindIs "map" $lightspeed.runtimeVolume)) (empty $lightspeed.runtimeVolume.name) (empty $lightspeed.runtimeVolume.mountPath) -}} + {{- fail "global.lightspeed.enabled=true requires the built-in Lightspeed runtime volume configuration" -}} + {{- end -}} + {{- if or (not (kindIs "map" $lightspeed.ragVolume)) (empty $lightspeed.ragVolume.name) (empty $lightspeed.ragVolume.mountPath) (empty $lightspeed.ragVolume.initMountPath) -}} + {{- fail "global.lightspeed.enabled=true requires the built-in Lightspeed RAG volume configuration" -}} + {{- end -}} + {{- $_ := include "rhdh.lightspeed.runtimeVolumeType" (dict "volume" $lightspeed.runtimeVolume "path" "global.lightspeed.runtimeVolume") -}} +{{- end -}} +{{- toYaml $lightspeed -}} +{{- end -}} + +{{/* +Return the passed Lightspeed values or compute them from context. +*/}} +{{- define "rhdh.lightspeed.resolve" -}} +{{- $context := .context -}} +{{- $input := .input -}} +{{- if and (kindIs "map" $input) (hasKey $input "lightspeed") -}} +{{- toYaml (get $input "lightspeed") -}} +{{- else -}} +{{- include "rhdh.lightspeed" $context -}} +{{- end -}} +{{- end -}} + +{{/* +Return the relative path for a Lightspeed payload file. +*/}} +{{- define "rhdh.lightspeed.filePath" -}} +{{- printf "files/lightspeed/%s" . -}} +{{- end -}} + +{{/* +Return rendered content of a Lightspeed payload file. +*/}} +{{- define "rhdh.lightspeed.fileContent" -}} +{{- .context.Files.Get (include "rhdh.lightspeed.filePath" .file) -}} +{{- end -}} + +{{/* +Return the stringData map for the Lightspeed Secret. +*/}} +{{- define "rhdh.lightspeed.secretStringData" -}} +{{- $context := . -}} +{{- if and (kindIs "map" .) (hasKey . "context") -}} + {{- $context = get . "context" -}} +{{- end -}} +{{- $lightspeed := include "rhdh.lightspeed.resolve" (dict "context" $context "input" .) | fromYaml -}} +{{- include "rhdh.lightspeed.fileContent" (dict "context" $context "file" $lightspeed.secret.sourceFile) | fromYaml | toYaml -}} +{{- end -}} + +{{/* +Return the Lightspeed ConfigMap payloads for checksum calculation. +*/}} +{{- define "rhdh.lightspeed.configMapsChecksum" -}} +{{- $context := . -}} +{{- if and (kindIs "map" .) (hasKey . "context") -}} + {{- $context = get . "context" -}} +{{- end -}} +{{- $lightspeed := include "rhdh.lightspeed.resolve" (dict "context" $context "input" .) | fromYaml -}} +{{- $configMaps := list -}} +{{- range $lightspeed.configMaps -}} + {{- $configMaps = append $configMaps (dict + "name" .name + "nameOverride" .nameOverride + "mountPath" .mountPath + "subPath" .subPath + "sourceFile" .sourceFile + "optional" .optional + "content" (include "rhdh.lightspeed.fileContent" (dict "context" $context "file" .sourceFile)) + ) -}} +{{- end -}} +{{- toJson $configMaps -}} +{{- end -}} + +{{/* +Return the Lightspeed Secret payload for checksum calculation. +*/}} +{{- define "rhdh.lightspeed.secretChecksum" -}} +{{- $context := . -}} +{{- if and (kindIs "map" .) (hasKey . "context") -}} + {{- $context = get . "context" -}} +{{- end -}} +{{- $lightspeed := include "rhdh.lightspeed.resolve" (dict "context" $context "input" .) | fromYaml -}} +{{- dict + "create" $lightspeed.secret.create + "name" $lightspeed.secret.name + "optional" $lightspeed.secret.optional + "sourceFile" $lightspeed.secret.sourceFile + "stringData" (include "rhdh.lightspeed.secretStringData" (dict "context" $context "lightspeed" $lightspeed) | fromYaml) + | toJson -}} +{{- end -}} + +{{/* +Return the Lightspeed secret name. +*/}} +{{- define "rhdh.lightspeed.secretName" -}} +{{- $context := . -}} +{{- if and (kindIs "map" .) (hasKey . "context") -}} + {{- $context = get . "context" -}} +{{- end -}} +{{- $lightspeed := include "rhdh.lightspeed.resolve" (dict "context" $context "input" .) | fromYaml -}} +{{- if $lightspeed.secret.name -}} + {{- $lightspeed.secret.name -}} +{{- else if $lightspeed.secret.create -}} + {{- printf "%s-lightspeed-secret" $context.Release.Name -}} +{{- else -}} + {{- fail "global.lightspeed.secret.name must be set when global.lightspeed.secret.create=false" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the Lightspeed ConfigMap name. +*/}} +{{- define "rhdh.lightspeed.configMapName" -}} +{{- $root := .root -}} +{{- $configMap := .configMap -}} + {{- if $configMap.nameOverride -}} + {{- $configMap.nameOverride -}} + {{- else -}} + {{- printf "%s-lightspeed-%s" $root.Release.Name $configMap.name | trunc 63 | trimSuffix "-" -}} + {{- end -}} +{{- end -}} + +{{/* +Return the Lightspeed ConfigMap volume name. +*/}} +{{- define "rhdh.lightspeed.configMapVolumeName" -}} +{{- printf "lightspeed-config-%s" .name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + {{/* DEPRECATED: The following templates are deprecated. Please use the corresponding "rhdh.*" templates instead. */}} diff --git a/charts/backstage/templates/dynamic-plugins-configmap.yaml b/charts/backstage/templates/dynamic-plugins-configmap.yaml index 321fd177..613545f7 100644 --- a/charts/backstage/templates/dynamic-plugins-configmap.yaml +++ b/charts/backstage/templates/dynamic-plugins-configmap.yaml @@ -4,6 +4,7 @@ metadata: name: {{ printf "%s-dynamic-plugins" .Release.Name }} data: dynamic-plugins.yaml: | + {{- $lightspeed := include "rhdh.lightspeed" . | fromYaml }} {{- $dynamic := deepCopy .Values.global.dynamic }} {{- $plugins := list }} @@ -17,6 +18,12 @@ data: {{- end }} {{- end }} + {{- if $lightspeed.enabled }} + {{- range $lightspeed.plugins }} + {{- $plugins = append $plugins . }} + {{- end }} + {{- end }} + {{- $_ := set $dynamic "plugins" $plugins }} {{- include "common.tplvalues.render" (dict "value" $dynamic "context" $) | nindent 4 }} diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 34bdbbf6..081621ef 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -116,6 +116,374 @@ "default": "", "title": "Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`", "type": "string" + }, + "lightspeed": { + "additionalProperties": false, + "default": { + "enabled": true, + "images": { + "lightspeedCore": "quay.io/lightspeed-core/lightspeed-stack:0.5.0", + "ragInit": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05" + }, + "plugins": [ + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed", + "pluginConfig": { + "dynamicPlugins": { + "frontend": { + "red-hat-developer-hub.backstage-plugin-lightspeed": { + "dynamicRoutes": [ + { + "importName": "LightspeedPage", + "path": "/lightspeed" + } + ], + "mountPoints": [ + { + "importName": "LightspeedFAB", + "mountPoint": "application/listener" + }, + { + "importName": "LightspeedDrawerProvider", + "mountPoint": "application/provider" + }, + { + "config": { + "id": "lightspeed" + }, + "importName": "LightspeedDrawerStateExposer", + "mountPoint": "application/internal/drawer-state" + }, + { + "config": { + "id": "lightspeed", + "priority": 100 + }, + "importName": "LightspeedChatContainer", + "mountPoint": "application/internal/drawer-content" + } + ], + "translationResources": [ + { + "importName": "lightspeedTranslations", + "module": "Alpha", + "ref": "lightspeedTranslationRef" + } + ] + } + } + } + } + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" + } + ], + "resources": { + "lightspeedCore": {}, + "ragInit": {} + }, + "runtimeVolume": { + "emptyDir": {}, + "persistentVolumeClaim": {}, + "type": "emptyDir" + } + }, + "properties": { + "enabled": { + "default": true, + "title": "Enable or disable the built-in Lightspeed feature.", + "type": "boolean" + }, + "images": { + "additionalProperties": false, + "properties": { + "lightspeedCore": { + "default": "quay.io/lightspeed-core/lightspeed-stack:0.5.0", + "title": "Full image reference for the Lightspeed Core sidecar. Override for disconnected environments.", + "type": "string" + }, + "ragInit": { + "default": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05", + "title": "Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments.", + "type": "string" + } + }, + "title": "Images used by the Lightspeed pod wiring.", + "type": "object" + }, + "plugins": { + "default": [ + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed", + "pluginConfig": { + "dynamicPlugins": { + "frontend": { + "red-hat-developer-hub.backstage-plugin-lightspeed": { + "dynamicRoutes": [ + { + "importName": "LightspeedPage", + "path": "/lightspeed" + } + ], + "mountPoints": [ + { + "importName": "LightspeedFAB", + "mountPoint": "application/listener" + }, + { + "importName": "LightspeedDrawerProvider", + "mountPoint": "application/provider" + }, + { + "config": { + "id": "lightspeed" + }, + "importName": "LightspeedDrawerStateExposer", + "mountPoint": "application/internal/drawer-state" + }, + { + "config": { + "id": "lightspeed", + "priority": 100 + }, + "importName": "LightspeedChatContainer", + "mountPoint": "application/internal/drawer-content" + } + ], + "translationResources": [ + { + "importName": "lightspeedTranslations", + "module": "Alpha", + "ref": "lightspeedTranslationRef" + } + ] + } + } + } + } + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" + } + ], + "items": { + "properties": { + "disabled": { + "default": false, + "title": "Disable the plugin.", + "type": "boolean" + }, + "integrity": { + "title": "Integrity checksum of the package. Optional for local packages and OCI packages. For OCI packages, you can specify the image digest in place of the tag in the 'package' field. Supported algorithms include: `sha512`, `sha384` and `sha256`. Refer to https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description for more information", + "type": "string" + }, + "package": { + "title": "Package specification of the dynamic plugin to install. It should be usable by the `npm pack` command (for NPM packages) or the `skopeo copy` command (for OCI packages).", + "type": "string" + }, + "pluginConfig": { + "title": "Optional plugin-specific app-config YAML fragment.", + "type": "object" + } + }, + "required": [ + "package" + ], + "type": "object" + }, + "title": "Lightspeed plugins and their configuration. Override package references for disconnected environments.", + "type": "array" + }, + "resources": { + "additionalProperties": false, + "properties": { + "lightspeedCore": { + "description": "ResourceRequirements describes the compute resource requirements.", + "properties": { + "claims": { + "description": "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.", + "items": { + "description": "ResourceClaim references one entry in PodSpec.ResourceClaims.", + "properties": { + "name": { + "description": "Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.", + "type": "string" + }, + "request": { + "description": "Request is the name chosen for a request in the referenced claim. If empty, everything from the claim is made available, otherwise only the result of this request.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, + "limits": { + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", + "type": "object" + }, + "requests": { + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", + "type": "object" + } + }, + "type": "object" + }, + "ragInit": { + "description": "ResourceRequirements describes the compute resource requirements.", + "properties": { + "claims": { + "description": "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.", + "items": { + "description": "ResourceClaim references one entry in PodSpec.ResourceClaims.", + "properties": { + "name": { + "description": "Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.", + "type": "string" + }, + "request": { + "description": "Request is the name chosen for a request in the referenced claim. If empty, everything from the claim is made available, otherwise only the result of this request.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "type": "array", + "x-kubernetes-list-map-keys": [ + "name" + ], + "x-kubernetes-list-type": "map" + }, + "limits": { + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", + "type": "object" + }, + "requests": { + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", + "type": "object" + } + }, + "type": "object" + } + }, + "title": "Resource requests/limits for Lightspeed containers.", + "type": "object" + }, + "runtimeVolume": { + "additionalProperties": false, + "properties": { + "emptyDir": { + "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", + "properties": { + "medium": { + "description": "medium represents what type of storage medium should back this directory. The default is \"\" which means to use the node's default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir", + "type": "string" + }, + "sizeLimit": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "type": "object" + }, + "persistentVolumeClaim": { + "additionalProperties": false, + "default": {}, + "properties": { + "claimName": { + "default": "", + "title": "Name of the existing PVC to mount for Lightspeed runtime data.", + "type": "string" + }, + "readOnly": { + "default": false, + "title": "Whether the existing PVC should be mounted read-only.", + "type": "boolean" + } + }, + "title": "Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`.", + "type": "object" + }, + "type": { + "default": "emptyDir", + "enum": [ + "emptyDir", + "persistentVolumeClaim" + ], + "title": "Volume source used for writable Lightspeed runtime storage mounted at `/tmp`.", + "type": "string" + } + }, + "title": "Runtime data volume configuration for the Lightspeed Core sidecar.", + "type": "object" + } + }, + "title": "Built-in Lightspeed feature configuration.", + "type": [ + "boolean", + "object" + ] } }, "type": "object" @@ -6143,7 +6511,7 @@ "type": "string" }, "default": { - "checksum/dynamic-plugins": "{{- include \"common.tplvalues.render\" ( dict \"value\" .Values.global.dynamic \"context\" $) | sha256sum }}" + "checksum/dynamic-plugins": "{{- $lightspeed := include \"rhdh.lightspeed\" . | fromYaml -}} {{- include \"common.tplvalues.render\" ( dict \"value\" (dict \"dynamic\" .Values.global.dynamic \"lightspeed\" (dict \"enabled\" $lightspeed.enabled \"plugins\" $lightspeed.plugins)) \"context\" $) | sha256sum }}" }, "title": "Annotations to add to the backend deployment pods", "type": "object" diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index 1806313c..eaa965a9 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -132,6 +132,125 @@ } } } + }, + "lightspeed": { + "title": "Built-in Lightspeed feature configuration.", + "type": [ + "boolean", + "object" + ], + "default": {}, + "additionalProperties": false, + "properties": { + "enabled": { + "title": "Enable or disable the built-in Lightspeed feature.", + "type": "boolean", + "default": true + }, + "plugins": { + "title": "Lightspeed plugins and their configuration. Override package references for disconnected environments.", + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "package": { + "title": "Package specification of the dynamic plugin to install. It should be usable by the `npm pack` command (for NPM packages) or the `skopeo copy` command (for OCI packages).", + "type": "string" + }, + "integrity": { + "title": "Integrity checksum of the package. Optional for local packages and OCI packages. For OCI packages, you can specify the image digest in place of the tag in the 'package' field. Supported algorithms include: `sha512`, `sha384` and `sha256`. Refer to https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description for more information", + "type": "string" + }, + "pluginConfig": { + "title": "Optional plugin-specific app-config YAML fragment.", + "type": "object" + }, + "disabled": { + "title": "Disable the plugin.", + "type": "boolean", + "default": false + } + }, + "required": [ + "package" + ] + } + }, + "images": { + "title": "Images used by the Lightspeed pod wiring.", + "type": "object", + "additionalProperties": false, + "properties": { + "ragInit": { + "title": "Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments.", + "type": "string", + "default": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05" + }, + "lightspeedCore": { + "title": "Full image reference for the Lightspeed Core sidecar. Override for disconnected environments.", + "type": "string", + "default": "quay.io/lightspeed-core/lightspeed-stack:0.5.0" + } + } + }, + "resources": { + "title": "Resource requests/limits for Lightspeed containers.", + "type": "object", + "additionalProperties": false, + "properties": { + "ragInit": { + "title": "Resource requests/limits for the Lightspeed RAG bootstrap init container.", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", + "default": {} + }, + "lightspeedCore": { + "title": "Resource requests/limits for the Lightspeed Core sidecar.", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", + "default": {} + } + } + }, + "runtimeVolume": { + "title": "Runtime data volume configuration for the Lightspeed Core sidecar.", + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "title": "Volume source used for writable Lightspeed runtime storage mounted at `/tmp`.", + "type": "string", + "default": "emptyDir", + "enum": [ + "emptyDir", + "persistentVolumeClaim" + ] + }, + "emptyDir": { + "title": "`emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`.", + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.EmptyDirVolumeSource", + "default": {} + }, + "persistentVolumeClaim": { + "title": "Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`.", + "type": "object", + "additionalProperties": false, + "properties": { + "claimName": { + "title": "Name of the existing PVC to mount for Lightspeed runtime data.", + "type": "string", + "default": "" + }, + "readOnly": { + "title": "Whether the existing PVC should be mounted read-only.", + "type": "boolean", + "default": false + } + }, + "default": {} + } + } + } + } } } }, diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index cd3c293e..53fbb809 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -35,6 +35,59 @@ global: registry: quay.io repository: rhdh/plugin-catalog-index tag: "1.10" + # -- Built-in Lightspeed feature configuration. + lightspeed: + # -- Enable or disable the built-in Lightspeed feature. + enabled: true + # -- Lightspeed plugins and their configuration. Override package references for disconnected environments. + plugins: + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-lightspeed: + translationResources: + - importName: lightspeedTranslations + module: Alpha + ref: lightspeedTranslationRef + dynamicRoutes: + - path: /lightspeed + importName: LightspeedPage + mountPoints: + - mountPoint: application/listener + importName: LightspeedFAB + - mountPoint: application/provider + importName: LightspeedDrawerProvider + - mountPoint: application/internal/drawer-state + importName: LightspeedDrawerStateExposer + config: + id: lightspeed + - mountPoint: application/internal/drawer-content + importName: LightspeedChatContainer + config: + id: lightspeed + priority: 100 + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend + disabled: false + images: + # -- Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. + ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 + # -- Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. + lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 + resources: + # -- Resource requests/limits for the Lightspeed RAG bootstrap init container. + ragInit: {} + # -- Resource requests/limits for the Lightspeed Core sidecar. + lightspeedCore: {} + runtimeVolume: + # -- Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. + # Supported values: `emptyDir`, `persistentVolumeClaim`. + type: emptyDir + # -- `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. + emptyDir: {} + # -- Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. + persistentVolumeClaim: {} # -- Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) # @default -- Use Openshift compatible settings upstream: @@ -253,7 +306,8 @@ upstream: installDir: /opt/app-root/src podAnnotations: checksum/dynamic-plugins: >- - {{- include "common.tplvalues.render" ( dict "value" .Values.global.dynamic "context" $) | sha256sum }} + {{- $lightspeed := include "rhdh.lightspeed" . | fromYaml -}} + {{- include "common.tplvalues.render" ( dict "value" (dict "dynamic" .Values.global.dynamic "lightspeed" (dict "enabled" $lightspeed.enabled "plugins" $lightspeed.plugins)) "context" $) | sha256sum }} ingress: host: "{{ .Values.global.host }}" metrics: diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml index bcdcd73a..7051afeb 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml @@ -1,6 +1,11 @@ {{- $imageRepository := .Values.backstage.image.repository | required "The repository name of the image is required (e.g. my-backstage:tag | docker.io/my-backstage:tag) !" -}} {{- $imageTag := .Values.backstage.image.tag | required "The image tag is required (e.g my-backstage:tag | docker.io/my-backstage:tag) !" -}} {{- $installDir := .Values.backstage.installDir -}} +{{- $lightspeed := include "rhdh.lightspeed" . | fromYaml -}} +{{- $lightspeedRuntimeVolumeType := "" -}} +{{- if $lightspeed.enabled -}} +{{- $lightspeedRuntimeVolumeType = include "rhdh.lightspeed.runtimeVolumeType" (dict "volume" $lightspeed.runtimeVolume "path" "global.lightspeed.runtimeVolume") -}} +{{- end -}} --- apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} kind: Deployment @@ -36,6 +41,10 @@ spec: {{- end }} annotations: checksum/app-config: {{ include "common.tplvalues.render" ( dict "value" .Values.backstage.appConfig "context" $) | sha256sum }} + {{- if $lightspeed.enabled }} + checksum/lightspeed-configmaps: {{ include "rhdh.lightspeed.configMapsChecksum" (dict "context" $ "lightspeed" $lightspeed) | sha256sum }} + checksum/lightspeed-secret: {{ include "rhdh.lightspeed.secretChecksum" (dict "context" $ "lightspeed" $lightspeed) | sha256sum }} + {{- end }} {{- if .Values.backstage.podAnnotations }} {{- include "common.tplvalues.render" ( dict "value" .Values.backstage.podAnnotations "context" $ ) | nindent 8 }} {{- end }} @@ -81,10 +90,57 @@ spec: configMap: name: {{ include "common.names.fullname" . }}-app-config {{- end }} + {{- if $lightspeed.enabled }} + - name: {{ $lightspeed.runtimeVolume.name }} + {{- if eq $lightspeedRuntimeVolumeType "persistentVolumeClaim" }} + persistentVolumeClaim: + {{- include "common.tplvalues.render" ( dict "value" $lightspeed.runtimeVolume.persistentVolumeClaim "context" $ ) | nindent 12 }} + {{- else }} + emptyDir: + {{- include "common.tplvalues.render" ( dict "value" $lightspeed.runtimeVolume.emptyDir "context" $ ) | nindent 12 }} + {{- end }} + - name: {{ $lightspeed.ragVolume.name }} + emptyDir: + {{- include "common.tplvalues.render" ( dict "value" $lightspeed.ragVolume.emptyDir "context" $ ) | nindent 12 }} + {{- range $lightspeed.configMaps }} + - name: {{ include "rhdh.lightspeed.configMapVolumeName" . }} + configMap: + name: {{ include "rhdh.lightspeed.configMapName" (dict "root" $ "configMap" .) }} + optional: {{ default false .optional }} + {{- end }} + {{- end }} {{- include "backstage.renderImagePullSecrets" . | nindent 6 }} - {{- if .Values.backstage.initContainers }} + {{- if or .Values.backstage.initContainers $lightspeed.enabled }} initContainers: + {{- if .Values.backstage.initContainers }} {{- include "common.tplvalues.render" ( dict "value" .Values.backstage.initContainers "context" $) | nindent 8 }} + {{- end }} + {{- if $lightspeed.enabled }} + - name: {{ $lightspeed.initContainer.name }} + image: {{ include "rhdh.lightspeed.image" (dict "image" $lightspeed.images.ragInit "context" $) }} + imagePullPolicy: {{ $lightspeed.initContainer.imagePullPolicy | quote }} + {{- if $lightspeed.initContainer.securityContext }} + securityContext: + {{- include "common.tplvalues.render" (dict "value" $lightspeed.initContainer.securityContext "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.initContainer.command }} + command: {{- include "common.tplvalues.render" (dict "value" $lightspeed.initContainer.command "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.initContainer.args }} + args: {{- include "common.tplvalues.render" (dict "value" $lightspeed.initContainer.args "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.initContainer.env }} + env: {{- include "common.tplvalues.render" (dict "value" $lightspeed.initContainer.env "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.initContainer.resources }} + resources: {{- include "common.tplvalues.render" (dict "value" $lightspeed.initContainer.resources "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ $lightspeed.runtimeVolume.name }} + mountPath: {{ $lightspeed.runtimeVolume.mountPath | quote }} + - name: {{ $lightspeed.ragVolume.name }} + mountPath: {{ $lightspeed.ragVolume.initMountPath | quote }} + {{- end }} {{- end }} containers: - name: backstage-backend @@ -183,6 +239,48 @@ spec: {{- include "common.tplvalues.render" ( dict "value" .Values.backstage.extraVolumeMounts "context" $ ) | nindent 12 }} {{- end }} {{- end }} + {{- if $lightspeed.enabled }} + - name: {{ $lightspeed.sidecar.name }} + image: {{ include "rhdh.lightspeed.image" (dict "image" $lightspeed.images.lightspeedCore "context" $) }} + imagePullPolicy: {{ $lightspeed.sidecar.imagePullPolicy | quote }} + {{- if $lightspeed.sidecar.securityContext }} + securityContext: + {{- include "common.tplvalues.render" (dict "value" $lightspeed.sidecar.securityContext "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.sidecar.command }} + command: {{- include "common.tplvalues.render" (dict "value" $lightspeed.sidecar.command "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.sidecar.args }} + args: {{- include "common.tplvalues.render" (dict "value" $lightspeed.sidecar.args "context" $) | nindent 12 }} + {{- end }} + ports: + - name: {{ $lightspeed.sidecar.portName }} + containerPort: {{ $lightspeed.sidecar.containerPort }} + protocol: TCP + envFrom: + - secretRef: + name: {{ include "rhdh.lightspeed.secretName" (dict "context" $ "lightspeed" $lightspeed) }} + optional: {{ default false $lightspeed.secret.optional }} + {{- if $lightspeed.sidecar.env }} + env: {{- include "common.tplvalues.render" (dict "value" $lightspeed.sidecar.env "context" $) | nindent 12 }} + {{- end }} + {{- if $lightspeed.sidecar.resources }} + resources: {{- include "common.tplvalues.render" (dict "value" $lightspeed.sidecar.resources "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ $lightspeed.runtimeVolume.name }} + mountPath: {{ $lightspeed.runtimeVolume.mountPath | quote }} + - name: {{ $lightspeed.ragVolume.name }} + mountPath: {{ $lightspeed.ragVolume.mountPath | quote }} + {{- range $lightspeed.configMaps }} + - name: {{ include "rhdh.lightspeed.configMapVolumeName" . }} + mountPath: {{ .mountPath | quote }} + {{- if .subPath }} + subPath: {{ .subPath | quote }} + {{- end }} + readOnly: true + {{- end }} + {{- end }} {{- if .Values.backstage.extraContainers }} {{- include "common.tplvalues.render" ( dict "value" .Values.backstage.extraContainers "context" $) | nindent 8 }} {{- end }} diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml new file mode 100644 index 00000000..0c218d2b --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml @@ -0,0 +1,16 @@ +{{- $lightspeed := include "rhdh.lightspeed" . | fromYaml -}} +{{- if and $lightspeed.enabled $lightspeed.configMaps }} +{{- range $index, $configMap := $lightspeed.configMaps }} +{{- if gt $index 0 }} +--- +{{- end }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "rhdh.lightspeed.configMapName" (dict "root" $ "configMap" $configMap) }} + namespace: {{ $.Release.Namespace | quote }} +data: + {{ $configMap.subPath }}: | +{{ include "rhdh.lightspeed.fileContent" (dict "context" $ "file" $configMap.sourceFile) | nindent 4 }} +{{- end }} +{{- end }} diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-secret.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-secret.yaml new file mode 100644 index 00000000..47a3bb83 --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-secret.yaml @@ -0,0 +1,15 @@ +{{- $lightspeed := include "rhdh.lightspeed" . | fromYaml -}} +{{- if and $lightspeed.enabled $lightspeed.secret.create }} +{{- $stringData := include "rhdh.lightspeed.secretStringData" (dict "context" . "lightspeed" $lightspeed) | fromYaml -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "rhdh.lightspeed.secretName" (dict "context" . "lightspeed" $lightspeed) }} + namespace: {{ .Release.Namespace | quote }} +type: Opaque +stringData: +{{- range $key, $value := $stringData }} + {{ $key }}: |- +{{ $value | nindent 4 }} +{{- end }} +{{- end }} From f1c00d32819857515b6b1ecac8c20564ccf4a774 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Thu, 9 Apr 2026 15:48:17 -0400 Subject: [PATCH 04/30] documentation updates for lightspeed Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 22 ++++++++++++++++++++++ charts/backstage/README.md.gotmpl | 12 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index c01838d9..82e2ff61 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,6 +174,16 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"resources":{"lightspeedCore":{},"ragInit":{}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | +| global.lightspeed.images.lightspeedCore | Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. | string | `"quay.io/lightspeed-core/lightspeed-stack:0.5.0"` | +| global.lightspeed.images.ragInit | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | +| global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}]` | +| global.lightspeed.resources.lightspeedCore | Resource requests/limits for the Lightspeed Core sidecar. | object | `{}` | +| global.lightspeed.resources.ragInit | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{}` | +| global.lightspeed.runtimeVolume.emptyDir | `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. | object | `{}` | +| global.lightspeed.runtimeVolume.persistentVolumeClaim | Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. | object | `{}` | +| global.lightspeed.runtimeVolume.type | Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. Supported values: `emptyDir`, `persistentVolumeClaim`. | string | `"emptyDir"` | | nameOverride | | string | `"developer-hub"` | | orchestrator.enabled | | bool | `false` | | orchestrator.plugins | Orchestrator plugins and their configuration | list | `[{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{ \"{{inherit}}\" }}"},{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{ \"{{inherit}}\" }}"},{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{ \"{{inherit}}\" }}"},{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{ \"{{inherit}}\" }}"}]` | @@ -304,6 +314,18 @@ The chart supports automatic plugin discovery through a catalog index OCI image. For detailed information on configuring the catalog index, including how to override the default image or use a private registry, see the [Catalog Index Configuration documentation](../../docs/catalog-index-configuration.md). +### Lightspeed + +Use `global.lightspeed.enabled` to enable or disable the built-in Lightspeed feature. + +When enabled, the chart adds the default Lightspeed dynamic plugins, a RAG bootstrap init container, a Lightspeed Core sidecar listening on port `8080`, chart-generated ConfigMaps, a chart-generated Secret, and separate runtime and RAG data volumes. Override `global.lightspeed.plugins` or the `global.lightspeed.images.ragInit` and `global.lightspeed.images.lightspeedCore` full image references for disconnected environments. + +Use `global.lightspeed.resources` to set resource requests and limits for the Lightspeed init container and sidecar. Use `global.lightspeed.runtimeVolume` to change the writable `/tmp` runtime storage between `emptyDir` and an existing PVC reference. The chart mounts that volume at `/tmp` so both generated temp files and `/tmp/data` remain writable. The `/rag-content` volume stays chart-managed and `emptyDir`-backed because the RAG assets are repopulated by the init container on each Pod start. + +When using the built-in Lightspeed feature, do not also keep Lightspeed plugin packages in `global.dynamic.plugins`. Existing installations that previously configured Lightspeed there should remove those entries if the built-in defaults are sufficient, or move their custom package definitions to `global.lightspeed.plugins`; otherwise the rendered `dynamic-plugins.yaml` will contain duplicate Lightspeed plugin entries. + +The Lightspeed Core sidecar loads the chart-created Lightspeed Secret as environment variables. If you update that Secret outside of Helm, Kubernetes does not guarantee that the Backstage Pod restarts automatically. Use a no-op `helm upgrade` or manually restart the Backstage deployment after changing the secret data. + ### Vanilla Kubernetes compatibility mode To deploy this chart on vanilla Kubernetes or any other non-OCP platform, apply the following changes. Note that further customizations might be required, depending on your exact Kubernetes setup: diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index e82f7acb..ad5b0597 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -236,6 +236,18 @@ The chart supports automatic plugin discovery through a catalog index OCI image. For detailed information on configuring the catalog index, including how to override the default image or use a private registry, see the [Catalog Index Configuration documentation](../../docs/catalog-index-configuration.md). +### Lightspeed + +Use `global.lightspeed.enabled` to enable or disable the built-in Lightspeed feature. + +When enabled, the chart adds the default Lightspeed dynamic plugins, a RAG bootstrap init container, a Lightspeed Core sidecar listening on port `8080`, chart-generated ConfigMaps, a chart-generated Secret, and separate runtime and RAG data volumes. Override `global.lightspeed.plugins` or the `global.lightspeed.images.ragInit` and `global.lightspeed.images.lightspeedCore` full image references for disconnected environments. + +Use `global.lightspeed.resources` to set resource requests and limits for the Lightspeed init container and sidecar. Use `global.lightspeed.runtimeVolume` to change the writable `/tmp` runtime storage between `emptyDir` and an existing PVC reference. The chart mounts that volume at `/tmp` so both generated temp files and `/tmp/data` remain writable. The `/rag-content` volume stays chart-managed and `emptyDir`-backed because the RAG assets are repopulated by the init container on each Pod start. + +When using the built-in Lightspeed feature, do not also keep Lightspeed plugin packages in `global.dynamic.plugins`. Existing installations that previously configured Lightspeed there should remove those entries if the built-in defaults are sufficient, or move their custom package definitions to `global.lightspeed.plugins`; otherwise the rendered `dynamic-plugins.yaml` will contain duplicate Lightspeed plugin entries. + +The Lightspeed Core sidecar loads the chart-created Lightspeed Secret as environment variables. If you update that Secret outside of Helm, Kubernetes does not guarantee that the Backstage Pod restarts automatically. Use a no-op `helm upgrade` or manually restart the Backstage deployment after changing the secret data. + ### Vanilla Kubernetes compatibility mode To deploy this chart on vanilla Kubernetes or any other non-OCP platform, apply the following changes. Note that further customizations might be required, depending on your exact Kubernetes setup: From bb065cd475094605a33a7b94b07767a2a999462a Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Thu, 9 Apr 2026 15:48:45 -0400 Subject: [PATCH 05/30] add ci case for lightspeed Signed-off-by: Jordan Dubrick --- .../ci/with-lightspeed-disabled-values.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 charts/backstage/ci/with-lightspeed-disabled-values.yaml diff --git a/charts/backstage/ci/with-lightspeed-disabled-values.yaml b/charts/backstage/ci/with-lightspeed-disabled-values.yaml new file mode 100644 index 00000000..d12c21e2 --- /dev/null +++ b/charts/backstage/ci/with-lightspeed-disabled-values.yaml @@ -0,0 +1,13 @@ +# Workaround for kind cluster in CI which has no Routes and no PVCs +route: + enabled: false + +global: + lightspeed: + enabled: false + +upstream: + postgresql: + primary: + persistence: + enabled: false From 3966154b209f7176a2bf0192d2837a1ce8e9edf5 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Thu, 9 Apr 2026 16:00:24 -0400 Subject: [PATCH 06/30] bump chart version Signed-off-by: Jordan Dubrick --- charts/backstage/Chart.yaml | 2 +- charts/backstage/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/backstage/Chart.yaml b/charts/backstage/Chart.yaml index e97d0f4e..e8103702 100644 --- a/charts/backstage/Chart.yaml +++ b/charts/backstage/Chart.yaml @@ -47,4 +47,4 @@ sources: [] # Versions are expected to follow Semantic Versioning (https://semver.org/) # Note that when this chart is published to https://github.com/openshift-helm-charts/charts # it will follow the RHDH versioning 1.y.z -version: 5.7.1 +version: 5.8.0 diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 82e2ff61..bd5c292d 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -1,7 +1,7 @@ # RHDH Backstage Helm Chart for OpenShift -![Version: 5.7.1](https://img.shields.io/badge/Version-5.7.1-informational?style=flat-square) +![Version: 5.8.0](https://img.shields.io/badge/Version-5.8.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) A Helm chart for deploying Red Hat Developer Hub, which is a Red Hat supported version of Backstage. @@ -29,7 +29,7 @@ For the **Generally Available** version of this chart, see: helm repo add bitnami https://charts.bitnami.com/bitnami helm repo add redhat-developer https://redhat-developer.github.io/rhdh-chart -helm install my-backstage redhat-developer/backstage --version 5.7.1 +helm install my-backstage redhat-developer/backstage --version 5.8.0 ``` ## Introduction From 275df9583f04268209327e1533003c856a112a81 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Fri, 10 Apr 2026 09:32:35 -0400 Subject: [PATCH 07/30] add mcp plugins for lightspeed Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 4 ++-- charts/backstage/templates/_helpers.tpl | 6 ++++++ charts/backstage/values.schema.json | 24 ++++++++++++++++++++++++ charts/backstage/values.yaml | 6 ++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index bd5c292d..e9f96314 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,11 +174,11 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"resources":{"lightspeedCore":{},"ragInit":{}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}],"resources":{"lightspeedCore":{},"ragInit":{}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | | global.lightspeed.images.lightspeedCore | Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. | string | `"quay.io/lightspeed-core/lightspeed-stack:0.5.0"` | | global.lightspeed.images.ragInit | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | -| global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}]` | +| global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}]` | | global.lightspeed.resources.lightspeedCore | Resource requests/limits for the Lightspeed Core sidecar. | object | `{}` | | global.lightspeed.resources.ragInit | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{}` | | global.lightspeed.runtimeVolume.emptyDir | `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. | object | `{}` | diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index 245e7570..461dada1 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -92,6 +92,12 @@ plugins: priority: 100 - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2 + disabled: false images: ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 081621ef..191603c0 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -179,6 +179,18 @@ { "disabled": false, "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5" + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1" + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2" } ], "resources": { @@ -269,6 +281,18 @@ { "disabled": false, "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5" + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1" + }, + { + "disabled": false, + "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2" } ], "items": { diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 53fbb809..0c4f70ea 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -70,6 +70,12 @@ global: priority: 100 - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2 + disabled: false images: # -- Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 From 72b697977aaa9321e1e1b35a0da1c7602b77fff7 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Fri, 10 Apr 2026 13:02:27 -0400 Subject: [PATCH 08/30] add secret syncing for lightspeed Signed-off-by: Jordan Dubrick --- CONTRIBUTING.md | 3 +- .../backstage/files/lightspeed/secret.yaml | 13 +++-- hack/sync-lightspeed-configs.sh | 57 ++++++++++++++++--- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ffee618..022b90fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,8 @@ Verify the vendored files are already in sync without writing changes: ./hack/sync-lightspeed-configs.sh --ref main --check ``` -The script copies the upstream files as-is, so choose the upstream branch or tag that matches the Lightspeed release you want to vendor. +The script copies the upstream config files directly, except it renders `secret.yaml` from upstream `env/default-values.env` by dropping comment lines plus `LIGHTSPEED_CORE_IMAGE` and `RAG_CONTENT_IMAGE`, then converting each remaining `KEY=value` line into the chart's YAML secret payload. +Choose the upstream branch or tag that matches the Lightspeed release you want to vendor. **Important:** After any change to the dependency structure or version of the vendored chart, you must rebuild the lock file and local subchart dependencies: diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml index c620cb07..b9817898 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml @@ -1,16 +1,17 @@ -# Placeholder values for the built-in Lightspeed config. ENABLE_VLLM: "" +ENABLE_VERTEX_AI: "" +ENABLE_OPENAI: "" +ENABLE_OLLAMA: "" +ENABLE_VALIDATION: "" VLLM_URL: "" VLLM_API_KEY: "" VLLM_MAX_TOKENS: "" VLLM_TLS_VERIFY: "" -ENABLE_OLLAMA: "" -OLLAMA_URL: "" -ENABLE_OPENAI: "" OPENAI_API_KEY: "" -ENABLE_VERTEX_AI: "" VERTEX_AI_PROJECT: "" VERTEX_AI_LOCATION: "" -ENABLE_VALIDATION: "" +GOOGLE_APPLICATION_CREDENTIALS: "" +OLLAMA_URL: "" VALIDATION_PROVIDER: "" VALIDATION_MODEL_NAME: "" +LLAMA_STACK_LOGGING: "" diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh index c8237787..6eae8a00 100755 --- a/hack/sync-lightspeed-configs.sh +++ b/hack/sync-lightspeed-configs.sh @@ -9,12 +9,50 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" LIGHTSPEED_DIR="${REPO_ROOT}/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed" +# Format: upstream_path|destination_path|transform_function TARGETS=( - "lightspeed-core-configs/lightspeed-stack.yaml:${LIGHTSPEED_DIR}/lightspeed-stack.yaml" - "llama-stack-configs/config.yaml:${LIGHTSPEED_DIR}/config.yaml" - "lightspeed-core-configs/rhdh-profile.py:${LIGHTSPEED_DIR}/rhdh-profile.py" + "lightspeed-core-configs/lightspeed-stack.yaml|${LIGHTSPEED_DIR}/lightspeed-stack.yaml|copy_fetched_file" + "llama-stack-configs/config.yaml|${LIGHTSPEED_DIR}/config.yaml|copy_fetched_file" + "lightspeed-core-configs/rhdh-profile.py|${LIGHTSPEED_DIR}/rhdh-profile.py|copy_fetched_file" + "env/default-values.env|${LIGHTSPEED_DIR}/secret.yaml|render_secret_yaml_from_env" ) +copy_fetched_file() { + local source_file=$1 + local destination_file=$2 + + cp "${source_file}" "${destination_file}" +} + +render_secret_yaml_from_env() { + local source_file=$1 + local destination_file=$2 + + awk ' + /^[[:space:]]*$/ { next } + # Skip comments from the upstream .env file. + /^[[:space:]]*#/ { next } + { + separator = index($0, "=") + if (separator == 0) { + printf "error: unsupported env line: %s\n", $0 > "/dev/stderr" + exit 1 + } + + key = substr($0, 1, separator - 1) + # These image settings are intentionally not part of the chart-managed secret payload. + if (key == "LIGHTSPEED_CORE_IMAGE" || key == "RAG_CONTENT_IMAGE") { + next + } + + value = substr($0, separator + 1) + gsub(/\\/, "\\\\", value) + gsub(/"/, "\\\"", value) + printf "%s: \"%s\"\n", key, value + } + ' "${source_file}" > "${destination_file}" +} + usage() { cat < Date: Fri, 10 Apr 2026 13:05:34 -0400 Subject: [PATCH 09/30] replace [ with [[ for sonarcloud check Signed-off-by: Jordan Dubrick --- hack/sync-lightspeed-configs.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh index 6eae8a00..4daab427 100755 --- a/hack/sync-lightspeed-configs.sh +++ b/hack/sync-lightspeed-configs.sh @@ -82,7 +82,7 @@ print_diff() { local fetched_file=$2 local relative_path=$3 - if [ -f "${existing_file}" ]; then + if [[ -f "${existing_file}" ]]; then diff -u \ --label "${relative_path}" \ --label "${relative_path}" \ @@ -99,10 +99,10 @@ repo="${DEFAULT_REPO}" ref="${DEFAULT_REF}" check_only=false -while [ $# -gt 0 ]; do +while [[ $# -gt 0 ]]; do case "$1" in --repo) - if [ $# -lt 2 ]; then + if [[ $# -lt 2 ]]; then echo "error: --repo requires a value" >&2 usage exit 1 @@ -111,7 +111,7 @@ while [ $# -gt 0 ]; do shift 2 ;; --ref) - if [ $# -lt 2 ]; then + if [[ $# -lt 2 ]]; then echo "error: --ref requires a value" >&2 usage exit 1 @@ -153,12 +153,12 @@ for target in "${TARGETS[@]}"; do fetch_file "${upstream_url}" "${fetched_file}" "${transform_function}" "${fetched_file}" "${rendered_file}" - if [ -f "${destination_path}" ] && cmp -s "${destination_path}" "${rendered_file}"; then + if [[ -f "${destination_path}" ]] && cmp -s "${destination_path}" "${rendered_file}"; then echo "up to date: ${relative_destination}" continue fi - if [ "${check_only}" = true ]; then + if [[ "${check_only}" == true ]]; then print_diff "${destination_path}" "${rendered_file}" "${relative_destination}" else mv "${rendered_file}" "${destination_path}" @@ -168,8 +168,8 @@ for target in "${TARGETS[@]}"; do changed_count=$((changed_count + 1)) done -if [ "${check_only}" = true ]; then - if [ "${changed_count}" -gt 0 ]; then +if [[ "${check_only}" == true ]]; then + if [[ "${changed_count}" -gt 0 ]]; then echo "lightspeed config sync is required for ${changed_count} file(s)" >&2 exit 1 fi From 6e025e35f630e7a32ccc510f499967886ce21ac8 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Fri, 10 Apr 2026 14:09:39 -0400 Subject: [PATCH 10/30] attempted fix for ci failures due to write permissions in Kind cluster Signed-off-by: Jordan Dubrick --- .github/actions/test-charts/action.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/actions/test-charts/action.yml b/.github/actions/test-charts/action.yml index 287c8718..e10d7152 100644 --- a/.github/actions/test-charts/action.yml +++ b/.github/actions/test-charts/action.yml @@ -166,6 +166,9 @@ runs: "--set route.enabled=false" "--set upstream.ingress.enabled=true" "--set global.host=rhdh.127.0.0.1.sslip.io" + "--set upstream.backstage.podSecurityContext.runAsUser=1001" + "--set upstream.backstage.podSecurityContext.runAsGroup=1001" + "--set upstream.backstage.podSecurityContext.fsGroup=1001" ) if [[ -n "$INPUT_EXTRA_HELM_ARGS" ]]; then IFS=' ' read -ra ADDITIONAL_ARGS <<< "$INPUT_EXTRA_HELM_ARGS" From 7a7c8662006da11fbae4d1748989e4ce1751875a Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 13 Apr 2026 13:15:01 -0400 Subject: [PATCH 11/30] add resource defaults for lightspeed Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 6 ++--- charts/backstage/templates/_helpers.tpl | 32 +++++++++++++++++++++--- charts/backstage/values.schema.json | 22 ++++++++++++++-- charts/backstage/values.schema.tmpl.json | 22 ++++++++++++++-- charts/backstage/values.yaml | 16 ++++++++++-- 5 files changed, 85 insertions(+), 13 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index e9f96314..dbedf6e1 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,13 +174,13 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}],"resources":{"lightspeedCore":{},"ragInit":{}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}],"resources":{"lightspeedCore":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"ragInit":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | | global.lightspeed.images.lightspeedCore | Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. | string | `"quay.io/lightspeed-core/lightspeed-stack:0.5.0"` | | global.lightspeed.images.ragInit | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | | global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}]` | -| global.lightspeed.resources.lightspeedCore | Resource requests/limits for the Lightspeed Core sidecar. | object | `{}` | -| global.lightspeed.resources.ragInit | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{}` | +| global.lightspeed.resources.lightspeedCore | Resource requests/limits for the Lightspeed Core sidecar. | object | `{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}}` | +| global.lightspeed.resources.ragInit | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}` | | global.lightspeed.runtimeVolume.emptyDir | `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. | object | `{}` | | global.lightspeed.runtimeVolume.persistentVolumeClaim | Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. | object | `{}` | | global.lightspeed.runtimeVolume.type | Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. Supported values: `emptyDir`, `persistentVolumeClaim`. | string | `"emptyDir"` | diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index 461dada1..a4f9cb78 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -102,8 +102,20 @@ images: ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 resources: - ragInit: {} - lightspeedCore: {} + ragInit: + requests: + cpu: 50m + memory: 150Mi + limits: + cpu: 100m + memory: 500Mi + lightspeedCore: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 1000m + memory: 2Gi runtimeVolume: name: lightspeed-data mountPath: /tmp @@ -153,7 +165,13 @@ initContainer: cp -r /rag/embeddings_model /rag-content/ && echo 'Copy complete.' env: [] - resources: {} + resources: + requests: + cpu: 50m + memory: 150Mi + limits: + cpu: 100m + memory: 500Mi securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false @@ -171,7 +189,13 @@ sidecar: command: [] args: [] env: [] - resources: {} + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 1000m + memory: 2Gi securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 191603c0..b8193101 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -194,8 +194,26 @@ } ], "resources": { - "lightspeedCore": {}, - "ragInit": {} + "lightspeedCore": { + "limits": { + "cpu": "1000m", + "memory": "2Gi" + }, + "requests": { + "cpu": "100m", + "memory": "512Mi" + } + }, + "ragInit": { + "limits": { + "cpu": "100m", + "memory": "500Mi" + }, + "requests": { + "cpu": "50m", + "memory": "150Mi" + } + } }, "runtimeVolume": { "emptyDir": {}, diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index eaa965a9..8946c029 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -202,12 +202,30 @@ "ragInit": { "title": "Resource requests/limits for the Lightspeed RAG bootstrap init container.", "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "default": {} + "default": { + "requests": { + "cpu": "50m", + "memory": "150Mi" + }, + "limits": { + "cpu": "100m", + "memory": "500Mi" + } + } }, "lightspeedCore": { "title": "Resource requests/limits for the Lightspeed Core sidecar.", "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "default": {} + "default": { + "requests": { + "cpu": "100m", + "memory": "512Mi" + }, + "limits": { + "cpu": "1000m", + "memory": "2Gi" + } + } } } }, diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 0c4f70ea..8da78d80 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -83,9 +83,21 @@ global: lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 resources: # -- Resource requests/limits for the Lightspeed RAG bootstrap init container. - ragInit: {} + ragInit: + requests: + cpu: 50m + memory: 150Mi + limits: + cpu: 100m + memory: 500Mi # -- Resource requests/limits for the Lightspeed Core sidecar. - lightspeedCore: {} + lightspeedCore: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 1000m + memory: 2Gi runtimeVolume: # -- Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. # Supported values: `emptyDir`, `persistentVolumeClaim`. From 2f3dfdc84d4ea7978bd03d4c7f51bc48dc31abaf Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 13 Apr 2026 13:40:24 -0400 Subject: [PATCH 12/30] move defaults for lightspeed to separate yaml file Signed-off-by: Jordan Dubrick --- charts/backstage/templates/_helpers.tpl | 154 +----------------- .../backstage/files/lightspeed/defaults.yaml | 144 ++++++++++++++++ 2 files changed, 153 insertions(+), 145 deletions(-) create mode 100644 charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index a4f9cb78..63ac2401 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -61,150 +61,9 @@ Return the Lightspeed defaults as YAML so upgrades from charts that predate the feature can still render when values are reused. */}} {{- define "rhdh.lightspeed.defaults" -}} -enabled: true -plugins: - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed - disabled: false - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-lightspeed: - translationResources: - - importName: lightspeedTranslations - module: Alpha - ref: lightspeedTranslationRef - dynamicRoutes: - - path: /lightspeed - importName: LightspeedPage - mountPoints: - - mountPoint: application/listener - importName: LightspeedFAB - - mountPoint: application/provider - importName: LightspeedDrawerProvider - - mountPoint: application/internal/drawer-state - importName: LightspeedDrawerStateExposer - config: - id: lightspeed - - mountPoint: application/internal/drawer-content - importName: LightspeedChatContainer - config: - id: lightspeed - priority: 100 - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5 - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1 - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2 - disabled: false -images: - ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 - lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 -resources: - ragInit: - requests: - cpu: 50m - memory: 150Mi - limits: - cpu: 100m - memory: 500Mi - lightspeedCore: - requests: - cpu: 100m - memory: 512Mi - limits: - cpu: 1000m - memory: 2Gi -runtimeVolume: - name: lightspeed-data - mountPath: /tmp - type: emptyDir - emptyDir: {} - persistentVolumeClaim: {} -ragVolume: - name: lightspeed-rag - initMountPath: /rag-content - mountPath: /rag-content - emptyDir: {} -configMaps: - - name: stack - nameOverride: "" - mountPath: /app-root/lightspeed-stack.yaml - subPath: lightspeed-stack.yaml - sourceFile: lightspeed-stack.yaml - optional: false - - name: config - nameOverride: "" - mountPath: /app-root/config.yaml - subPath: config.yaml - sourceFile: config.yaml - optional: false - - name: rhdh-profile - nameOverride: "" - mountPath: /app-root/rhdh-profile.py - subPath: rhdh-profile.py - sourceFile: rhdh-profile.py - optional: false -secret: - create: true - name: "" - optional: false - sourceFile: secret.yaml -initContainer: - name: lightspeed-rag-init - imagePullPolicy: IfNotPresent - command: - - sh - - -c - args: - - >- - mkdir -p /tmp/data && - echo 'Copying Lightspeed RAG data...' && - cp -r /rag/vector_db /rag-content/ && - cp -r /rag/embeddings_model /rag-content/ && - echo 'Copy complete.' - env: [] - resources: - requests: - cpu: 50m - memory: 150Mi - limits: - cpu: 100m - memory: 500Mi - securityContext: - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - seccompProfile: - type: "RuntimeDefault" -sidecar: - name: lightspeed-core - imagePullPolicy: IfNotPresent - portName: http-lightspeed - containerPort: 8080 - command: [] - args: [] - env: [] - resources: - requests: - cpu: 100m - memory: 512Mi - limits: - cpu: 1000m - memory: 2Gi - securityContext: - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - seccompProfile: - type: "RuntimeDefault" +{{- $file := "defaults.yaml" -}} +{{- $content := include "rhdh.lightspeed.fileContent" (dict "context" . "file" $file) -}} +{{- required (printf "missing Lightspeed defaults file %s" (include "rhdh.lightspeed.filePath" $file)) $content -}} {{- end -}} {{/* @@ -349,7 +208,12 @@ Return the relative path for a Lightspeed payload file. Return rendered content of a Lightspeed payload file. */}} {{- define "rhdh.lightspeed.fileContent" -}} -{{- .context.Files.Get (include "rhdh.lightspeed.filePath" .file) -}} +{{- $path := include "rhdh.lightspeed.filePath" .file -}} +{{- $content := .context.Files.Get $path -}} +{{- if and (empty $content) .context.Subcharts (hasKey .context.Subcharts "upstream") -}} + {{- $content = .context.Subcharts.upstream.Files.Get $path -}} +{{- end -}} +{{- $content -}} {{- end -}} {{/* diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml new file mode 100644 index 00000000..7f291fde --- /dev/null +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml @@ -0,0 +1,144 @@ +enabled: true +plugins: + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + red-hat-developer-hub.backstage-plugin-lightspeed: + translationResources: + - importName: lightspeedTranslations + module: Alpha + ref: lightspeedTranslationRef + dynamicRoutes: + - path: /lightspeed + importName: LightspeedPage + mountPoints: + - mountPoint: application/listener + importName: LightspeedFAB + - mountPoint: application/provider + importName: LightspeedDrawerProvider + - mountPoint: application/internal/drawer-state + importName: LightspeedDrawerStateExposer + config: + id: lightspeed + - mountPoint: application/internal/drawer-content + importName: LightspeedChatContainer + config: + id: lightspeed + priority: 100 + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2 + disabled: false +images: + ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 + lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 +resources: + ragInit: + requests: + cpu: 50m + memory: 150Mi + limits: + cpu: 100m + memory: 500Mi + lightspeedCore: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 1000m + memory: 2Gi +runtimeVolume: + name: lightspeed-data + mountPath: /tmp + type: emptyDir + emptyDir: {} + persistentVolumeClaim: {} +ragVolume: + name: lightspeed-rag + initMountPath: /rag-content + mountPath: /rag-content + emptyDir: {} +configMaps: + - name: stack + nameOverride: "" + mountPath: /app-root/lightspeed-stack.yaml + subPath: lightspeed-stack.yaml + sourceFile: lightspeed-stack.yaml + optional: false + - name: config + nameOverride: "" + mountPath: /app-root/config.yaml + subPath: config.yaml + sourceFile: config.yaml + optional: false + - name: rhdh-profile + nameOverride: "" + mountPath: /app-root/rhdh-profile.py + subPath: rhdh-profile.py + sourceFile: rhdh-profile.py + optional: false +secret: + create: true + name: "" + optional: false + sourceFile: secret.yaml +initContainer: + name: lightspeed-rag-init + imagePullPolicy: IfNotPresent + command: + - sh + - -c + args: + - >- + mkdir -p /tmp/data && + echo 'Copying Lightspeed RAG data...' && + cp -r /rag/vector_db /rag-content/ && + cp -r /rag/embeddings_model /rag-content/ && + echo 'Copy complete.' + env: [] + resources: + requests: + cpu: 50m + memory: 150Mi + limits: + cpu: 100m + memory: 500Mi + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" +sidecar: + name: lightspeed-core + imagePullPolicy: IfNotPresent + portName: http-lightspeed + containerPort: 8080 + command: [] + args: [] + env: [] + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 1000m + memory: 2Gi + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" From 0cbdc52e4ebdf81cd6f6335d869af3f2e3eab541 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 13 Apr 2026 14:53:51 -0400 Subject: [PATCH 13/30] add mcp to the lightspeed stack config Signed-off-by: Jordan Dubrick --- CONTRIBUTING.md | 2 +- .../files/lightspeed/lightspeed-stack.yaml | 6 ++++++ hack/sync-lightspeed-configs.sh | 17 ++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 022b90fe..0c794b78 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,7 @@ Verify the vendored files are already in sync without writing changes: ./hack/sync-lightspeed-configs.sh --ref main --check ``` -The script copies the upstream config files directly, except it renders `secret.yaml` from upstream `env/default-values.env` by dropping comment lines plus `LIGHTSPEED_CORE_IMAGE` and `RAG_CONTENT_IMAGE`, then converting each remaining `KEY=value` line into the chart's YAML secret payload. +The script copies the upstream config files directly, except it appends the chart-managed `mcp_servers` block to `lightspeed-stack.yaml` and renders `secret.yaml` from upstream `env/default-values.env` by dropping comment lines plus `LIGHTSPEED_CORE_IMAGE` and `RAG_CONTENT_IMAGE`, then converting each remaining `KEY=value` line into the chart's YAML secret payload. Choose the upstream branch or tag that matches the Lightspeed release you want to vendor. **Important:** After any change to the dependency structure or version of the vendored chart, you must rebuild the lock file and local subchart dependencies: diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml index 92fd72c4..c4563e1a 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml @@ -35,3 +35,9 @@ conversation_cache: db_path: '/tmp/cache.db' customization: profile_path: '/app-root/rhdh-profile.py' +mcp_servers: + - name: mcp-integration-tools + provider_id: "model-context-protocol" + url: "http://localhost:7007/api/mcp-actions/v1" + authorization_headers: + Authorization: "client" diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh index 4daab427..a1d3b406 100755 --- a/hack/sync-lightspeed-configs.sh +++ b/hack/sync-lightspeed-configs.sh @@ -11,7 +11,7 @@ LIGHTSPEED_DIR="${REPO_ROOT}/charts/backstage/vendor/backstage/charts/backstage/ # Format: upstream_path|destination_path|transform_function TARGETS=( - "lightspeed-core-configs/lightspeed-stack.yaml|${LIGHTSPEED_DIR}/lightspeed-stack.yaml|copy_fetched_file" + "lightspeed-core-configs/lightspeed-stack.yaml|${LIGHTSPEED_DIR}/lightspeed-stack.yaml|render_lightspeed_stack_yaml" "llama-stack-configs/config.yaml|${LIGHTSPEED_DIR}/config.yaml|copy_fetched_file" "lightspeed-core-configs/rhdh-profile.py|${LIGHTSPEED_DIR}/rhdh-profile.py|copy_fetched_file" "env/default-values.env|${LIGHTSPEED_DIR}/secret.yaml|render_secret_yaml_from_env" @@ -24,6 +24,21 @@ copy_fetched_file() { cp "${source_file}" "${destination_file}" } +render_lightspeed_stack_yaml() { + local source_file=$1 + local destination_file=$2 + + cp "${source_file}" "${destination_file}" + cat <<'EOF' >> "${destination_file}" +mcp_servers: + - name: mcp-integration-tools + provider_id: "model-context-protocol" + url: "http://localhost:7007/api/mcp-actions/v1" + authorization_headers: + Authorization: "client" +EOF +} + render_secret_yaml_from_env() { local source_file=$1 local destination_file=$2 From e6b3158fc48520649984df0d2515fad406f05610 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Fri, 17 Apr 2026 10:34:18 -0400 Subject: [PATCH 14/30] remove MCP plugins from default lightspeed install Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 4 ++-- charts/backstage/values.schema.json | 24 ------------------- charts/backstage/values.yaml | 6 ----- .../backstage/files/lightspeed/defaults.yaml | 6 ----- hack/sync-lightspeed-configs.sh | 2 +- 5 files changed, 3 insertions(+), 39 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index dbedf6e1..24534e5c 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,11 +174,11 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}],"resources":{"lightspeedCore":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"ragInit":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"resources":{"lightspeedCore":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"ragInit":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | | global.lightspeed.images.lightspeedCore | Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. | string | `"quay.io/lightspeed-core/lightspeed-stack:0.5.0"` | | global.lightspeed.images.ragInit | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | -| global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1"},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2"}]` | +| global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}]` | | global.lightspeed.resources.lightspeedCore | Resource requests/limits for the Lightspeed Core sidecar. | object | `{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}}` | | global.lightspeed.resources.ragInit | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}` | | global.lightspeed.runtimeVolume.emptyDir | `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. | object | `{}` | diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index b8193101..740feec8 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -179,18 +179,6 @@ { "disabled": false, "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" - }, - { - "disabled": false, - "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5" - }, - { - "disabled": false, - "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1" - }, - { - "disabled": false, - "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2" } ], "resources": { @@ -299,18 +287,6 @@ { "disabled": false, "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" - }, - { - "disabled": false, - "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5" - }, - { - "disabled": false, - "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1" - }, - { - "disabled": false, - "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2" } ], "items": { diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 8da78d80..4a60122e 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -70,12 +70,6 @@ global: priority: 100 - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5 - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1 - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2 - disabled: false images: # -- Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml index 7f291fde..02e7c3af 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml @@ -29,12 +29,6 @@ plugins: priority: 100 - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-mcp-actions-backend:bs_1.45.3__0.1.5 - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-software-catalog-mcp-tool:bs_1.45.3__0.4.1 - disabled: false - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-techdocs-mcp-tool:bs_1.45.3__0.3.2 - disabled: false images: ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh index a1d3b406..13b3e2e0 100755 --- a/hack/sync-lightspeed-configs.sh +++ b/hack/sync-lightspeed-configs.sh @@ -23,7 +23,7 @@ copy_fetched_file() { cp "${source_file}" "${destination_file}" } - +# add mcp to LCORE config render_lightspeed_stack_yaml() { local source_file=$1 local destination_file=$2 From dd51e04c3cee758b91e36f39a23f4e2234c9b879 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Fri, 17 Apr 2026 11:57:49 -0400 Subject: [PATCH 15/30] add rhdh ai team as codeowner of lightspeed defaults Signed-off-by: Jordan Dubrick --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 65a78d4b..5f89714c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,3 +17,6 @@ # Documentation: *.md.gotmpl @redhat-developer/RHDH-content /README.md @redhat-developer/RHDH-content + +# Lightspeed: +/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml @redhat-developer/rhdh-ai From 6794cbb8dcec0194cc1edd1ad07e58394f7fb562 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Fri, 17 Apr 2026 13:11:58 -0400 Subject: [PATCH 16/30] add fast fail for lightspeed files Signed-off-by: Jordan Dubrick --- charts/backstage/templates/_helpers.tpl | 26 ++++++++++++++++--- .../templates/lightspeed-configmaps.yaml | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index 63ac2401..356dff97 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -206,12 +206,26 @@ Return the relative path for a Lightspeed payload file. {{/* Return rendered content of a Lightspeed payload file. + +When optional=false is passed, fail fast if the referenced payload file is missing. */}} {{- define "rhdh.lightspeed.fileContent" -}} {{- $path := include "rhdh.lightspeed.filePath" .file -}} {{- $content := .context.Files.Get $path -}} -{{- if and (empty $content) .context.Subcharts (hasKey .context.Subcharts "upstream") -}} - {{- $content = .context.Subcharts.upstream.Files.Get $path -}} +{{- $exists := gt (len (.context.Files.Glob $path)) 0 -}} +{{- if and .context.Subcharts (hasKey .context.Subcharts "upstream") -}} + {{- $upstreamExists := gt (len (.context.Subcharts.upstream.Files.Glob $path)) 0 -}} + {{- if and (empty $content) $upstreamExists -}} + {{- $content = .context.Subcharts.upstream.Files.Get $path -}} + {{- end -}} + {{- $exists = or $exists $upstreamExists -}} +{{- end -}} +{{- if and (hasKey . "optional") (not .optional) -}} + {{- $message := printf "missing required Lightspeed payload file %s" $path -}} + {{- if hasKey . "ref" -}} + {{- $message = printf "%s referenced by %s" $message .ref -}} + {{- end -}} + {{- $_ := required $message (ternary $path "" $exists) -}} {{- end -}} {{- $content -}} {{- end -}} @@ -225,7 +239,11 @@ Return the stringData map for the Lightspeed Secret. {{- $context = get . "context" -}} {{- end -}} {{- $lightspeed := include "rhdh.lightspeed.resolve" (dict "context" $context "input" .) | fromYaml -}} -{{- include "rhdh.lightspeed.fileContent" (dict "context" $context "file" $lightspeed.secret.sourceFile) | fromYaml | toYaml -}} +{{- if not $lightspeed.secret.create -}} +{{- dict | toYaml -}} +{{- else -}} +{{- include "rhdh.lightspeed.fileContent" (dict "context" $context "file" $lightspeed.secret.sourceFile "optional" $lightspeed.secret.optional "ref" "global.lightspeed.secret.sourceFile") | fromYaml | toYaml -}} +{{- end -}} {{- end -}} {{/* @@ -246,7 +264,7 @@ Return the Lightspeed ConfigMap payloads for checksum calculation. "subPath" .subPath "sourceFile" .sourceFile "optional" .optional - "content" (include "rhdh.lightspeed.fileContent" (dict "context" $context "file" .sourceFile)) + "content" (include "rhdh.lightspeed.fileContent" (dict "context" $context "file" .sourceFile "optional" .optional "ref" (printf "global.lightspeed.configMaps[%s].sourceFile" .name))) ) -}} {{- end -}} {{- toJson $configMaps -}} diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml index 0c218d2b..06252b71 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml @@ -11,6 +11,6 @@ metadata: namespace: {{ $.Release.Namespace | quote }} data: {{ $configMap.subPath }}: | -{{ include "rhdh.lightspeed.fileContent" (dict "context" $ "file" $configMap.sourceFile) | nindent 4 }} +{{ include "rhdh.lightspeed.fileContent" (dict "context" $ "file" $configMap.sourceFile "optional" $configMap.optional "ref" (printf "global.lightspeed.configMaps[%s].sourceFile" $configMap.name)) | nindent 4 }} {{- end }} {{- end }} From dbbfe2a3fe24da0b63883ebec39e56792c5a313d Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 12:09:34 -0400 Subject: [PATCH 17/30] remove plugins from defaults for lightspeed, keep defined in values Signed-off-by: Jordan Dubrick --- .../backstage/files/lightspeed/defaults.yaml | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml index 02e7c3af..5e979bd8 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml @@ -1,34 +1,4 @@ enabled: true -plugins: - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed - disabled: false - pluginConfig: - dynamicPlugins: - frontend: - red-hat-developer-hub.backstage-plugin-lightspeed: - translationResources: - - importName: lightspeedTranslations - module: Alpha - ref: lightspeedTranslationRef - dynamicRoutes: - - path: /lightspeed - importName: LightspeedPage - mountPoints: - - mountPoint: application/listener - importName: LightspeedFAB - - mountPoint: application/provider - importName: LightspeedDrawerProvider - - mountPoint: application/internal/drawer-state - importName: LightspeedDrawerStateExposer - config: - id: lightspeed - - mountPoint: application/internal/drawer-content - importName: LightspeedChatContainer - config: - id: lightspeed - priority: 100 - - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend - disabled: false images: ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 From 8d58db21e9dc1a06f87100950c8e5653cc1a1a33 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 12:21:07 -0400 Subject: [PATCH 18/30] move enabled and image defaults out, rely solely on values file Signed-off-by: Jordan Dubrick --- .../backstage/charts/backstage/files/lightspeed/defaults.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml index 5e979bd8..c3f3f9d5 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml @@ -1,7 +1,3 @@ -enabled: true -images: - ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 - lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 resources: ragInit: requests: From fab5e54b844422c268878c06f8ada2239fa5b758 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 12:35:55 -0400 Subject: [PATCH 19/30] move checksum for lightspeed plugin to vendored template Signed-off-by: Jordan Dubrick --- charts/backstage/values.schema.json | 4 +--- charts/backstage/values.yaml | 4 ---- .../charts/backstage/templates/backstage-deployment.yaml | 1 + 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 740feec8..10e6db10 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -6528,9 +6528,7 @@ "additionalProperties": { "type": "string" }, - "default": { - "checksum/dynamic-plugins": "{{- $lightspeed := include \"rhdh.lightspeed\" . | fromYaml -}} {{- include \"common.tplvalues.render\" ( dict \"value\" (dict \"dynamic\" .Values.global.dynamic \"lightspeed\" (dict \"enabled\" $lightspeed.enabled \"plugins\" $lightspeed.plugins)) \"context\" $) | sha256sum }}" - }, + "default": {}, "title": "Annotations to add to the backend deployment pods", "type": "object" }, diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 4a60122e..8511b4bf 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -316,10 +316,6 @@ upstream: mountPath: /tmp workingDir: /opt/app-root/src installDir: /opt/app-root/src - podAnnotations: - checksum/dynamic-plugins: >- - {{- $lightspeed := include "rhdh.lightspeed" . | fromYaml -}} - {{- include "common.tplvalues.render" ( dict "value" (dict "dynamic" .Values.global.dynamic "lightspeed" (dict "enabled" $lightspeed.enabled "plugins" $lightspeed.plugins)) "context" $) | sha256sum }} ingress: host: "{{ .Values.global.host }}" metrics: diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml index 7051afeb..47f02389 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml @@ -41,6 +41,7 @@ spec: {{- end }} annotations: checksum/app-config: {{ include "common.tplvalues.render" ( dict "value" .Values.backstage.appConfig "context" $) | sha256sum }} + checksum/dynamic-plugins: {{ include "common.tplvalues.render" ( dict "value" (dict "dynamic" .Values.global.dynamic "lightspeed" (dict "enabled" $lightspeed.enabled "plugins" $lightspeed.plugins)) "context" $) | sha256sum }} {{- if $lightspeed.enabled }} checksum/lightspeed-configmaps: {{ include "rhdh.lightspeed.configMapsChecksum" (dict "context" $ "lightspeed" $lightspeed) | sha256sum }} checksum/lightspeed-secret: {{ include "rhdh.lightspeed.secretChecksum" (dict "context" $ "lightspeed" $lightspeed) | sha256sum }} From 4a1e22df81ac54429fc714b299587c2c27c68c34 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 13:27:55 -0400 Subject: [PATCH 20/30] move lightspeed files to parent chart Signed-off-by: Jordan Dubrick --- .../files/lightspeed/config.yaml | 0 .../files/lightspeed/lightspeed-stack.yaml | 0 .../files/lightspeed/rhdh-profile.py | 0 .../files/lightspeed/secret.yaml | 0 .../templates/lightspeed-configmaps.yaml | 0 .../templates/lightspeed-secret.yaml | 0 .../backstage/files/lightspeed/defaults.yaml | 104 ------------------ hack/sync-lightspeed-configs.sh | 2 +- 8 files changed, 1 insertion(+), 105 deletions(-) rename charts/backstage/{vendor/backstage/charts/backstage => }/files/lightspeed/config.yaml (100%) rename charts/backstage/{vendor/backstage/charts/backstage => }/files/lightspeed/lightspeed-stack.yaml (100%) rename charts/backstage/{vendor/backstage/charts/backstage => }/files/lightspeed/rhdh-profile.py (100%) rename charts/backstage/{vendor/backstage/charts/backstage => }/files/lightspeed/secret.yaml (100%) rename charts/backstage/{vendor/backstage/charts/backstage => }/templates/lightspeed-configmaps.yaml (100%) rename charts/backstage/{vendor/backstage/charts/backstage => }/templates/lightspeed-secret.yaml (100%) delete mode 100644 charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/config.yaml b/charts/backstage/files/lightspeed/config.yaml similarity index 100% rename from charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/config.yaml rename to charts/backstage/files/lightspeed/config.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml b/charts/backstage/files/lightspeed/lightspeed-stack.yaml similarity index 100% rename from charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/lightspeed-stack.yaml rename to charts/backstage/files/lightspeed/lightspeed-stack.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/rhdh-profile.py b/charts/backstage/files/lightspeed/rhdh-profile.py similarity index 100% rename from charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/rhdh-profile.py rename to charts/backstage/files/lightspeed/rhdh-profile.py diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml b/charts/backstage/files/lightspeed/secret.yaml similarity index 100% rename from charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/secret.yaml rename to charts/backstage/files/lightspeed/secret.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml b/charts/backstage/templates/lightspeed-configmaps.yaml similarity index 100% rename from charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-configmaps.yaml rename to charts/backstage/templates/lightspeed-configmaps.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-secret.yaml b/charts/backstage/templates/lightspeed-secret.yaml similarity index 100% rename from charts/backstage/vendor/backstage/charts/backstage/templates/lightspeed-secret.yaml rename to charts/backstage/templates/lightspeed-secret.yaml diff --git a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml b/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml deleted file mode 100644 index c3f3f9d5..00000000 --- a/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml +++ /dev/null @@ -1,104 +0,0 @@ -resources: - ragInit: - requests: - cpu: 50m - memory: 150Mi - limits: - cpu: 100m - memory: 500Mi - lightspeedCore: - requests: - cpu: 100m - memory: 512Mi - limits: - cpu: 1000m - memory: 2Gi -runtimeVolume: - name: lightspeed-data - mountPath: /tmp - type: emptyDir - emptyDir: {} - persistentVolumeClaim: {} -ragVolume: - name: lightspeed-rag - initMountPath: /rag-content - mountPath: /rag-content - emptyDir: {} -configMaps: - - name: stack - nameOverride: "" - mountPath: /app-root/lightspeed-stack.yaml - subPath: lightspeed-stack.yaml - sourceFile: lightspeed-stack.yaml - optional: false - - name: config - nameOverride: "" - mountPath: /app-root/config.yaml - subPath: config.yaml - sourceFile: config.yaml - optional: false - - name: rhdh-profile - nameOverride: "" - mountPath: /app-root/rhdh-profile.py - subPath: rhdh-profile.py - sourceFile: rhdh-profile.py - optional: false -secret: - create: true - name: "" - optional: false - sourceFile: secret.yaml -initContainer: - name: lightspeed-rag-init - imagePullPolicy: IfNotPresent - command: - - sh - - -c - args: - - >- - mkdir -p /tmp/data && - echo 'Copying Lightspeed RAG data...' && - cp -r /rag/vector_db /rag-content/ && - cp -r /rag/embeddings_model /rag-content/ && - echo 'Copy complete.' - env: [] - resources: - requests: - cpu: 50m - memory: 150Mi - limits: - cpu: 100m - memory: 500Mi - securityContext: - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - seccompProfile: - type: "RuntimeDefault" -sidecar: - name: lightspeed-core - imagePullPolicy: IfNotPresent - portName: http-lightspeed - containerPort: 8080 - command: [] - args: [] - env: [] - resources: - requests: - cpu: 100m - memory: 512Mi - limits: - cpu: 1000m - memory: 2Gi - securityContext: - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - seccompProfile: - type: "RuntimeDefault" diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh index 13b3e2e0..72b387d6 100755 --- a/hack/sync-lightspeed-configs.sh +++ b/hack/sync-lightspeed-configs.sh @@ -7,7 +7,7 @@ DEFAULT_REF="main" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" -LIGHTSPEED_DIR="${REPO_ROOT}/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed" +LIGHTSPEED_DIR="${REPO_ROOT}/charts/backstage/files/lightspeed" # Format: upstream_path|destination_path|transform_function TARGETS=( From 61b6915277154539aeb2dcd44432fab8adb30e2b Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 13:31:48 -0400 Subject: [PATCH 21/30] update codeowners and docs for new lightspeed file location Signed-off-by: Jordan Dubrick --- .github/CODEOWNERS | 2 +- CONTRIBUTING.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5f89714c..5df8c931 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -19,4 +19,4 @@ /README.md @redhat-developer/RHDH-content # Lightspeed: -/charts/backstage/vendor/backstage/charts/backstage/files/lightspeed/defaults.yaml @redhat-developer/rhdh-ai +/charts/backstage/files/lightspeed/ @redhat-developer/rhdh-ai diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c794b78..8ee7b30b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,7 +43,7 @@ It is important to use `--squash` to avoid pulling the entire commit history of ### Sync Lightspeed vendored config files -The vendored Lightspeed config files under [`charts/backstage/vendor/backstage/charts/backstage/files/lightspeed`](./charts/backstage/vendor/backstage/charts/backstage/files/lightspeed) are synced separately from the Backstage subtree by [`hack/sync-lightspeed-configs.sh`](./hack/sync-lightspeed-configs.sh). +The Lightspeed config files under [`charts/backstage/files/lightspeed`](./charts/backstage/files/lightspeed) are synced separately from the Backstage subtree by [`hack/sync-lightspeed-configs.sh`](./hack/sync-lightspeed-configs.sh). Use the default upstream branch: From 3e647a0feb0c8b98df82868d4c61b75aa7688a68 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 13:46:54 -0400 Subject: [PATCH 22/30] consolidate lightspeed fields in values.yaml Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 10 +- charts/backstage/README.md.gotmpl | 4 +- charts/backstage/templates/_helpers.tpl | 65 +------ charts/backstage/values.schema.json | 182 ++---------------- charts/backstage/values.yaml | 109 +++++++++-- .../templates/backstage-deployment.yaml | 4 +- 6 files changed, 123 insertions(+), 251 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 24534e5c..50386857 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,13 +174,9 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"images":{"lightspeedCore":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","ragInit":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"resources":{"lightspeedCore":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"ragInit":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}},"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | -| global.lightspeed.images.lightspeedCore | Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. | string | `"quay.io/lightspeed-core/lightspeed-stack:0.5.0"` | -| global.lightspeed.images.ragInit | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | | global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}]` | -| global.lightspeed.resources.lightspeedCore | Resource requests/limits for the Lightspeed Core sidecar. | object | `{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}}` | -| global.lightspeed.resources.ragInit | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}` | | global.lightspeed.runtimeVolume.emptyDir | `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. | object | `{}` | | global.lightspeed.runtimeVolume.persistentVolumeClaim | Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. | object | `{}` | | global.lightspeed.runtimeVolume.type | Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. Supported values: `emptyDir`, `persistentVolumeClaim`. | string | `"emptyDir"` | @@ -318,9 +314,9 @@ For detailed information on configuring the catalog index, including how to over Use `global.lightspeed.enabled` to enable or disable the built-in Lightspeed feature. -When enabled, the chart adds the default Lightspeed dynamic plugins, a RAG bootstrap init container, a Lightspeed Core sidecar listening on port `8080`, chart-generated ConfigMaps, a chart-generated Secret, and separate runtime and RAG data volumes. Override `global.lightspeed.plugins` or the `global.lightspeed.images.ragInit` and `global.lightspeed.images.lightspeedCore` full image references for disconnected environments. +When enabled, the chart adds the default Lightspeed dynamic plugins, a RAG bootstrap init container, a Lightspeed Core sidecar listening on port `8080`, chart-generated ConfigMaps, a chart-generated Secret, and separate runtime and RAG data volumes. Override `global.lightspeed.plugins` for disconnected environments. -Use `global.lightspeed.resources` to set resource requests and limits for the Lightspeed init container and sidecar. Use `global.lightspeed.runtimeVolume` to change the writable `/tmp` runtime storage between `emptyDir` and an existing PVC reference. The chart mounts that volume at `/tmp` so both generated temp files and `/tmp/data` remain writable. The `/rag-content` volume stays chart-managed and `emptyDir`-backed because the RAG assets are repopulated by the init container on each Pod start. +Use `global.lightspeed.runtimeVolume` to change the writable `/tmp` runtime storage between `emptyDir` and an existing PVC reference. The chart mounts that volume at `/tmp` so both generated temp files and `/tmp/data` remain writable. The `/rag-content` volume stays chart-managed and `emptyDir`-backed because the RAG assets are repopulated by the init container on each Pod start. When using the built-in Lightspeed feature, do not also keep Lightspeed plugin packages in `global.dynamic.plugins`. Existing installations that previously configured Lightspeed there should remove those entries if the built-in defaults are sufficient, or move their custom package definitions to `global.lightspeed.plugins`; otherwise the rendered `dynamic-plugins.yaml` will contain duplicate Lightspeed plugin entries. diff --git a/charts/backstage/README.md.gotmpl b/charts/backstage/README.md.gotmpl index ad5b0597..caf11499 100644 --- a/charts/backstage/README.md.gotmpl +++ b/charts/backstage/README.md.gotmpl @@ -240,9 +240,9 @@ For detailed information on configuring the catalog index, including how to over Use `global.lightspeed.enabled` to enable or disable the built-in Lightspeed feature. -When enabled, the chart adds the default Lightspeed dynamic plugins, a RAG bootstrap init container, a Lightspeed Core sidecar listening on port `8080`, chart-generated ConfigMaps, a chart-generated Secret, and separate runtime and RAG data volumes. Override `global.lightspeed.plugins` or the `global.lightspeed.images.ragInit` and `global.lightspeed.images.lightspeedCore` full image references for disconnected environments. +When enabled, the chart adds the default Lightspeed dynamic plugins, a RAG bootstrap init container, a Lightspeed Core sidecar listening on port `8080`, chart-generated ConfigMaps, a chart-generated Secret, and separate runtime and RAG data volumes. Override `global.lightspeed.plugins` for disconnected environments. -Use `global.lightspeed.resources` to set resource requests and limits for the Lightspeed init container and sidecar. Use `global.lightspeed.runtimeVolume` to change the writable `/tmp` runtime storage between `emptyDir` and an existing PVC reference. The chart mounts that volume at `/tmp` so both generated temp files and `/tmp/data` remain writable. The `/rag-content` volume stays chart-managed and `emptyDir`-backed because the RAG assets are repopulated by the init container on each Pod start. +Use `global.lightspeed.runtimeVolume` to change the writable `/tmp` runtime storage between `emptyDir` and an existing PVC reference. The chart mounts that volume at `/tmp` so both generated temp files and `/tmp/data` remain writable. The `/rag-content` volume stays chart-managed and `emptyDir`-backed because the RAG assets are repopulated by the init container on each Pod start. When using the built-in Lightspeed feature, do not also keep Lightspeed plugin packages in `global.dynamic.plugins`. Existing installations that previously configured Lightspeed there should remove those entries if the built-in defaults are sufficient, or move their custom package definitions to `global.lightspeed.plugins`; otherwise the rendered `dynamic-plugins.yaml` will contain duplicate Lightspeed plugin entries. diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index 356dff97..46acd488 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -49,23 +49,6 @@ Referenced from: https://github.com/bitnami/charts/blob/main/bitnami/postgresql/ {{- end -}} {{- end -}} -{{/* -Render a Lightspeed container image reference string. -*/}} -{{- define "rhdh.lightspeed.image" -}} -{{- include "common.tplvalues.render" (dict "value" .image "context" .context) -}} -{{- end -}} - -{{/* -Return the Lightspeed defaults as YAML so upgrades from charts that predate -the feature can still render when values are reused. -*/}} -{{- define "rhdh.lightspeed.defaults" -}} -{{- $file := "defaults.yaml" -}} -{{- $content := include "rhdh.lightspeed.fileContent" (dict "context" . "file" $file) -}} -{{- required (printf "missing Lightspeed defaults file %s" (include "rhdh.lightspeed.filePath" $file)) $content -}} -{{- end -}} - {{/* Return the configured Lightspeed runtime volume type and validate the required source block is present. @@ -93,42 +76,17 @@ source block is present. {{- end -}} {{/* -Return Lightspeed values merged with upgrade-safe defaults. +Return resolved Lightspeed values from global.lightspeed with legacy key migration. */}} {{- define "rhdh.lightspeed" -}} -{{- $defaults := include "rhdh.lightspeed.defaults" . | fromYaml -}} -{{- $lightspeed := deepCopy $defaults -}} {{- $global := default dict .Values.global -}} +{{- $lightspeed := dict -}} {{- if hasKey $global "lightspeed" -}} {{- $raw := get $global "lightspeed" -}} {{- if kindIs "bool" $raw -}} {{- $_ := set $lightspeed "enabled" $raw -}} {{- else if kindIs "map" $raw -}} - {{- $lightspeed = mergeOverwrite $lightspeed $raw -}} - {{- if hasKey $raw "images" -}} - {{- $rawImages := get $raw "images" -}} - {{- if kindIs "map" $rawImages -}} - {{- if hasKey $rawImages "init" -}} - {{- $legacyInit := get $rawImages "init" -}} - {{- $_ := set $lightspeed.images "ragInit" $legacyInit -}} - {{- end -}} - {{- if hasKey $rawImages "sidecar" -}} - {{- $legacySidecar := get $rawImages "sidecar" -}} - {{- $_ := set $lightspeed.images "lightspeedCore" $legacySidecar -}} - {{- end -}} - {{- end -}} - {{- end -}} - {{- if hasKey $raw "resources" -}} - {{- $rawResources := get $raw "resources" -}} - {{- if kindIs "map" $rawResources -}} - {{- if hasKey $rawResources "ragInit" -}} - {{- $_ := set $lightspeed.initContainer "resources" (get $rawResources "ragInit") -}} - {{- end -}} - {{- if hasKey $rawResources "lightspeedCore" -}} - {{- $_ := set $lightspeed.sidecar "resources" (get $rawResources "lightspeedCore") -}} - {{- end -}} - {{- end -}} - {{- end -}} + {{- $lightspeed = deepCopy $raw -}} {{- if hasKey $raw "runtimeVolume" -}} {{- $rawRuntimeVolume := get $raw "runtimeVolume" -}} {{- if and (kindIs "map" $rawRuntimeVolume) (not (hasKey $rawRuntimeVolume "type")) -}} @@ -213,13 +171,6 @@ When optional=false is passed, fail fast if the referenced payload file is missi {{- $path := include "rhdh.lightspeed.filePath" .file -}} {{- $content := .context.Files.Get $path -}} {{- $exists := gt (len (.context.Files.Glob $path)) 0 -}} -{{- if and .context.Subcharts (hasKey .context.Subcharts "upstream") -}} - {{- $upstreamExists := gt (len (.context.Subcharts.upstream.Files.Glob $path)) 0 -}} - {{- if and (empty $content) $upstreamExists -}} - {{- $content = .context.Subcharts.upstream.Files.Get $path -}} - {{- end -}} - {{- $exists = or $exists $upstreamExists -}} -{{- end -}} {{- if and (hasKey . "optional") (not .optional) -}} {{- $message := printf "missing required Lightspeed payload file %s" $path -}} {{- if hasKey . "ref" -}} @@ -247,7 +198,9 @@ Return the stringData map for the Lightspeed Secret. {{- end -}} {{/* -Return the Lightspeed ConfigMap payloads for checksum calculation. +Return the Lightspeed ConfigMap configuration for checksum calculation. +This checksums the resolved configMaps values; payload file content is baked +into the chart archive so changes are captured by chart version bumps. */}} {{- define "rhdh.lightspeed.configMapsChecksum" -}} {{- $context := . -}} @@ -264,14 +217,15 @@ Return the Lightspeed ConfigMap payloads for checksum calculation. "subPath" .subPath "sourceFile" .sourceFile "optional" .optional - "content" (include "rhdh.lightspeed.fileContent" (dict "context" $context "file" .sourceFile "optional" .optional "ref" (printf "global.lightspeed.configMaps[%s].sourceFile" .name))) ) -}} {{- end -}} {{- toJson $configMaps -}} {{- end -}} {{/* -Return the Lightspeed Secret payload for checksum calculation. +Return the Lightspeed Secret configuration for checksum calculation. +This checksums the resolved secret values; payload file content is baked +into the chart archive so changes are captured by chart version bumps. */}} {{- define "rhdh.lightspeed.secretChecksum" -}} {{- $context := . -}} @@ -284,7 +238,6 @@ Return the Lightspeed Secret payload for checksum calculation. "name" $lightspeed.secret.name "optional" $lightspeed.secret.optional "sourceFile" $lightspeed.secret.sourceFile - "stringData" (include "rhdh.lightspeed.secretStringData" (dict "context" $context "lightspeed" $lightspeed) | fromYaml) | toJson -}} {{- end -}} diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 10e6db10..623fdd2e 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -118,13 +118,9 @@ "type": "string" }, "lightspeed": { - "additionalProperties": false, + "additionalProperties": true, "default": { "enabled": true, - "images": { - "lightspeedCore": "quay.io/lightspeed-core/lightspeed-stack:0.5.0", - "ragInit": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05" - }, "plugins": [ { "disabled": false, @@ -181,30 +177,10 @@ "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" } ], - "resources": { - "lightspeedCore": { - "limits": { - "cpu": "1000m", - "memory": "2Gi" - }, - "requests": { - "cpu": "100m", - "memory": "512Mi" - } - }, - "ragInit": { - "limits": { - "cpu": "100m", - "memory": "500Mi" - }, - "requests": { - "cpu": "50m", - "memory": "150Mi" - } - } - }, "runtimeVolume": { "emptyDir": {}, + "name": "lightspeed-data", + "mountPath": "/tmp", "persistentVolumeClaim": {}, "type": "emptyDir" } @@ -215,23 +191,6 @@ "title": "Enable or disable the built-in Lightspeed feature.", "type": "boolean" }, - "images": { - "additionalProperties": false, - "properties": { - "lightspeedCore": { - "default": "quay.io/lightspeed-core/lightspeed-stack:0.5.0", - "title": "Full image reference for the Lightspeed Core sidecar. Override for disconnected environments.", - "type": "string" - }, - "ragInit": { - "default": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05", - "title": "Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments.", - "type": "string" - } - }, - "title": "Images used by the Lightspeed pod wiring.", - "type": "object" - }, "plugins": { "default": [ { @@ -317,134 +276,19 @@ "title": "Lightspeed plugins and their configuration. Override package references for disconnected environments.", "type": "array" }, - "resources": { - "additionalProperties": false, - "properties": { - "lightspeedCore": { - "description": "ResourceRequirements describes the compute resource requirements.", - "properties": { - "claims": { - "description": "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.", - "items": { - "description": "ResourceClaim references one entry in PodSpec.ResourceClaims.", - "properties": { - "name": { - "description": "Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.", - "type": "string" - }, - "request": { - "description": "Request is the name chosen for a request in the referenced claim. If empty, everything from the claim is made available, otherwise only the result of this request.", - "type": "string" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" - }, - "limits": { - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "description": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", - "type": "object" - }, - "requests": { - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", - "type": "object" - } - }, - "type": "object" - }, - "ragInit": { - "description": "ResourceRequirements describes the compute resource requirements.", - "properties": { - "claims": { - "description": "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.", - "items": { - "description": "ResourceClaim references one entry in PodSpec.ResourceClaims.", - "properties": { - "name": { - "description": "Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.", - "type": "string" - }, - "request": { - "description": "Request is the name chosen for a request in the referenced claim. If empty, everything from the claim is made available, otherwise only the result of this request.", - "type": "string" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "type": "array", - "x-kubernetes-list-map-keys": [ - "name" - ], - "x-kubernetes-list-type": "map" - }, - "limits": { - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "description": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", - "type": "object" - }, - "requests": { - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "description": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/", - "type": "object" - } - }, - "type": "object" - } - }, - "title": "Resource requests/limits for Lightspeed containers.", - "type": "object" - }, "runtimeVolume": { "additionalProperties": false, "properties": { + "name": { + "default": "lightspeed-data", + "title": "Name of the Kubernetes volume used for writable Lightspeed runtime storage.", + "type": "string" + }, + "mountPath": { + "default": "/tmp", + "title": "Mount path inside the container for Lightspeed runtime storage.", + "type": "string" + }, "emptyDir": { "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", "properties": { diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 8511b4bf..2a9ab00e 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -70,36 +70,115 @@ global: priority: 100 - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend disabled: false - images: + runtimeVolume: + # -- Name of the Kubernetes volume used for writable Lightspeed runtime storage. + name: lightspeed-data + # -- Mount path inside the container for Lightspeed runtime storage. + mountPath: /tmp + # -- Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. + # Supported values: `emptyDir`, `persistentVolumeClaim`. + type: emptyDir + # -- `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. + emptyDir: {} + # -- Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. + persistentVolumeClaim: {} + ragVolume: + # -- Name of the Kubernetes volume used for Lightspeed RAG data. + name: lightspeed-rag + # -- Mount path inside the init container for seeding RAG data. + initMountPath: /rag-content + # -- Mount path inside the sidecar container for serving RAG data. + mountPath: /rag-content + # -- `emptyDir` configuration for the RAG data volume. + emptyDir: {} + configMaps: + - name: stack + nameOverride: "" + mountPath: /app-root/lightspeed-stack.yaml + subPath: lightspeed-stack.yaml + sourceFile: lightspeed-stack.yaml + optional: false + - name: config + nameOverride: "" + mountPath: /app-root/config.yaml + subPath: config.yaml + sourceFile: config.yaml + optional: false + - name: rhdh-profile + nameOverride: "" + mountPath: /app-root/rhdh-profile.py + subPath: rhdh-profile.py + sourceFile: rhdh-profile.py + optional: false + secret: + # -- Whether to create a Lightspeed Secret from the bundled source file. + create: true + # -- Name of an existing Secret to use instead. Required when `create` is false. + name: "" + # -- Whether the Secret reference is optional in the pod spec. + optional: false + # -- Bundled file used to populate the Secret's `stringData` keys. + sourceFile: secret.yaml + initContainer: + name: lightspeed-rag-init # -- Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. - ragInit: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 - # -- Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. - lightspeedCore: quay.io/lightspeed-core/lightspeed-stack:0.5.0 - resources: + image: quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05 + imagePullPolicy: IfNotPresent + command: + - sh + - -c + args: + - >- + mkdir -p /tmp/data && + echo 'Copying Lightspeed RAG data...' && + cp -r /rag/vector_db /rag-content/ && + cp -r /rag/embeddings_model /rag-content/ && + echo 'Copy complete.' + env: [] # -- Resource requests/limits for the Lightspeed RAG bootstrap init container. - ragInit: + resources: requests: cpu: 50m memory: 150Mi limits: cpu: 100m memory: 500Mi + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" + sidecar: + name: lightspeed-core + # -- Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. + image: quay.io/lightspeed-core/lightspeed-stack:0.5.0 + imagePullPolicy: IfNotPresent + portName: http-lightspeed + containerPort: 8080 + command: [] + args: [] + env: [] # -- Resource requests/limits for the Lightspeed Core sidecar. - lightspeedCore: + resources: requests: cpu: 100m memory: 512Mi limits: cpu: 1000m memory: 2Gi - runtimeVolume: - # -- Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. - # Supported values: `emptyDir`, `persistentVolumeClaim`. - type: emptyDir - # -- `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. - emptyDir: {} - # -- Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. - persistentVolumeClaim: {} + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: "RuntimeDefault" # -- Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) # @default -- Use Openshift compatible settings upstream: diff --git a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml index 47f02389..540832bb 100644 --- a/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml +++ b/charts/backstage/vendor/backstage/charts/backstage/templates/backstage-deployment.yaml @@ -118,7 +118,7 @@ spec: {{- end }} {{- if $lightspeed.enabled }} - name: {{ $lightspeed.initContainer.name }} - image: {{ include "rhdh.lightspeed.image" (dict "image" $lightspeed.images.ragInit "context" $) }} + image: {{ include "common.tplvalues.render" (dict "value" $lightspeed.initContainer.image "context" $) }} imagePullPolicy: {{ $lightspeed.initContainer.imagePullPolicy | quote }} {{- if $lightspeed.initContainer.securityContext }} securityContext: @@ -242,7 +242,7 @@ spec: {{- end }} {{- if $lightspeed.enabled }} - name: {{ $lightspeed.sidecar.name }} - image: {{ include "rhdh.lightspeed.image" (dict "image" $lightspeed.images.lightspeedCore "context" $) }} + image: {{ include "common.tplvalues.render" (dict "value" $lightspeed.sidecar.image "context" $) }} imagePullPolicy: {{ $lightspeed.sidecar.imagePullPolicy | quote }} {{- if $lightspeed.sidecar.securityContext }} securityContext: From 7d5b2b918f8b37e7dfd4e366b877519acec4833e Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 14:04:54 -0400 Subject: [PATCH 23/30] remove mcp servers addition from sync in favour of upstream containing it Signed-off-by: Jordan Dubrick --- hack/sync-lightspeed-configs.sh | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/hack/sync-lightspeed-configs.sh b/hack/sync-lightspeed-configs.sh index 72b387d6..7eebed50 100755 --- a/hack/sync-lightspeed-configs.sh +++ b/hack/sync-lightspeed-configs.sh @@ -11,7 +11,7 @@ LIGHTSPEED_DIR="${REPO_ROOT}/charts/backstage/files/lightspeed" # Format: upstream_path|destination_path|transform_function TARGETS=( - "lightspeed-core-configs/lightspeed-stack.yaml|${LIGHTSPEED_DIR}/lightspeed-stack.yaml|render_lightspeed_stack_yaml" + "lightspeed-core-configs/lightspeed-stack.yaml|${LIGHTSPEED_DIR}/lightspeed-stack.yaml|copy_fetched_file" "llama-stack-configs/config.yaml|${LIGHTSPEED_DIR}/config.yaml|copy_fetched_file" "lightspeed-core-configs/rhdh-profile.py|${LIGHTSPEED_DIR}/rhdh-profile.py|copy_fetched_file" "env/default-values.env|${LIGHTSPEED_DIR}/secret.yaml|render_secret_yaml_from_env" @@ -23,22 +23,6 @@ copy_fetched_file() { cp "${source_file}" "${destination_file}" } -# add mcp to LCORE config -render_lightspeed_stack_yaml() { - local source_file=$1 - local destination_file=$2 - - cp "${source_file}" "${destination_file}" - cat <<'EOF' >> "${destination_file}" -mcp_servers: - - name: mcp-integration-tools - provider_id: "model-context-protocol" - url: "http://localhost:7007/api/mcp-actions/v1" - authorization_headers: - Authorization: "client" -EOF -} - render_secret_yaml_from_env() { local source_file=$1 local destination_file=$2 From 2ef185a7c3cfc325bad9f374e132bfd474b54914 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 14:09:28 -0400 Subject: [PATCH 24/30] update schemas for lightspeed Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 16 ++- charts/backstage/values.schema.json | 119 ++++++++++++++++++++--- charts/backstage/values.schema.tmpl.json | 54 +--------- 3 files changed, 124 insertions(+), 65 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 50386857..0a8e3946 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,12 +174,26 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"enabled":true,"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"runtimeVolume":{"emptyDir":{},"persistentVolumeClaim":{},"type":"emptyDir"}}` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"configMaps":[{"mountPath":"/app-root/lightspeed-stack.yaml","name":"stack","nameOverride":"","optional":false,"sourceFile":"lightspeed-stack.yaml","subPath":"lightspeed-stack.yaml"},{"mountPath":"/app-root/config.yaml","name":"config","nameOverride":"","optional":false,"sourceFile":"config.yaml","subPath":"config.yaml"},{"mountPath":"/app-root/rhdh-profile.py","name":"rhdh-profile","nameOverride":"","optional":false,"sourceFile":"rhdh-profile.py","subPath":"rhdh-profile.py"}],"enabled":true,"initContainer":{"args":["mkdir -p /tmp/data && echo 'Copying Lightspeed RAG data...' && cp -r /rag/vector_db /rag-content/ && cp -r /rag/embeddings_model /rag-content/ && echo 'Copy complete.'"],"command":["sh","-c"],"env":[],"image":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05","imagePullPolicy":"IfNotPresent","name":"lightspeed-rag-init","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"ragVolume":{"emptyDir":{},"initMountPath":"/rag-content","mountPath":"/rag-content","name":"lightspeed-rag"},"runtimeVolume":{"emptyDir":{},"mountPath":"/tmp","name":"lightspeed-data","persistentVolumeClaim":{},"type":"emptyDir"},"secret":{"create":true,"name":"","optional":false,"sourceFile":"secret.yaml"},"sidecar":{"args":[],"command":[],"containerPort":8080,"env":[],"image":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","imagePullPolicy":"IfNotPresent","name":"lightspeed-core","portName":"http-lightspeed","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}}` | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | +| global.lightspeed.initContainer.image | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | +| global.lightspeed.initContainer.resources | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}` | | global.lightspeed.plugins | Lightspeed plugins and their configuration. Override package references for disconnected environments. | list | `[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}]` | +| global.lightspeed.ragVolume.emptyDir | `emptyDir` configuration for the RAG data volume. | object | `{}` | +| global.lightspeed.ragVolume.initMountPath | Mount path inside the init container for seeding RAG data. | string | `"/rag-content"` | +| global.lightspeed.ragVolume.mountPath | Mount path inside the sidecar container for serving RAG data. | string | `"/rag-content"` | +| global.lightspeed.ragVolume.name | Name of the Kubernetes volume used for Lightspeed RAG data. | string | `"lightspeed-rag"` | | global.lightspeed.runtimeVolume.emptyDir | `emptyDir` configuration for the Lightspeed runtime data volume when `runtimeVolume.type=emptyDir`. | object | `{}` | +| global.lightspeed.runtimeVolume.mountPath | Mount path inside the container for Lightspeed runtime storage. | string | `"/tmp"` | +| global.lightspeed.runtimeVolume.name | Name of the Kubernetes volume used for writable Lightspeed runtime storage. | string | `"lightspeed-data"` | | global.lightspeed.runtimeVolume.persistentVolumeClaim | Existing PVC reference for the Lightspeed runtime data volume when `runtimeVolume.type=persistentVolumeClaim`. | object | `{}` | | global.lightspeed.runtimeVolume.type | Volume source used for writable Lightspeed runtime storage mounted at `/tmp`. Supported values: `emptyDir`, `persistentVolumeClaim`. | string | `"emptyDir"` | +| global.lightspeed.secret.create | Whether to create a Lightspeed Secret from the bundled source file. | bool | `true` | +| global.lightspeed.secret.name | Name of an existing Secret to use instead. Required when `create` is false. | string | `""` | +| global.lightspeed.secret.optional | Whether the Secret reference is optional in the pod spec. | bool | `false` | +| global.lightspeed.secret.sourceFile | Bundled file used to populate the Secret's `stringData` keys. | string | `"secret.yaml"` | +| global.lightspeed.sidecar.image | Full image reference for the Lightspeed Core sidecar. Override for disconnected environments. | string | `"quay.io/lightspeed-core/lightspeed-stack:0.5.0"` | +| global.lightspeed.sidecar.resources | Resource requests/limits for the Lightspeed Core sidecar. | object | `{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}}` | | nameOverride | | string | `"developer-hub"` | | orchestrator.enabled | | bool | `false` | | orchestrator.plugins | Orchestrator plugins and their configuration | list | `[{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-backend:{{ \"{{inherit}}\" }}"},{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator-form-widgets:{{ \"{{inherit}}\" }}"},{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator:{{ \"{{inherit}}\" }}"},{"disabled":false,"package":"oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-scaffolder-backend-module-orchestrator:{{ \"{{inherit}}\" }}"}]` | diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 623fdd2e..a00fae27 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -120,7 +120,69 @@ "lightspeed": { "additionalProperties": true, "default": { + "configMaps": [ + { + "mountPath": "/app-root/lightspeed-stack.yaml", + "name": "stack", + "nameOverride": "", + "optional": false, + "sourceFile": "lightspeed-stack.yaml", + "subPath": "lightspeed-stack.yaml" + }, + { + "mountPath": "/app-root/config.yaml", + "name": "config", + "nameOverride": "", + "optional": false, + "sourceFile": "config.yaml", + "subPath": "config.yaml" + }, + { + "mountPath": "/app-root/rhdh-profile.py", + "name": "rhdh-profile", + "nameOverride": "", + "optional": false, + "sourceFile": "rhdh-profile.py", + "subPath": "rhdh-profile.py" + } + ], "enabled": true, + "initContainer": { + "args": [ + "mkdir -p /tmp/data && echo 'Copying Lightspeed RAG data...' && cp -r /rag/vector_db /rag-content/ && cp -r /rag/embeddings_model /rag-content/ && echo 'Copy complete.'" + ], + "command": [ + "sh", + "-c" + ], + "env": [], + "image": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05", + "imagePullPolicy": "IfNotPresent", + "name": "lightspeed-rag-init", + "resources": { + "limits": { + "cpu": "100m", + "memory": "500Mi" + }, + "requests": { + "cpu": "50m", + "memory": "150Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsNonRoot": true, + "seccompProfile": { + "type": "RuntimeDefault" + } + } + }, "plugins": [ { "disabled": false, @@ -177,12 +239,57 @@ "package": "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend" } ], + "ragVolume": { + "emptyDir": {}, + "initMountPath": "/rag-content", + "mountPath": "/rag-content", + "name": "lightspeed-rag" + }, "runtimeVolume": { "emptyDir": {}, - "name": "lightspeed-data", "mountPath": "/tmp", + "name": "lightspeed-data", "persistentVolumeClaim": {}, "type": "emptyDir" + }, + "secret": { + "create": true, + "name": "", + "optional": false, + "sourceFile": "secret.yaml" + }, + "sidecar": { + "args": [], + "command": [], + "containerPort": 8080, + "env": [], + "image": "quay.io/lightspeed-core/lightspeed-stack:0.5.0", + "imagePullPolicy": "IfNotPresent", + "name": "lightspeed-core", + "portName": "http-lightspeed", + "resources": { + "limits": { + "cpu": "1000m", + "memory": "2Gi" + }, + "requests": { + "cpu": "100m", + "memory": "512Mi" + } + }, + "securityContext": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsNonRoot": true, + "seccompProfile": { + "type": "RuntimeDefault" + } + } } }, "properties": { @@ -279,16 +386,6 @@ "runtimeVolume": { "additionalProperties": false, "properties": { - "name": { - "default": "lightspeed-data", - "title": "Name of the Kubernetes volume used for writable Lightspeed runtime storage.", - "type": "string" - }, - "mountPath": { - "default": "/tmp", - "title": "Mount path inside the container for Lightspeed runtime storage.", - "type": "string" - }, "emptyDir": { "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", "properties": { diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index 8946c029..63369aa9 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -140,7 +140,7 @@ "object" ], "default": {}, - "additionalProperties": false, + "additionalProperties": true, "properties": { "enabled": { "title": "Enable or disable the built-in Lightspeed feature.", @@ -177,58 +177,6 @@ ] } }, - "images": { - "title": "Images used by the Lightspeed pod wiring.", - "type": "object", - "additionalProperties": false, - "properties": { - "ragInit": { - "title": "Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments.", - "type": "string", - "default": "quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05" - }, - "lightspeedCore": { - "title": "Full image reference for the Lightspeed Core sidecar. Override for disconnected environments.", - "type": "string", - "default": "quay.io/lightspeed-core/lightspeed-stack:0.5.0" - } - } - }, - "resources": { - "title": "Resource requests/limits for Lightspeed containers.", - "type": "object", - "additionalProperties": false, - "properties": { - "ragInit": { - "title": "Resource requests/limits for the Lightspeed RAG bootstrap init container.", - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "default": { - "requests": { - "cpu": "50m", - "memory": "150Mi" - }, - "limits": { - "cpu": "100m", - "memory": "500Mi" - } - } - }, - "lightspeedCore": { - "title": "Resource requests/limits for the Lightspeed Core sidecar.", - "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.4/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "default": { - "requests": { - "cpu": "100m", - "memory": "512Mi" - }, - "limits": { - "cpu": "1000m", - "memory": "2Gi" - } - } - } - } - }, "runtimeVolume": { "title": "Runtime data volume configuration for the Lightspeed Core sidecar.", "type": "object", From ebb6997e27d0e165cc218d98d3d0e13f9173d030 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 14:50:16 -0400 Subject: [PATCH 25/30] fix volume schema issues for lightspeed Signed-off-by: Jordan Dubrick --- charts/backstage/values.schema.json | 10 ++++++++++ charts/backstage/values.schema.tmpl.json | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index a00fae27..42a5b21f 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -386,6 +386,16 @@ "runtimeVolume": { "additionalProperties": false, "properties": { + "name": { + "default": "lightspeed-data", + "title": "Name of the Kubernetes volume used for writable Lightspeed runtime storage.", + "type": "string" + }, + "mountPath": { + "default": "/tmp", + "title": "Mount path inside the container for Lightspeed runtime storage.", + "type": "string" + }, "emptyDir": { "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", "properties": { diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index 63369aa9..a287b19d 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -182,6 +182,16 @@ "type": "object", "additionalProperties": false, "properties": { + "name": { + "title": "Name of the Kubernetes volume used for writable Lightspeed runtime storage.", + "type": "string", + "default": "lightspeed-data" + }, + "mountPath": { + "title": "Mount path inside the container for Lightspeed runtime storage.", + "type": "string", + "default": "/tmp" + }, "type": { "title": "Volume source used for writable Lightspeed runtime storage mounted at `/tmp`.", "type": "string", From bd648ee7d3892db629dd4b3022730fcfe66f6cca Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Mon, 20 Apr 2026 15:11:00 -0400 Subject: [PATCH 26/30] regen schema Signed-off-by: Jordan Dubrick --- charts/backstage/values.schema.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 42a5b21f..e5c622a3 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -386,16 +386,6 @@ "runtimeVolume": { "additionalProperties": false, "properties": { - "name": { - "default": "lightspeed-data", - "title": "Name of the Kubernetes volume used for writable Lightspeed runtime storage.", - "type": "string" - }, - "mountPath": { - "default": "/tmp", - "title": "Mount path inside the container for Lightspeed runtime storage.", - "type": "string" - }, "emptyDir": { "description": "Represents an empty directory for a pod. Empty directory volumes support ownership management and SELinux relabeling.", "properties": { @@ -416,6 +406,16 @@ }, "type": "object" }, + "mountPath": { + "default": "/tmp", + "title": "Mount path inside the container for Lightspeed runtime storage.", + "type": "string" + }, + "name": { + "default": "lightspeed-data", + "title": "Name of the Kubernetes volume used for writable Lightspeed runtime storage.", + "type": "string" + }, "persistentVolumeClaim": { "additionalProperties": false, "default": {}, From 2cbebf7027c2bd9b9a7634bb819002ae8eeee14e Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Tue, 21 Apr 2026 09:36:13 -0400 Subject: [PATCH 27/30] move lightspeed templates to dedicated /lightspeed dir Signed-off-by: Jordan Dubrick --- .../templates/{ => lightspeed}/lightspeed-configmaps.yaml | 0 .../backstage/templates/{ => lightspeed}/lightspeed-secret.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename charts/backstage/templates/{ => lightspeed}/lightspeed-configmaps.yaml (100%) rename charts/backstage/templates/{ => lightspeed}/lightspeed-secret.yaml (100%) diff --git a/charts/backstage/templates/lightspeed-configmaps.yaml b/charts/backstage/templates/lightspeed/lightspeed-configmaps.yaml similarity index 100% rename from charts/backstage/templates/lightspeed-configmaps.yaml rename to charts/backstage/templates/lightspeed/lightspeed-configmaps.yaml diff --git a/charts/backstage/templates/lightspeed-secret.yaml b/charts/backstage/templates/lightspeed/lightspeed-secret.yaml similarity index 100% rename from charts/backstage/templates/lightspeed-secret.yaml rename to charts/backstage/templates/lightspeed/lightspeed-secret.yaml From 885659a36261aa2d2a4532b2eb70e8d9a6a12b7b Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Tue, 21 Apr 2026 10:03:03 -0400 Subject: [PATCH 28/30] use @default for global.lightspeed generated description Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 2 +- charts/backstage/values.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 0a8e3946..dc42c22b 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -174,7 +174,7 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.includes[0] | List of dynamic plugins included inside the `rhdh` container image, some of which are disabled by default. This file ONLY works with the `rhdh` container image. | string | `"dynamic-plugins.default.yaml"` | | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | -| global.lightspeed | Built-in Lightspeed feature configuration. | object | `{"configMaps":[{"mountPath":"/app-root/lightspeed-stack.yaml","name":"stack","nameOverride":"","optional":false,"sourceFile":"lightspeed-stack.yaml","subPath":"lightspeed-stack.yaml"},{"mountPath":"/app-root/config.yaml","name":"config","nameOverride":"","optional":false,"sourceFile":"config.yaml","subPath":"config.yaml"},{"mountPath":"/app-root/rhdh-profile.py","name":"rhdh-profile","nameOverride":"","optional":false,"sourceFile":"rhdh-profile.py","subPath":"rhdh-profile.py"}],"enabled":true,"initContainer":{"args":["mkdir -p /tmp/data && echo 'Copying Lightspeed RAG data...' && cp -r /rag/vector_db /rag-content/ && cp -r /rag/embeddings_model /rag-content/ && echo 'Copy complete.'"],"command":["sh","-c"],"env":[],"image":"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05","imagePullPolicy":"IfNotPresent","name":"lightspeed-rag-init","resources":{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}},"plugins":[{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed","pluginConfig":{"dynamicPlugins":{"frontend":{"red-hat-developer-hub.backstage-plugin-lightspeed":{"dynamicRoutes":[{"importName":"LightspeedPage","path":"/lightspeed"}],"mountPoints":[{"importName":"LightspeedFAB","mountPoint":"application/listener"},{"importName":"LightspeedDrawerProvider","mountPoint":"application/provider"},{"config":{"id":"lightspeed"},"importName":"LightspeedDrawerStateExposer","mountPoint":"application/internal/drawer-state"},{"config":{"id":"lightspeed","priority":100},"importName":"LightspeedChatContainer","mountPoint":"application/internal/drawer-content"}],"translationResources":[{"importName":"lightspeedTranslations","module":"Alpha","ref":"lightspeedTranslationRef"}]}}}}},{"disabled":false,"package":"oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-lightspeed-backend:bs_1.45.3__1.4.0!red-hat-developer-hub-backstage-plugin-lightspeed-backend"}],"ragVolume":{"emptyDir":{},"initMountPath":"/rag-content","mountPath":"/rag-content","name":"lightspeed-rag"},"runtimeVolume":{"emptyDir":{},"mountPath":"/tmp","name":"lightspeed-data","persistentVolumeClaim":{},"type":"emptyDir"},"secret":{"create":true,"name":"","optional":false,"sourceFile":"secret.yaml"},"sidecar":{"args":[],"command":[],"containerPort":8080,"env":[],"image":"quay.io/lightspeed-core/lightspeed-stack:0.5.0","imagePullPolicy":"IfNotPresent","name":"lightspeed-core","portName":"http-lightspeed","resources":{"limits":{"cpu":"1000m","memory":"2Gi"},"requests":{"cpu":"100m","memory":"512Mi"}},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}}}` | +| global.lightspeed | Built-in Lightspeed feature configuration. | object | Use Lightspeed compatible settings / configurations. | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | | global.lightspeed.initContainer.image | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | | global.lightspeed.initContainer.resources | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}` | diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 2a9ab00e..f0e3cde5 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -36,6 +36,7 @@ global: repository: rhdh/plugin-catalog-index tag: "1.10" # -- Built-in Lightspeed feature configuration. + # @default -- Use Lightspeed compatible settings / configurations. lightspeed: # -- Enable or disable the built-in Lightspeed feature. enabled: true From c2745bdc4bf75bcca71644e78dae1e88950e9898 Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Tue, 21 Apr 2026 12:30:36 -0400 Subject: [PATCH 29/30] allow for customized configs Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 9 +++++++++ charts/backstage/templates/_helpers.tpl | 6 +++++- .../lightspeed/lightspeed-configmaps.yaml | 6 +++++- charts/backstage/values.schema.json | 5 ++++- charts/backstage/values.yaml | 15 +++++++++++++++ 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index dc42c22b..c3956482 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -175,6 +175,15 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | | global.lightspeed | Built-in Lightspeed feature configuration. | object | Use Lightspeed compatible settings / configurations. | +| global.lightspeed.configMaps[0].create | Whether to create this ConfigMap from the bundled source file. Set to false and provide `nameOverride` to use a pre-existing ConfigMap. | bool | `false` | +| global.lightspeed.configMaps[0].nameOverride | Name of an existing ConfigMap to use instead. Required when `create` is false. | string | `"test-stack"` | +| global.lightspeed.configMaps[0].sourceFile | Bundled file used to populate the ConfigMap data when `create` is true. | string | `"lightspeed-stack.yaml"` | +| global.lightspeed.configMaps[1].create | Whether to create this ConfigMap from the bundled source file. Set to false and provide `nameOverride` to use a pre-existing ConfigMap. | bool | `true` | +| global.lightspeed.configMaps[1].nameOverride | Name of an existing ConfigMap to use instead. Required when `create` is false. | string | `""` | +| global.lightspeed.configMaps[1].sourceFile | Bundled file used to populate the ConfigMap data when `create` is true. | string | `"config.yaml"` | +| global.lightspeed.configMaps[2].create | Whether to create this ConfigMap from the bundled source file. Set to false and provide `nameOverride` to use a pre-existing ConfigMap. | bool | `true` | +| global.lightspeed.configMaps[2].nameOverride | Name of an existing ConfigMap to use instead. Required when `create` is false. | string | `""` | +| global.lightspeed.configMaps[2].sourceFile | Bundled file used to populate the ConfigMap data when `create` is true. | string | `"rhdh-profile.py"` | | global.lightspeed.enabled | Enable or disable the built-in Lightspeed feature. | bool | `true` | | global.lightspeed.initContainer.image | Full image reference for the Lightspeed RAG bootstrap init container. Override for disconnected environments. | string | `"quay.io/redhat-ai-dev/rag-content:release-1.9-lls-0.5.0-642c567fe10a62b5ff711654306b72912f341e05"` | | global.lightspeed.initContainer.resources | Resource requests/limits for the Lightspeed RAG bootstrap init container. | object | `{"limits":{"cpu":"100m","memory":"500Mi"},"requests":{"cpu":"50m","memory":"150Mi"}}` | diff --git a/charts/backstage/templates/_helpers.tpl b/charts/backstage/templates/_helpers.tpl index 46acd488..43f73eb3 100644 --- a/charts/backstage/templates/_helpers.tpl +++ b/charts/backstage/templates/_helpers.tpl @@ -212,6 +212,7 @@ into the chart archive so changes are captured by chart version bumps. {{- range $lightspeed.configMaps -}} {{- $configMaps = append $configMaps (dict "name" .name + "create" (not (and (hasKey . "create") (not .create))) "nameOverride" .nameOverride "mountPath" .mountPath "subPath" .subPath @@ -265,10 +266,13 @@ Return the Lightspeed ConfigMap name. {{- define "rhdh.lightspeed.configMapName" -}} {{- $root := .root -}} {{- $configMap := .configMap -}} +{{- $create := not (and (hasKey $configMap "create") (not $configMap.create)) -}} {{- if $configMap.nameOverride -}} {{- $configMap.nameOverride -}} - {{- else -}} + {{- else if $create -}} {{- printf "%s-lightspeed-%s" $root.Release.Name $configMap.name | trunc 63 | trimSuffix "-" -}} + {{- else -}} + {{- fail (printf "global.lightspeed.configMaps[%s].nameOverride must be set when create=false" $configMap.name) -}} {{- end -}} {{- end -}} diff --git a/charts/backstage/templates/lightspeed/lightspeed-configmaps.yaml b/charts/backstage/templates/lightspeed/lightspeed-configmaps.yaml index 06252b71..ad2957b8 100644 --- a/charts/backstage/templates/lightspeed/lightspeed-configmaps.yaml +++ b/charts/backstage/templates/lightspeed/lightspeed-configmaps.yaml @@ -1,9 +1,12 @@ {{- $lightspeed := include "rhdh.lightspeed" . | fromYaml -}} {{- if and $lightspeed.enabled $lightspeed.configMaps }} +{{- $created := 0 -}} {{- range $index, $configMap := $lightspeed.configMaps }} -{{- if gt $index 0 }} +{{- if not (and (hasKey $configMap "create") (not $configMap.create)) }} +{{- if gt $created 0 }} --- {{- end }} +{{- $created = add1 $created }} apiVersion: v1 kind: ConfigMap metadata: @@ -14,3 +17,4 @@ data: {{ include "rhdh.lightspeed.fileContent" (dict "context" $ "file" $configMap.sourceFile "optional" $configMap.optional "ref" (printf "global.lightspeed.configMaps[%s].sourceFile" $configMap.name)) | nindent 4 }} {{- end }} {{- end }} +{{- end }} diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index e5c622a3..011df42c 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -122,14 +122,16 @@ "default": { "configMaps": [ { + "create": false, "mountPath": "/app-root/lightspeed-stack.yaml", "name": "stack", - "nameOverride": "", + "nameOverride": "test-stack", "optional": false, "sourceFile": "lightspeed-stack.yaml", "subPath": "lightspeed-stack.yaml" }, { + "create": true, "mountPath": "/app-root/config.yaml", "name": "config", "nameOverride": "", @@ -138,6 +140,7 @@ "subPath": "config.yaml" }, { + "create": true, "mountPath": "/app-root/rhdh-profile.py", "name": "rhdh-profile", "nameOverride": "", diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index f0e3cde5..bf261876 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -94,21 +94,36 @@ global: emptyDir: {} configMaps: - name: stack + # -- Whether to create this ConfigMap from the bundled source file. + # Set to false and provide `nameOverride` to use a pre-existing ConfigMap. + create: true + # -- Name of an existing ConfigMap to use instead. Required when `create` is false. nameOverride: "" mountPath: /app-root/lightspeed-stack.yaml subPath: lightspeed-stack.yaml + # -- Bundled file used to populate the ConfigMap data when `create` is true. sourceFile: lightspeed-stack.yaml optional: false - name: config + # -- Whether to create this ConfigMap from the bundled source file. + # Set to false and provide `nameOverride` to use a pre-existing ConfigMap. + create: true + # -- Name of an existing ConfigMap to use instead. Required when `create` is false. nameOverride: "" mountPath: /app-root/config.yaml subPath: config.yaml + # -- Bundled file used to populate the ConfigMap data when `create` is true. sourceFile: config.yaml optional: false - name: rhdh-profile + # -- Whether to create this ConfigMap from the bundled source file. + # Set to false and provide `nameOverride` to use a pre-existing ConfigMap. + create: true + # -- Name of an existing ConfigMap to use instead. Required when `create` is false. nameOverride: "" mountPath: /app-root/rhdh-profile.py subPath: rhdh-profile.py + # -- Bundled file used to populate the ConfigMap data when `create` is true. sourceFile: rhdh-profile.py optional: false secret: From 529b7030975cdb6c8122646f6b3961afa36c974a Mon Sep 17 00:00:00 2001 From: Jordan Dubrick Date: Tue, 21 Apr 2026 12:33:08 -0400 Subject: [PATCH 30/30] run commit hook Signed-off-by: Jordan Dubrick --- charts/backstage/README.md | 4 ++-- charts/backstage/values.schema.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/backstage/README.md b/charts/backstage/README.md index c3956482..6b859ea9 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -175,8 +175,8 @@ Kubernetes: `>= 1.27.0-0` | global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description). | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`. | string | `""` | | global.lightspeed | Built-in Lightspeed feature configuration. | object | Use Lightspeed compatible settings / configurations. | -| global.lightspeed.configMaps[0].create | Whether to create this ConfigMap from the bundled source file. Set to false and provide `nameOverride` to use a pre-existing ConfigMap. | bool | `false` | -| global.lightspeed.configMaps[0].nameOverride | Name of an existing ConfigMap to use instead. Required when `create` is false. | string | `"test-stack"` | +| global.lightspeed.configMaps[0].create | Whether to create this ConfigMap from the bundled source file. Set to false and provide `nameOverride` to use a pre-existing ConfigMap. | bool | `true` | +| global.lightspeed.configMaps[0].nameOverride | Name of an existing ConfigMap to use instead. Required when `create` is false. | string | `""` | | global.lightspeed.configMaps[0].sourceFile | Bundled file used to populate the ConfigMap data when `create` is true. | string | `"lightspeed-stack.yaml"` | | global.lightspeed.configMaps[1].create | Whether to create this ConfigMap from the bundled source file. Set to false and provide `nameOverride` to use a pre-existing ConfigMap. | bool | `true` | | global.lightspeed.configMaps[1].nameOverride | Name of an existing ConfigMap to use instead. Required when `create` is false. | string | `""` | diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index 011df42c..0abf2b01 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -122,10 +122,10 @@ "default": { "configMaps": [ { - "create": false, + "create": true, "mountPath": "/app-root/lightspeed-stack.yaml", "name": "stack", - "nameOverride": "test-stack", + "nameOverride": "", "optional": false, "sourceFile": "lightspeed-stack.yaml", "subPath": "lightspeed-stack.yaml"